Datahorses

How to read a DMARC aggregate report (rua) and what to do with it

By · · 5 min read

A DMARC aggregate report is a daily summary that large mailbox providers send to the address in the rua tag of your DMARC record. It lists every IP address that sent mail using your domain in the From line, how many messages each one sent, and whether SPF and DKIM passed and aligned with your domain. It does not contain message content, subjects or recipients' addresses.

Reading these reports is how you find out who is really sending as you: your own mail servers, the CRM, the invoicing tool, the newsletter platform, and anyone else who simply puts your domain in the From line. That list is what you need before you move your policy from p=none to enforcement.

Since May 2026 the format is defined in RFC 9990, which together with RFC 9989 (the DMARC mechanism itself) replaced the older RFC 7489. If you need a refresher on the 3 records, start with SPF, DKIM and DMARC explained.

How reports reach you

You ask for reports with the rua tag in your DMARC record:

_dmarc.example.com.  TXT  "v=DMARC1; p=none; rua=mailto:dmarc-reports@example.com"

Each participating provider then emails you an XML file, usually compressed. RFC 9990 says the XML SHOULD be GZIP compressed, with the extension .xml.gz, and the file name follows a fixed pattern:

mail.receiver.example!example.com!1013662812!1013749130.xml.gz

That is the reporting organization, your domain, and the start and end of the period as Unix timestamps. The reporting period typically covers a single UTC day.

If reports should go to a mailbox on a different domain (for example a reporting service at reports.example.net), that domain has to confirm it accepts them. Receivers look up a TXT record such as example.com._report._dmarc.reports.example.net containing v=DMARC1, and if it is missing, they ignore the rua address. A missing confirmation record is a common reason why reports never arrive.

The structure of one report

Every report has the same 3 parts. Here is a shortened example based on the sample in RFC 9990:

<feedback xmlns="urn:ietf:params:xml:ns:dmarc-2.0">
  <report_metadata>
    <org_name>Sample Reporter</org_name>
    <date_range><begin>302832000</begin><end>302918399</end></date_range>
  </report_metadata>
  <policy_published>
    <domain>example.com</domain>
    <p>quarantine</p>
    <testing>n</testing>
  </policy_published>
  <record>
    <row>
      <source_ip>192.0.2.123</source_ip>
      <count>123</count>
      <policy_evaluated>
        <disposition>pass</disposition>
        <dkim>pass</dkim>
        <spf>fail</spf>
      </policy_evaluated>
    </row>
    <identifiers>
      <envelope_from>example.com</envelope_from>
      <header_from>example.com</header_from>
    </identifiers>
    <auth_results>
      <dkim><domain>example.com</domain><result>pass</result><selector>abc123</selector></dkim>
      <spf><domain>example.com</domain><result>fail</result></spf>
    </auth_results>
  </record>
</feedback>
  • report_metadata: who sent the report and which period it covers.
  • policy_published: the DMARC record the receiver saw. Compare it with what you think you published.
  • record: one block per combination of sending IP and results. A busy domain gets many of these.

Reading a record, field by field

source_ip and count. The server that connected to the receiver and how many messages it delivered in that period. This is where you identify senders: a reverse DNS lookup (dig -x 192.0.2.123 +short) or the IP owner often tells you whether it belongs to your mail provider, your CRM or someone unknown.

policy_evaluated. The DMARC verdict. Here dkim and spf are not the raw results but the alignment results: did the check pass for a domain matching your From domain. DMARC passes if at least one of them is pass. disposition shows what the receiver did: none, pass, quarantine or reject. If it differs from your policy, a reason element explains why, for example a forwarding or mailing list override.

identifiers. header_from is the domain your recipients saw. envelope_from is the domain the SPF check used, which is often a subdomain of your sending service rather than yours.

auth_results. The raw SPF and DKIM results with the domains they were checked for. RFC 9990 now requires the DKIM selector, which helps you tell which service signed the message.

In the example above, DKIM passed and aligned, SPF failed, and the message passed DMARC anyway. That is a typical picture for a service that signs with your domain but sends from its own envelope domain.

Sorting senders into 3 groups

After a few weeks of reports, every source IP fits into one of these groups:

  1. Known and passing. Your mail provider and properly configured services. Nothing to do.
  2. Known but failing. A legitimate tool (help desk, invoicing, newsletter) that sends without aligned DKIM, or is missing from SPF. Enable DKIM with your domain in that tool, or add it to SPF while watching the 10 lookup limit.
  3. Unknown and failing. Servers you cannot attribute to anything you use. Some are forwarders and mailing lists; others are someone putting your domain in the From line. These are exactly the messages a p=quarantine or p=reject policy would stop, the same kind of mail used in fake invoice scams.

Group 2 is the one that matters before enforcement. If you switch to p=quarantine while a legitimate tool is still failing, its mail goes to spam.

Practical tips

  • Use a dedicated mailbox or a report processing tool. Raw XML from several providers every day is hard to read by hand.
  • Watch the testing value. RFC 9989 replaced the old pct tag with a t test mode tag; t=y asks receivers to apply a milder action than your policy.
  • Look at volume, not only failures. A sudden new source with a high count deserves attention even if it passes.
  • Keep reports for a few months so you can compare before and after a change.
  • Remember that mailbox providers increasingly expect DMARC from bulk senders, as covered in Gmail and Yahoo sender requirements.

A short checklist

  • DMARC record with a rua address someone actually reads.
  • External report destinations confirmed with a _report._dmarc record.
  • Every source IP attributed to a service you know.
  • Aligned DKIM enabled for every legitimate sender.
  • Unknown failing sources reviewed, then the policy moved to p=quarantine and later p=reject.

Where Guarding fits

DMARC reports show what receivers saw. We watch the other side from the outside every day: your SPF, DKIM and DMARC records, lookalike domains and the rest of your external exposure. When a record is weakened or a selector disappears, a person reviews it and you get the exact change to make, as described in what happens when we find something. You can see how it looks in the example dashboard.

More articles

Pinned

We now proudly guard InvestTimes.com

Invest Times, an English language financial daily about startups and investing, has chosen Guarding. From today we watch InvestTimes.com from the outside, around the clock.

All articles