Blog

How to Read DMARC XML Reports

DMARC aggregate reports are XML files that look intimidating but follow a predictable structure. Learn to read them manually.

Published October 28, 2025 Updated May 9, 2026
dmarc xml reports rua email-authentication
Guide to reading DMARC XML report data

DMARC aggregate reports follow a predictable structure: metadata about the reporter, your published policy, and rows showing authentication results per source IP. Once you understand the layout, they’re not as intimidating as they first appear.

You’ll probably use a monitoring service for ongoing analysis, but knowing how to read raw reports helps when troubleshooting or verifying what tools tell you.

What You Receive

DMARC aggregate reports arrive as:

  • Email attachments
  • Compressed files (.zip or .gz)
  • XML content inside

The filename usually indicates the sender and date range:

google.com!yourdomain.com!1703980800!1704067199.xml

The Report Structure

Every DMARC report has three main sections:

<?xml version="1.0" encoding="UTF-8"?>
<feedback>
  <report_metadata>...</report_metadata>
  <policy_published>...</policy_published>
  <record>...</record>
  <record>...</record>
  <!-- More records -->
</feedback>

Let’s break down each section.

Section 1: Report Metadata

<report_metadata>
  <org_name>google.com</org_name>
  <email>[email protected]</email>
  <report_id>12345678901234567890</report_id>
  <date_range>
    <begin>1703980800</begin>
    <end>1704067199</end>
  </date_range>
</report_metadata>
FieldWhat It Tells You
org_nameWho generated the report (Google, Microsoft, etc.)
emailContact for the reporting organization
report_idUnique identifier for this report
date_rangeUnix timestamps for the period covered

Converting timestamps: Use an online converter or:

date -d @1703980800
# Outputs: Sat Dec 30 2023 ...

This tells you what 24-hour period the report covers.

Section 2: Policy Published

<policy_published>
  <domain>yourdomain.com</domain>
  <adkim>r</adkim>
  <aspf>r</aspf>
  <p>reject</p>
  <sp>reject</sp>
  <pct>100</pct>
</policy_published>

This shows your DMARC policy as the reporter saw it:

FieldMeaning
domainYour domain
adkimDKIM alignment mode (r=relaxed, s=strict)
aspfSPF alignment mode (r=relaxed, s=strict)
pYour policy (none, quarantine, reject)
spSubdomain policy
pctPercentage of messages policy applies to

If this doesn’t match what you think your policy is, check your DNS record.

Section 3: Records (The Important Part)

Each <record> represents one source IP and its authentication results:

<record>
  <row>
    <source_ip>209.85.220.41</source_ip>
    <count>1523</count>
    <policy_evaluated>
      <disposition>none</disposition>
      <dkim>pass</dkim>
      <spf>pass</spf>
    </policy_evaluated>
  </row>
  <identifiers>
    <header_from>yourdomain.com</header_from>
  </identifiers>
  <auth_results>
    <dkim>
      <domain>yourdomain.com</domain>
      <result>pass</result>
      <selector>google</selector>
    </dkim>
    <spf>
      <domain>yourdomain.com</domain>
      <result>pass</result>
    </spf>
  </auth_results>
</record>

Breaking Down a Record

The <row> section:

  • source_ip: The IP address that sent email
  • count: How many messages from this IP
  • disposition: What happened (none, quarantine, reject)
  • dkim/spf: Pass or fail for DMARC evaluation

The <identifiers> section:

  • header_from: The From address domain in the email

The <auth_results> section:

  • Raw SPF and DKIM check results
  • Which domain was checked
  • For DKIM: which selector was used

Reading for Failures

When troubleshooting, look for records where:

<policy_evaluated>
  <dkim>fail</dkim>
  <spf>fail</spf>
</policy_evaluated>

Both failing means DMARC failed. Look at:

  1. source_ip: Who sent this? Look up the IP.
  2. count: How many messages? High count means a bigger problem.
  3. auth_results: Why did it fail?

Common Failure Patterns

SPF fail, DKIM pass:

<dkim>pass</dkim>
<spf>fail</spf>

The sender isn’t in your SPF record, but DKIM saved it. DMARC passes (only one needs to pass with alignment).

SPF pass, DKIM fail:

<dkim>fail</dkim>
<spf>pass</spf>

DKIM isn’t configured for this sender, but SPF worked. Still passes DMARC.

Both fail:

<dkim>fail</dkim>
<spf>fail</spf>

Neither authentication method worked. This is either:

  • Legitimate sender not configured properly
  • Unauthorized sender (spoofing attempt)
  • Forwarded email (breaks SPF, might break DKIM)

Looking Up Source IPs

When you see an unfamiliar IP, identify it:

# Reverse DNS
dig -x 209.85.220.41

# Or use whois
whois 209.85.220.41

Common results:

  • google.com: Google Workspace or Gmail
  • sendgrid.net: SendGrid
  • amazonses.com: Amazon SES
  • outlook.com: Microsoft

If you can’t identify the IP and both auth methods fail, it might be spoofing.

A Real-World Example

Here’s a complete record with explanation:

<record>
  <row>
    <source_ip>198.2.135.42</source_ip>
    <count>847</count>
    <policy_evaluated>
      <disposition>none</disposition>
      <dkim>fail</dkim>
      <spf>fail</spf>
    </policy_evaluated>
  </row>
  <identifiers>
    <header_from>yourdomain.com</header_from>
  </identifiers>
  <auth_results>
    <spf>
      <domain>bounces.sendgrid.net</domain>
      <result>pass</result>
    </spf>
  </auth_results>
</record>

What this tells us:

  • 847 emails from 198.2.135.42
  • DMARC failed (both dkim and spf failed in policy_evaluated)
  • SPF did pass, but for bounces.sendgrid.net, not yourdomain.com
  • This is an alignment failure. SendGrid’s SPF passed for bounces.sendgrid.net, but that domain doesn’t align with your header_from of yourdomain.com

The fix: Configure DKIM for SendGrid, or use a custom return-path domain.

Processing Multiple Reports

You’ll receive reports from many providers. Each covers their perspective:

  • Google reports what Gmail/Workspace saw
  • Microsoft reports what Outlook saw
  • Yahoo, Comcast, etc.

To get a complete picture, you need to aggregate across all reports. This is where monitoring services help: they combine every provider into one view.

Tools for Parsing

If you want to process reports yourself:

Command line:

# Decompress
gunzip report.xml.gz

# Pretty print
xmllint --format report.xml

# Extract source IPs with failures
grep -B5 "<spf>fail" report.xml

Python libraries:

  • xml.etree.ElementTree (built-in)
  • Various DMARC-specific parsers on PyPI

Online parsers:

  • Use our free DMARC Report Parser. Paste the XML or upload the file, get a readable view of sources, pass rates, and failures.
  • Useful when you have a single report in hand and want a quick read without writing a script.

When to Read Reports Manually

Most of the time, use a monitoring service. Manual reading is useful when:

  • Troubleshooting a specific failure
  • Verifying what a tool is telling you
  • Learning how DMARC works
  • Investigating a security incident
  • Your monitoring service is down

Quick Reference

ElementLocationWhat It Means
source_iprowWho sent the email
countrowHow many messages
dispositionpolicy_evaluatedWhat receiver did
dkim/spfpolicy_evaluatedPass/fail for DMARC
domainauth_resultsWhat domain was checked
resultauth_resultsRaw auth result

For more on interpreting what you find, see Understanding DMARC Reports.

If you have a single report in front of you right now and don’t want to read XML, paste it into our free DMARC Report Parser for a readable view.


Verkh ingests your DMARC reports daily, groups sources, and flags week-over-week changes so you don’t have to read XML to know what’s happening. Start Free. No credit card.

Ready to implement this?

Verkh helps you monitor DMARC, identify issues, and reach enforcement. Start free.

Start Free