How to read a DMARC report
What a DMARC aggregate report contains, how to read each part of the XML, the four patterns you'll see, and what to do about each one.
By Doug Hall · Updated
- An aggregate report is a daily XML file from each mailbox provider, listing every server that sent email as the domain and how it fared.
- policy_evaluated shows the DMARC-aligned results; auth_results shows the raw SPF and DKIM results. The difference between them is where problems hide.
- Most rows fall into four patterns: aligned pass, unaligned third-party sender, forwarding, and spoofing.
What arrives, and from whom
When a domain's DMARC record includes a rua= address, mailbox providers that support reporting send an aggregate report there, usually once a day. Google, Microsoft and Yahoo all do, along with many smaller providers. Each report covers the email that provider received during the period, typically one UTC day, that claimed to come from the domain.
The report is an XML file, compressed as a .zip or .gz attachment. The format was first described in RFC 7489 and is now defined by RFC 9990, published in May 2026 alongside RFC 9989 for DMARC itself. Reports from before and after the new RFCs look almost the same; newer ones may add a namespace and a few extra elements.
To follow along with one of your own, open the attachment, or upload it to our DMARC report analyser, which lays it out as a table and doesn't keep a copy.
An example report
Here is a shortened report for a made-up domain, example.co.uk, with two records. The addresses are reserved documentation ranges; real reports often have dozens of records.
<feedback>
<report_metadata>
<org_name>mail-provider.example</org_name>
<email>dmarc-reports@mail-provider.example</email>
<report_id>4821736502914837265</report_id>
<date_range>
<begin>1791158400</begin>
<end>1791244799</end>
</date_range>
</report_metadata>
<policy_published>
<domain>example.co.uk</domain>
<adkim>r</adkim>
<aspf>r</aspf>
<p>none</p>
<sp>none</sp>
</policy_published>
<record>
<row>
<source_ip>192.0.2.25</source_ip>
<count>412</count>
<policy_evaluated>
<disposition>none</disposition>
<dkim>pass</dkim>
<spf>pass</spf>
</policy_evaluated>
</row>
<identifiers>
<header_from>example.co.uk</header_from>
</identifiers>
<auth_results>
<dkim>
<domain>example.co.uk</domain>
<selector>selector1</selector>
<result>pass</result>
</dkim>
<spf>
<domain>example.co.uk</domain>
<result>pass</result>
</spf>
</auth_results>
</record>
<record>
<row>
<source_ip>198.51.100.7</source_ip>
<count>1630</count>
<policy_evaluated>
<disposition>none</disposition>
<dkim>fail</dkim>
<spf>fail</spf>
</policy_evaluated>
</row>
<identifiers>
<header_from>example.co.uk</header_from>
</identifiers>
<auth_results>
<dkim>
<domain>newsletter-tool.example</domain>
<selector>nt1</selector>
<result>pass</result>
</dkim>
<spf>
<domain>bounce.newsletter-tool.example</domain>
<result>pass</result>
</spf>
</auth_results>
</record>
</feedback>The file name tells you three things before you open it: who sent the report, which domain it's about, and the start and end of the period as Unix timestamps.
The header: who reported, and the policy they saw
report_metadata says who sent the report and when it covers:
- org_name
- The provider that received the mail and wrote the report.
- Where to contact them about the report itself.
- report_id
- Their unique id for this report. Useful for spotting duplicates.
- date_range
- Start and end of the period, in seconds since 1 January 1970, UTC. 1791158400 is 0:00 UTC on 5 October 2026.
policy_published is the DMARC record the provider found when it looked up the domain. Check it matches what you think you published. If you changed the record during the day, some reports will show the old one.
- domain
- The domain the policy belongs to.
- p
- The policy: none, quarantine or reject.
- sp
- The policy for subdomains, if set.
- adkim, aspf
- Alignment mode for DKIM and SPF: r for relaxed (the default), s for strict.
- np, testing
- Newer reports only: the policy for subdomains that don't exist, and whether the record is in test mode.
Each record, line by line
Each record groups messages that share a sending IP address and the same results. It has three parts.
row. source_ip is the server that sent the messages, and count is how many. policy_evaluated is the DMARC verdict:
- disposition
- What the provider did: none (delivered as normal), quarantine (spam folder), reject (refused). RFC 9990 also allows pass.
- dkim
- pass only if DKIM passed for a domain aligned with the From address. Otherwise fail.
- spf
- pass only if SPF passed for a domain aligned with the From address. Otherwise fail.
- reason
- Optional. Why the provider applied a different action from the policy, such as mailing_list, trusted_forwarder or local_policy.
identifiers. header_from is the domain in the From address people see. Some reports also give envelope_from, the bounce domain.
auth_results. The raw SPF and DKIM results, before alignment: which domain passed or failed. DKIM shows the signing domain (d=) and the selector; SPF shows the domain checked, usually the bounce domain.
The key is to read policy_evaluated and auth_results together. DMARC passes if either dkim or spf in policy_evaluated is pass. When auth_results shows a pass but policy_evaluated shows fail, the check succeeded for someone else's domain. That's an alignment problem, and it's the commonest one.
The four patterns you'll see
| Pattern | What the record shows | What to do |
|---|---|---|
| Aligned pass | policy_evaluated dkim or spf is pass | Nothing. This is your own mail working. |
| Third-party sender, not aligned | auth_results pass for the service's own domain; policy_evaluated fail | Set up DKIM for your domain in that service. |
| Forwarding | SPF fails (a new server); DKIM often still passes and aligns | Usually nothing, if DKIM passes. Make sure every source signs with DKIM. |
| Spoofing | Unknown IP; nothing passes for your domain | Nothing to fix at the sender. Move towards p=reject. |
Aligned pass. The first record in the example: 412 messages from the domain's own mail service, signed with its own DKIM key and sent from a server in its SPF record. Both aligned results are pass.
Third-party sender, not aligned. The second record: 1,630 messages from a newsletter tool. In auth_results both SPF and DKIM pass, but for the tool's domains, not example.co.uk, so both aligned results are fail. At p=reject the client's newsletter would be refused. The fix is to turn on the tool's domain authentication so it signs as example.co.uk. Don't just add the tool to SPF: its bounce domain is still its own, so SPF still won't align, and you use up lookups. Look the IP up in the report analyser or by reverse DNS if you don't recognise the service.
Forwarding. Someone has a rule forwarding mail from their old address to a new one. The forwarding server isn't in your SPF record, so SPF fails, but DKIM survives forwarding when the message isn't changed. Small volumes of this are normal. If a record shows DKIM failing too, a mailing list or security gateway may have rewritten the message; the reason element sometimes says so.
Spoofing. An IP address you don't recognise, often abroad, with nothing passing for your domain. Nobody legitimate is behind it, so there's nothing to fix at their end. This is what p=quarantine and p=reject stop, which is why the reports matter: they prove every real sender passes before you tighten the policy. The DMARC guide covers that move step by step.
Why providers' reports differ
The same day's mail can look different in each provider's report:
- They only see the mail they received. Each provider reports on mail that reached its own servers. A sender that only emails one provider's users appears in only that provider's report.
- Optional fields vary. Some include
envelope_fromor a DKIM selector; some leave them out. - Periods don't line up exactly, so daily totals across providers won't match your sent counts.
- Local policy. A provider may deliver mail that failed DMARC, or junk mail that passed, for its own reasons.
dispositionandreasonrecord that.
That's why reading reports by hand stops working beyond one or two domains: the real job is combining a month of files from a dozen providers into one view of who sends as each domain, and how much of it passes.
Not receiving reports?
- Check the record has a rua tag, spelt correctly, with
mailto:in front of the address. The DMARC checker shows it. If it's missing, see how to fix missing DMARC reporting. - Give it a day or two. Reports cover a whole day and arrive after it ends.
- Check the mailbox accepts attachments and isn't filtering them as spam. Some reports are large.
- If the address is on another domain, that domain must publish an authorisation record, or providers won't send to it. For reports about example.co.uk sent to an address at reports.example.net, it looks like this:
v=DMARC1
Reporting services publish this for you. Domain Health Hub's report address works for every domain without any extra record on your side, and the reports are read for you, so you see the senders and pass rates rather than the XML. For agencies, those pass rates go straight into each client's monthly report card.
Doing this for clients? Domain Health Hub checks every client domain each day and puts the results in a monthly report card with your logo. Start a free trial; no card needed.
Questions
Do DMARC reports contain the content of emails?
No. Aggregate reports hold counts, sending IP addresses, domains and pass or fail results. No subjects, bodies or recipient addresses.
How often do reports arrive?
Usually once a day from each provider that received mail from the domain, covering one UTC day. A quiet domain may get none on some days.
Why does a report show mail we never sent?
Because someone else sent it with your domain in the From address. That's exactly what DMARC reports are for. At p=reject, those messages are refused.
What about forensic (ruf) reports?
They're copies or extracts of individual failing messages, and few providers send them. They can contain personal data, so we don't accept them, and you rarely need them.
Watch every client's domains, every day.
Reports read for you, and a monthly report card your clients will understand.