DEV Community

Vadim Ivanov
Vadim Ivanov

Posted on

How to read a DMARC aggregate report without losing your mind

You turned on DMARC, and now a few times a day Google, Microsoft, and a handful of providers you've never heard of email you an XML file. Opened one, saw a wall of <record> tags, closed it again. This is the part of DMARC nobody walks you through, so here is how to actually read those reports and what to do with them.

What an aggregate report actually is

First, calm one fear: these reports contain no message content and no recipients. An aggregate (rua) report is a daily summary from one receiver that says, in effect, "here is the mail I saw claiming to be from your domain, grouped by sending IP, and here is how it authenticated." That's it. Counts and auth results, bucketed by source. They are how you find out who is sending as you, the legitimate senders you forgot about and the ones you never authorized.

They are also not meant to be read one message at a time. Each report is a rollup, and you get one per receiver per day, which is why doing this by hand gets old fast.

The three parts of the XML

Every report (the schema is RFC 7489 Appendix C) has the same shape.

report_metadata tells you who sent the report and the time window: org_name (say, google.com), a report_id, and a date_range. Skim it and move on.

policy_published is your own DMARC record as that receiver read it: domain, p, sp, adkim, aspf, pct. Worth a glance to confirm they're seeing the policy you think you published.

record is the part that matters, and there's one per sending source. Inside each one:

  • row has source_ip, a count of messages, and a policy_evaluated block with the DMARC verdict: disposition (none, quarantine, or reject) and the aligned results for dkim and spf.
  • identifiers has the header_from, the visible From domain the message used.
  • auth_results has the raw checks: an spf block with its domain and result, and a dkim block with the signing domain, selector, and result.

Reading a single record

Here's the mental move. For each record, ignore the pretty stuff and look at two things.

In policy_evaluated, do dkim and spf both say pass? If either passes there, the message aligned and DMARC passed for that source. If both say fail, that source is failing DMARC, and the count tells you how many messages.

Then, when something failed, drop into auth_results to see why. Compare the SPF domain (the Return-Path) and the DKIM domain (the d=) against the header_from. If SPF passed but for a Return-Path on a different domain, or DKIM verified but d= isn't yours, you've found a classic alignment failure: the mail authenticated, just not as you.

The difference between policy_evaluated and auth_results trips everyone up at first. auth_results is "did SPF/DKIM pass at all." policy_evaluated is "did it pass and align," which is the DMARC question. A source can show spf=pass in auth_results and spf=fail in policy_evaluated, and that gap is alignment.

What you're actually hunting for

Two things, and they need opposite responses.

Legitimate sources that aren't aligned. Your ESP, a helpdesk tool, an invoicing SaaS, the marketing platform someone in another department signed up for. They're sending real mail as you, but failing DMARC because nobody set up aligned DKIM for your domain on that platform. These are the ones to fix: go into each service and complete its domain authentication so it signs with d=yourdomain.

Sources you don't recognize. Could be shadow IT, could be a spoofer. Either way you want to know before you move to an enforcing policy, because once you're at p=reject, that source stops delivering. If it turns out to be legitimate, authenticate it; if it's abuse, you now have evidence and you've confirmed reject will stop it.

Don't grind through raw XML

For one domain with a couple of senders you can eyeball the files. Past that it stops scaling, and the tags start blurring. Feed them to something that parses the XML and shows you a table of sources, counts, and pass/fail instead: an open-source parser, a dedicated DMARC service, or a checker like Relaymetry's report analyzer that turns one of these files into a readable summary. The point is to get to "which sources are failing and how many" without reading angle brackets.

Why this is the whole job

The reports are the map for the one journey that matters in DMARC: getting from p=none to p=reject safely. You start at none precisely so these reports can accumulate without any mail being blocked. You read them for a few weeks, you authenticate every legitimate source until it aligns, and only when the failing sources are all either fixed or confirmed-malicious do you tighten the policy. Skip the reports and you're moving to reject blind, which is how legitimate mail ends up in the void. Read them, and enforcement becomes a decision instead of a gamble.

Top comments (0)