How to Read a DMARC Aggregate Report (RUA): A Field Guide
If you’ve published a DMARC record with a rua tag, you’re already receiving aggregate reports from mailbox providers like Google, Microsoft, and Yahoo. The problem is that these reports arrive as gzipped XML attachments that are nearly unreadable without a parser — and most guides just tell you to “use a DMARC dashboard tool” without explaining what the data actually means. This article walks through a real report field by field so you can interpret one yourself, whether you’re using a paid dashboard or just cat and a text editor.
What triggers an aggregate report
Every domain with a _dmarc TXT record that includes a rua=mailto:... tag will receive periodic (usually daily) XML summaries from any receiving mail server that saw mail claiming to be from your domain. This includes your legitimate marketing platform, your transactional email service, your employees’ phones — and anyone spoofing your domain. That’s the entire point: aggregate reports tell you who is sending mail “as you,” so you can distinguish authorized senders from abuse before moving your policy to p=quarantine or p=reject.
Getting the raw file
Reports arrive as an email attachment named something like google.com!yourdomain.com!1717027200!1717113600.xml.gz. Decompress it:
gunzip google.com\!yourdomain.com\!1717027200\!1717113600.xml.gz
The filename itself is informative: reporting organization, your domain, and the Unix timestamp range the report covers.
Anatomy of the XML
A typical record inside the report looks like this:
<record>
<row>
<source_ip>203.0.113.45</source_ip>
<count>42</count>
<policy_evaluated>
<disposition>none</disposition>
<dkim>pass</dkim>
<spf>fail</spf>
</policy_evaluated>
</row>
<identifiers>
<header_from>yourdomain.com</header_from>
</identifiers>
<auth_results>
<dkim>
<domain>yourdomain.com</domain>
<result>pass</result>
<selector>mail</selector>
</dkim>
<spf>
<domain>bounce.marketingtool.com</domain>
<result>fail</result>
</spf>
</auth_results>
</record>
Field-by-field meaning
source_ip— The IP address that connected to the receiving server. Reverse-DNS or WHOIS this if you don’t recognize it; it tells you which sending platform (or attacker) is involved.count— Number of messages from that IP matching this exact result combination during the reporting window.policy_evaluated > disposition— What the receiver actually did:none,quarantine, orreject. This reflects the policy in effect at evaluation time, which can differ from your published policy if the receiver applies apctsampling percentage.policy_evaluated > dkim/spf— Whether DKIM and SPF passed DMARC alignment, not just raw authentication. This is the distinction that trips people up (see below).identifiers > header_from— The visible “From:” domain recipients saw. This is the domain DMARC actually protects.auth_results > spf > domain— The domain used in the SPF check, taken from the SMTPMAIL FROM/envelope sender. If this differs fromheader_from, SPF alignment fails even if SPF itself passed.auth_results > dkim > domainandselector— Thed=domain ands=selector from the DKIM signature. Useful for identifying exactly which sending system signed the mail.
Why “SPF fail” doesn’t always mean a spoofer
The record above shows spf>fail in policy_evaluated but the message still passed DMARC overall — because DKIM passed and DKIM alone satisfies DMARC. This is the normal, expected result for mail forwarded through a mailing list or relay, since forwarding breaks the envelope sender SPF checks but leaves the DKIM signature intact. Don’t panic at every SPF fail; check whether DKIM covered it.
Conversely, watch for records where both DKIM and SPF fail alignment, especially from unfamiliar source_ip addresses, with header_from matching your exact domain. That pattern is the signature of actual spoofing, and it’s the evidence you need before tightening your policy.
A practical workflow
- Collect a week or two of reports before making policy changes — one day’s data isn’t representative of your full sending landscape.
- Group records by
source_ipand count total volume per IP. - For each IP, resolve PTR/WHOIS and match it against known senders: your ESP, CRM, helpdesk, internal relays, etc.
- Flag any high-volume IP with failing DMARC alignment that you can’t identify — that’s either a misconfigured legitimate sender (fix its SPF/DKIM) or abuse.
- Once every legitimate IP passes alignment, move from
p=nonetop=quarantine, monitor again, then top=reject.
Automating the parsing
For anything beyond a handful of reports, parsing XML by hand doesn’t scale — providers send one file per day per receiving organization, and a busy domain accumulates dozens of files daily. A small script using Python’s xml.etree.ElementTree or a dedicated DMARC report parser can aggregate source_ip, count, and alignment results into a single table. The field meanings above apply regardless of which tool renders them — understanding the raw structure means you can always sanity-check what a dashboard is telling you, and debug cases where a tool’s summary seems to disagree with what you’d expect from your own sending infrastructure.