Skip to content
← BlogDeliverability6 min read

Reading DMARC XML reports by hand vs. having Norbelys do it

What manually parsing DMARC aggregate report XML files actually involves at real send volume, and why most teams stop doing it themselves within weeks.

By Gabriel Lara, Developer Relations, Norbelys

Founder-reviewed ·How we research and correct articles

Every domain with a DMARC record and an rua= tag gets aggregate reports — gzipped XML files, one from roughly every receiving mail server that processed mail claiming to be from your domain, sent about once a day. How to read one is a solved problem; this post is about what it costs to keep reading them, forever, by hand, once you’re sending at real volume.

What actually lands in that inbox

If you’re sending to Gmail, Outlook, and Yahoo users, that’s a minimum of three separate report files a day, because every provider that received mail from your domain sends its own report independently. Once you’re sending broadly enough to reach the long tail of regional providers, corporate gateways, and security filters, that count climbs fast — Suped’s analysis of DMARC reporting puts a genuinely high-volume domain at 20 to 80 report files a day, and a domain sending to a wide enough mix of providers can clear 150 without anything being misconfigured. Each one is a .xml.gz or .zip attachment that needs to be unzipped before it’s readable at all.

One report, by hand
today's haul: 41 new rua reports in the inbox$ gunzip google.com!yourdomain.com!*.xml.gz$ xmllint --format report.xml | less<record><row><source_ip>203.0.113.44</source_ip><policy_evaluated><dkim>fail</dkim><spf>pass</spf>...is 203.0.113.44 you? a vendor? or someone spoofing you? repeat for 40 more files.

That’s one file. The actual job is doing that forty times a day, every day, indefinitely — because DMARC reporting isn’t a one-time audit, it’s a running feed. A source that was clean last week can start failing tomorrow, whether that’s a marketing tool you forgot was still sending on your behalf, a misconfigured forwarder, or an actual spoofing attempt.

Where the manual version quietly breaks

It’s not really one-time work, and nobody budgets it as ongoing work. Most teams set up an rua= mailbox once, read a handful of reports to confirm SPF and DKIM pass, and consider DMARC “done.” The reports keep arriving daily regardless. Without someone actually opening them on a schedule, a new failing source can run for weeks before anyone notices — which defeats the entire point of aggregate reporting, since its value is in catching new unauthorized senders, not confirming old ones are still fine.

The parser is itself infrastructure someone has to own. A script that unzips, parses the XML, and aggregates by source IP is the sane way to do this at any real volume — but that script now needs a maintainer, error handling for malformed reports, and someone who notices when it silently stops running. You’ve replaced “read email XML by hand” with “own a small internal tool,” which is a different job, not a smaller one.

Multi-domain and agency setups multiply the noise linearly. Run DMARC across five client domains or ten subdomains and the report count doesn’t average out — it stacks. Two hundred reports a day across a small agency’s book of domains isn’t unusual, and reading each domain’s feed separately in a generic mail client makes it nearly impossible to spot the same unauthorized source hitting three different clients at once.

Acting on what you find requires judgment a raw XML row doesn’t give you. A dkim=fail row doesn’t tell you whether that source IP is a spoofer or a legitimate vendor with a broken signature — you have to cross-reference it against what you actually authorized. That correlation step is the part that actually protects the domain, and it’s the part a plain XML reader gives you zero help with.

Reading rua XML by handNorbelys DMARC monitoring
SetupConfigure rua=, build or find a parserPoint rua= at the provided address, done
Daily reading effortUnzip and parse every file yourselfZero — already aggregated
New unauthorized sourceFound only if someone's looking that dayFlagged automatically
Multi-domain / agency viewSeparate feed per domainOne dashboard across every domain
Path to enforcementYou infer readiness from raw pass/fail countsGuided p=none → quarantine → reject

What a minimal in-house pipeline actually requires

Building a parser instead of reading files by hand doesn’t remove the ownership problem, it just relocates it. A workable in-house pipeline needs an inbox rule that reliably captures every rua= report without a spam filter silently swallowing them, a job that survives the malformed or truncated XML every provider occasionally sends, somewhere to store results so trends are visible over time, and logic that flags genuinely new source IPs rather than dumping “everything that sent mail” with no prioritization. None of that is exotic engineering — together it’s a real internal tool with a code owner, not a script you write once and forget. (This is about aggregate rua data specifically; forensic ruf reports are a rarer, separate stream most providers have scaled back sending in 2026.)

Frequently asked questions

Once monitoring is in place, do I still need to keep the rua= mailbox around?

The rua= address itself still needs to exist and keep receiving reports — that's how providers deliver DMARC data, and there's no alternative delivery mechanism. What changes is what happens after a report arrives: instead of a mailbox full of gzipped attachments waiting for someone to open them, the reports feed straight into an aggregated, searchable view.

Can I still see the raw XML if I want it?

The underlying data doesn't disappear — aggregation is a presentation layer on top of the same reports every provider is already sending, not a replacement for the source data. The difference is not having to be the one who unzips and reads it to get the answer you actually need: is anything unauthorized sending mail as this domain right now.

What changes with monitoring built in

Norbelys’s DMARC monitoring takes the same rua= feed every provider is already sending and turns it into what you actually need from it: authorized sources aggregated automatically, new or unauthorized sources flagged instead of buried in row 340 of a report you haven’t opened yet, and one view across every domain you manage — which matters specifically if you’re running DMARC for more than one domain at once. The XML parsing isn’t gone because it stopped mattering; it’s gone because it shouldn’t have been a manual, ongoing chore in the first place.

If you’re currently running DMARC by pointing rua= at a mailbox and occasionally remembering to look, that’s the exact gap worth closing before your next attempt to move enforcement from p=none to something that actually blocks spoofed mail. See DMARC monitoring on your domain or check what’s included on every plan — reading the reports was never supposed to be the job.