Reading a DMARC aggregate report
The XML is dense but the structure is simple: who sent, from where, how much, and what the checks said. Here is how to turn it into a decision.
Aggregate reports are the reason to publish DMARC even if you never intend to enforce it. Each one is a receiver telling you, for a 24-hour window, exactly what it saw claiming to come from your domain: which IP addresses sent it, how much, and how it authenticated. Without them you are guessing about your own mail.
They arrive as gzipped XML attachments, one per reporting receiver per day. They are machine-readable rather than human-friendly, but the structure is genuinely simple once you have seen it once.
The shape of a report
Every report has two parts. The metadata block names the reporting receiver, the date range, and the policy they found in your DNS. Then comes a set of records, one per sending IP address, each with a count and results.
One record from a report
<record>
<row>
<source_ip>203.0.113.10</source_ip>
<count>148</count>
<policy_evaluated>
<disposition>none</disposition>
<dkim>pass</dkim>
<spf>fail</spf>
</policy_evaluated>
</row>
<identifiers><header_from>example.com</header_from></identifiers>
<auth_results>
<dkim><domain>example.com</domain><result>pass</result></dkim>
<spf><domain>mail.vendor.net</domain><result>pass</result></spf>
</auth_results>
</record>The two result sets, and why they differ
This trips up nearly everyone on first reading. There are two places results appear, and they mean different things.
- policy_evaluated holds the DMARC-aligned results. This is what decided the disposition, and it is the one that matters.
- auth_results holds the raw SPF and DKIM outcomes, before alignment was considered, along with the domains that were checked.
In the record above, SPF passed for mail.vendor.net but policy_evaluated reports spf as fail. Nothing is contradictory: SPF authenticated successfully for the vendor's domain, and that domain does not align with example.com in the From header. That gap between the two blocks is the signature of an unaligned sender, and it is the single most useful pattern to be able to spot.
What disposition tells you
The disposition field reports what the receiver actually did: none, quarantine, or reject. While you are at p=none it will read none even for failing mail, which is the point of monitoring. Once you tighten, disposition is how you confirm receivers are honouring the policy you published.
Working through a report
- Sort sources by count, descending. The top handful is your real mail. The long tail is usually noise, forwarders, and background spoofing.
- Identify each significant source. Reverse DNS on the IP address is the fastest route, and the PTR lookup will usually name the provider outright.
- Split the failures into two piles: your own senders that are misconfigured, and mail that is not yours at all.
- Fix the first pile. Missing SPF entries, or a vendor signing with their own domain instead of yours.
- Leave the second pile alone. That is what enforcement is for, and it is the mail you eventually want rejected.
The aligned-pass rate
The number to track over time is the proportion of your total volume that passes DMARC with alignment. Early on it is often surprisingly low, not because anything is broken but because two or three vendors are signing as themselves. As you fix each one it climbs in visible steps.
When that rate is high and stable across several weeks, and every remaining failure is either explained or genuinely not yours, you are ready to tighten. That judgement is the whole content of moving from none to reject.
Do not act on a single day's report. Low-volume senders such as password resets, invoicing, annual renewal notices and the office printer may not appear for weeks. This is the real reason to sit at p=none for a month rather than a few days: you are waiting for the infrequent senders to show themselves.
Why receivers disagree
Two reports covering the same day will rarely tell the same story, and that is expected. Each receiver only reports on mail it received, so a provider your customers do not use will show almost nothing. Reporting windows do not align perfectly either, and a message sent just before midnight may land in the following day's report.
Not every receiver reports at all. The large mailbox providers do, which covers most consumer mail, but plenty of corporate mail servers send nothing. Your reports are therefore a large sample rather than a complete census, and a sender that appears in no report has not necessarily stopped sending.
What the metadata block tells you
The header of each report names the reporting organisation, an email contact, a unique report ID, and the date range covered. It also echoes back the policy that receiver found in your DNS at the time.
That echo is more useful than it looks. It is independent confirmation of what the world actually sees, rather than what you think you published. If you tightened your policy a week ago and reports still show p=none, either the change did not take effect or you edited the wrong record.
Sources you do not recognise
Resist the urge to conclude you are being attacked. Most surprising entries turn out to be mundane: mailing lists relaying your posts, universities and alumni services forwarding to members, a customer's own forwarding rule, or a security gateway rewriting mail on its way through. Genuine spoofing is usually low volume and from scattered addresses with no reverse DNS.
Forwarded mail in particular will show SPF failing and DKIM passing, which is exactly what forwarding does to SPF and not a problem to fix.
Reading them without parsing XML
For a handful of reports a day, drop the file into the DMARC report reader exactly as it arrived, as .zip, .gz or .xml, and read it in plain English. Past a few dozen a day the volume stops being tractable by hand and a dedicated processor earns its keep, but the structure it shows you is the same one above.
More on DMARC
What DMARC actually does
DMARC binds SPF and DKIM to the From address your recipients see, tells receivers what to do on failure, and sends you reports about it.
Every DMARC tag, and which ones matter
A DMARC record has eleven possible tags. Four of them do the work; the rest are tuning you will rarely touch.
Publishing your first DMARC record
Start at p=none with a reporting address. It changes nothing about delivery and gives you the data you need for every decision that follows.