Blog

How to Read DMARC XML Reports (Without Losing Your Mind)

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

Published October 28, 2025
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 = 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 SPF passed but didn’t align with your domain

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 excel—they combine everything into one dashboard.

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:

  • Several free tools will visualize a single report
  • Upload the XML, get a readable summary

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.


Verkh processes your DMARC reports automatically and highlights failures that need attention. Stop reading XML manually at verkh.io.

Ready to implement this?

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

Start Free