Back to blog
Threat Intel
Phishing Forensics

Decoding DMARC Failures: A Forensic Guide to RUA & RUF Reports

DMARC dashboards hide the truth; mastering raw XML is how you find the broken mail flows preventing a p=reject policy.

MailSleuth Research
Email Security Team
June 15, 20268 min read
A desk with XML code printouts under a magnifying glass, which highlights a red 'fail' status, symbolizing DMARC report

You’ve been stuck at DMARC’s `p=quarantine` for six months. Your aggregated dashboard looks clean—99% pass rate, a few specks of red from obvious spoofing attempts. But every time you propose switching to `p=reject`, a legitimate sender screams that their mail is being junked. Your dashboard is lying to you through omission.

The pretty charts aggregate away the nuance. They can’t distinguish a critical partner’s misconfigured mail server from a low-volume spammer. To find the subtle, systemic failures that keep you from locking down your domain, you have to go deeper. You have to read the raw XML reports your domain receives every day.

This is where the real work of DMARC analysis happens. It’s less about big data and more about digital forensics. It’s about dissecting the raw data feeds—the RUA and RUF reports—to build a ground-truth map of who is sending mail on behalf of your domain and whether they’re doing it correctly.

RUA vs. RUF: Choosing the Report for the Job

Your DMARC record requests two types of reports via the `rua` (Reporting URI for Aggregate) and `ruf` (Reporting URI for Forensic) tags. They serve fundamentally different purposes, and knowing which one to reach for is the first step in any real investigation.

RUA: The 30,000-Foot View

Aggregate reports are XML summaries sent by receiving mail servers, typically daily. They don't contain message content. Instead, they provide a statistical overview: for a given sending IP, this many messages were seen, this was the `From` header, these were the SPF and DKIM results, and this was the ultimate DMARC disposition. This is your primary tool for identifying systemic issues. If a new marketing platform you just onboarded is failing DKIM alignment across thousands of sends, it will light up your RUA reports like a Christmas tree.

RUF: The Microscope

Forensic, or failure, reports are different. They are generated almost instantly for individual message failures. Crucially, they contain message headers and often the message body or a snippet of it. This is both their power and their peril. The potential for leaking personally identifiable information (PII) means most major mailbox providers have either stopped sending them or send heavily redacted versions. But when you can get them, they are forensic gold. Imagine a single, critical invoice email from your CFO to a vendor fails DMARC. A RUF report can give you the exact headers, showing the transit path and the precise point of failure, allowing for rapid, targeted remediation. Use `rua` for trends, `ruf` for specific, high-stakes incidents.

Anatomy of a RUA Report

At first glance, RUA XML is a wall of text. But like any structured data, it's telling a story once you know the language. The entire file is wrapped in a `<feedback>` tag, but the real action is inside the child elements.

The Prologue: Report Metadata

At the top of the file, you'll find the `<report_metadata>` section. Check the `<org_name>` (the reporter, e.g., Google Inc.), `<date_range>` (the UTC timestamps for the reporting period), and `<report_id>`. This tells you who the report is from and what period it covers. Also, check `<policy_published>`, which shows the DMARC policy the receiver evaluated against. If you see `p=none` here when you thought you'd set `p=quarantine`, you have a DNS propagation issue or you’re looking at an old, cached policy.

The Core Evidence: `<record>` Elements

The bulk of the report is a series of `<record>` elements. Each record represents a unique combination of sending source and authentication results. Inside each, you’ll find three key areas.

<record>
<row>
<source_ip>209.85.220.69</source_ip>
<count>5</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>s2048</selector>
</dkim>
<spf>
<domain>some-forwarder.com</domain>
<result>fail</result>
</spf>
</auth_results>
</record>

The `<row>` contains the `<source_ip>` of the sending server and the `<count>` of messages received from it. The `<identifiers>` block contains the `<header_from>` domain—the domain being protected by DMARC. Finally, the `<auth_results>` block provides the raw SPF and DKIM results, governed by RFC 7208 and RFC 6376, respectively. This is where you see the *actual* authentication verdicts, not DMARC’s interpretation of them.

Correlating IPs and Auth Results to Find the Guilty Parties

This is the core analytic loop of DMARC debugging. For each `<record>`, you must connect the dots between the IP, the `From` header, and the authentication results. The goal is to determine if a failure is legitimate (a real, unauthenticated sender) or illegitimate (a valid sender with a configuration problem).

The DMARC check, defined in RFC 7489, passes if either SPF or DKIM passes *and* aligns with the `<header_from>` domain. Alignment is the key. For SPF, the envelope `MAIL FROM` domain must match the `header_from`. For DKIM, the domain in the DKIM signature's `d=` tag must match. A `pass` verdict without alignment does nothing for DMARC.

Consider a common scenario: a report shows `<spf><result>fail</result></spf>` but `<dkim><result>pass</result></dkim>`, and the DKIM domain aligns with your `<header_from>` domain. The overall DMARC result for that message is a pass. This is expected behavior for many third-party sending services. They can't pass SPF alignment, so they rely on correctly configured DKIM. Your job is to verify that the `<source_ip>` actually belongs to that service.

The real trouble is a record showing both SPF and DKIM failing. Look at the `<source_ip>`. Is it an IP block belonging to a cloud provider your developers are using for a side project? Is it Mailchimp, but the DKIM `<selector>` is wrong? Is it a completely unknown IP from a hostile network? The IP is your lead. A reverse DNS lookup is your first follow-up action. This context separates shadow IT from a BEC attack.

The Forwarding Black Hole and the ARC Lifeline

Indirect mail flows are the number one reason legitimate mail fails DMARC. Calendar invites get forwarded, mailing list messages get re-sent, and users have personal accounts auto-forwarding to corporate inboxes. Every one of these hops breaks email authentication.

SPF breaks immediately. When a Google server forwards a message to a Microsoft 365 tenant, the receiving server sees the email coming from a Google IP. That IP is not in the original sender's SPF record, so SPF fails. It’s doing exactly what it was designed to do. DKIM is more resilient but can also fail if the forwarding service modifies the message body, even by just adding an `[External]` tag or a URL-scanning link wrapper. This modification causes the DKIM body hash to mismatch, leading to a DKIM `fail`.

Spotting ARC in the Wild

So how do you differentiate a malicious spoof from a legitimate forwarded message? You look for traces of the Authenticated Received Chain (ARC), defined in RFC 8617. ARC is a protocol designed to solve this exact problem. It allows intermediate mail servers to attest to the original authentication results before forwarding.

An ARC-aware receiver, upon seeing a DMARC failure, will check for a valid ARC chain. If it finds one that shows the message *originally* passed SPF or DKIM, it may choose to trust the ARC results and override the DMARC failure. In your RUA reports, this often appears inside the `<policy_evaluated>` section with a `<reason>` tag. You might see a DMARC `fail` but a comment like `<comment>arc=pass</comment>`. This is a massive clue. It tells you the failure was likely due to forwarding, and that the modern mail ecosystem handled it correctly. If you see failures from major providers without any ARC data, it might mean their systems aren't ARC-compliant, which is a problem you need to account for.

From Raw Data to Actionable Checklist

A folder full of XML files is useless without a systematic way to query them and act on the findings. While you can open them one by one, the real power comes from treating them as a database. Command-line tools like `xmlgrep`, `grep`, or the more modern `yq` can quickly sift through hundreds of reports.

For example, using `yq`, you could find all failing sources across all reports in a directory with a query like: `yq '.feedback.record[] | select(.row.policy_evaluated.dkim == "fail" and .row.policy_evaluated.spf == "fail") | .row.source_ip' *.xml | sort | uniq -c`. This command extracts, sorts, and counts every source IP that failed both SPF and DKIM. This is how you turn data into a priority list.

After triaging your data, your remediation work will likely fall into a few common categories. First, identify any high-volume sources that are failing. These are your legitimate-but-misconfigured senders. Go find the business owner of that service and get them to configure DKIM correctly. This solves the majority of problems. Second, hunt for subdomain-specific issues. A failure from `marketing.yourdomain.com` might mean that subdomain lacks the necessary CNAME record for DKIM or isn't included in your SPF. Third, focus on third-party alignment. A service like Zendesk may pass SPF for `zendesk.com` but fail DMARC because the `From` header is `yourdomain.com`. The fix is almost always to configure DKIM alignment within that platform's admin panel. Finally, for persistent failures due to forwarding, identify the sources and decide if you need to contact those partners or if the volume is low enough to accept as a known issue.

The takeaway

Moving to `p=reject` is not a flip of a switch. It's an iterative, forensic process of identifying every legitimate way your domain is used, correcting the configurations, and shrinking the pool of 'unknowns' until you are confident that the only mail a `reject` policy will block is mail you truly want blocked. Dashboards give you the confidence to start the journey, but raw RUA reports are the map that guides you through the final, most difficult miles.

While manual analysis with command-line tools is a powerful skill, scaling this process across thousands of daily reports for multiple domains can be overwhelming. This is where platforms like MailSleuth.AI come in, automating the ingestion, parsing, and correlation of this data to surface the same actionable insights without the need for custom scripting.

#dmarc#email-security#rua-report#forensics#spf#dkim#mail-flow
MailSleuth Research
Email Security Team

We dissect phishing campaigns and email infrastructure so you don't have to.