Back to blog

Tutorials

How to Read a DMARC XML Report and Identify Who Sends Email From Your Domain

Understand DMARC aggregate XML reports, identify senders and separate legitimate traffic from errors or suspicious use.

May 17, 2026 - 9 min

DMARC XML report excerpt: source_ip, count, policy_evaluated with DKIM pass and SPF fail, header_from, and a DMARC pass result

A DMARC aggregate report is an XML file, usually compressed, sent by a mailbox provider to the address in your DMARC record. It does not contain your messages. For a given period, it summarizes the IP addresses that sent on behalf of your domain and how they authenticated.

Direct answer: to find out who sends with your domain, group the report’s records by source_ip, identify the service behind each IP, then compare two blocks. auth_results shows whether SPF and DKIM succeeded. policy_evaluated shows whether they succeeded and aligned with the visible domain, header_from. Only this second result counts for DMARC: it passes when dkim or spf is pass there.

Key takeaway: a message can pass both SPF and DKIM and still fail DMARC. This is the most common sign of a legitimate tool that is misconfigured, and the first thing to look for in your reports.

In short

  • A report describes sources and volumes, never message content.
  • auth_results gives the raw result; policy_evaluated gives the alignment result.
  • A failing legitimate source gets fixed; an unknown source gets identified before you conclude anything.
  • One report is not enough: compare several days and several providers.

Get and open the report

Reports go to the address in the rua tag of your DMARC record:

_dmarc.example.com. TXT "v=DMARC1; p=none; rua=mailto:dmarc@example.com"

If that address belongs to another domain, that domain must authorize it by publishing a dedicated record:

example.com._report._dmarc.provider.example. TXT "v=DMARC1"

The attachment is usually compressed. Its name follows a standard format that already tells you who issued the report, for which domain and for what period:

receiver.example!example.com!1778889600!1778975999.xml.gz

The two numbers are Unix timestamps: seconds since January 1, 1970 UTC.

An annotated report

This example follows the RFC 9990 format. It is deliberately limited to three sources.

<feedback xmlns="urn:ietf:params:xml:ns:dmarc-2.0">
  <version>1.0</version>
  <report_metadata>
    <org_name>receiver.example</org_name>
    <email>noreply-dmarc@receiver.example</email>
    <report_id>20260516-a1b2c3</report_id>
    <date_range>
      <!-- May 16, 2026, 00:00:00 to 23:59:59 UTC -->
      <begin>1778889600</begin>
      <end>1778975999</end>
    </date_range>
  </report_metadata>
  <policy_published>
    <domain>example.com</domain>
    <!-- monitoring: nothing is blocked -->
    <p>none</p>
    <sp>none</sp>
    <adkim>r</adkim>
    <aspf>r</aspf>
  </policy_published>

  <!-- Case A: email marketing platform, 860 messages -->
  <record>
    <row>
      <source_ip>198.51.100.25</source_ip>
      <count>860</count>
      <policy_evaluated>
        <disposition>none</disposition>
        <!-- ALIGNMENT result, not the signature result -->
        <dkim>pass</dkim>
        <spf>fail</spf>
      </policy_evaluated>
    </row>
    <identifiers>
      <envelope_from>bounce.esp.example</envelope_from>
      <!-- the domain the recipient sees -->
      <header_from>example.com</header_from>
    </identifiers>
    <auth_results>
      <dkim>
        <!-- d= aligned with header_from -->
        <domain>example.com</domain>
        <selector>esp1</selector>
        <result>pass</result>
      </dkim>
      <spf>
        <domain>bounce.esp.example</domain>
        <!-- SPF is valid, but for another domain -->
        <result>pass</result>
      </spf>
    </auth_results>
  </record>

  <!-- Case B: invoicing tool, 312 messages -->
  <record>
    <row>
      <source_ip>203.0.113.40</source_ip>
      <count>312</count>
      <policy_evaluated>
        <disposition>none</disposition>
        <dkim>fail</dkim>
        <spf>fail</spf>
      </policy_evaluated>
    </row>
    <identifiers>
      <envelope_from>mail.billing-tool.example</envelope_from>
      <header_from>example.com</header_from>
    </identifiers>
    <auth_results>
      <dkim>
        <domain>billing-tool.example</domain>
        <selector>s1</selector>
        <result>pass</result>
      </dkim>
      <spf>
        <domain>mail.billing-tool.example</domain>
        <result>pass</result>
      </spf>
    </auth_results>
  </record>

  <!-- Case C: unknown source, 3 messages -->
  <record>
    <row>
      <source_ip>192.0.2.77</source_ip>
      <count>3</count>
      <policy_evaluated>
        <disposition>none</disposition>
        <dkim>fail</dkim>
        <spf>fail</spf>
      </policy_evaluated>
    </row>
    <identifiers>
      <envelope_from>example.com</envelope_from>
      <header_from>example.com</header_from>
    </identifiers>
    <auth_results>
      <spf>
        <domain>example.com</domain>
        <result>fail</result>
      </spf>
    </auth_results>
  </record>
</feedback>

Real reports vary by provider: some still follow the RFC 7489 format, with no namespace and with other tags. The fields used for diagnosis stay the same.

The fields to know

Field What it tells you Pitfall
date_range Period covered, in UTC Not the date you received the report
p Policy published at report time It may have changed during the period
source_ip Server that delivered the message With forwarding, this is the intermediate server
count Messages grouped in this row Not a number of recipients
disposition Treatment applied: none, quarantine, reject and, in the RFC 9990 format, pass none does not mean DMARC passed
policy_evaluated: dkim, spf Alignment result This is what determines DMARC
header_from Domain the recipient sees The reference for alignment
envelope_from Return-path domain, checked by SPF Optional, sometimes missing
auth_results: dkim, spf Raw verification result Can say pass without alignment
selector DKIM key used Helps recognize the platform

Interpret each case

auth_results (raw) policy_evaluated (alignment) DMARC Likely meaning What to do
SPF pass, DKIM pass, same domain spf pass, dkim pass Pass Correctly configured source Nothing, check that it is known
SPF pass on the provider’s domain, DKIM pass on yours (case A) spf fail, dkim pass Pass Common with an email marketing platform Acceptable: DKIM carries DMARC
SPF pass on your domain, DKIM missing or failing spf pass, dkim fail Pass Fragile: SPF does not survive forwarding Enable an aligned DKIM signature
SPF fail, DKIM pass on your domain, unknown IP spf fail, dkim pass Pass Often forwarding or a mailing list Check, usually nothing to fix
SPF pass and DKIM pass, both on the provider’s domain (case B) spf fail, dkim fail Fail Legitimate tool, not aligned Priority: set up DKIM with your domain
SPF fail, DKIM failing on your domain, forwarding IP spf fail, dkim fail Fail Message changed in transit, or broken signature Identify the intermediary or platform
SPF fail, no DKIM, unknown IP (case C) spf fail, dkim fail Fail Forgotten tool or spoofing attempt Investigate: see below

These readings are starting hypotheses. A report does not show message content, so only identifying the source lets you conclude.

Identify senders, step by step

Step Action Validation
1 Decompress a week of reports and turn each record into a table row. count totals per report are consistent and no file was skipped.
2 Check policy_published first and, if present, error. The policy shown matches the one you think you published.
3 Group rows by source_ip, then by DKIM domain and SPF domain. Each group represents one likely service.
4 Identify each source: reverse DNS, IP owner, selector, d= domain and envelope_from. Each source has a service name, or is marked “unknown”.
5 Find the internal owner of each service. Each legitimate service has a named owner.
6 Classify: legitimate and compliant, legitimate to fix, forwarding, unknown. No source remains unclassified.
7 Fix by volume and criticality, then check later reports. Alignment turns to pass for that source in new reports.

Diagram: investigate a source IP

Investigation process for a source IP found in a DMARC aggregate report

Source IP analysis combines reverse DNS, WHOIS, likely provider and authentication results.

An IP address owned by Google or Microsoft does not prove it is your mail system: these infrastructures are shared across many customers. Rely on the DKIM signing domain and the alignment result instead.

Low volume does not mean low risk, and an unknown source is not necessarily an attack. Before concluding, ask your marketing, finance and support teams: an old tool or a forgotten provider is a common explanation.

Before enforcing the policy

  • Several days of reports were analyzed, across several providers.
  • Infrequent sends, such as monthly invoicing, appear in the observed period.
  • Each legitimate source has dkim or spf at pass in policy_evaluated.
  • Tools relying only on SPF were reviewed, since forwarding can make them fail DMARC.
  • Remaining sources are explained, or knowingly treated as illegitimate.

To move on to the fixes, see How to Configure SPF, DKIM and DMARC Without Breaking Email Delivery.

FAQ

Why does DKIM show pass in auth_results and fail in policy_evaluated?

Because the two blocks measure different things. The signature is valid, but its d= domain does not match header_from. This is typical of a tool signing with its own domain.

Why is disposition none when DMARC failed?

With p=none, no action is requested. The receiver may also have applied a local exception, in which case the reason field says so.

Why am I not receiving any reports?

Check the record syntax, the rua address and, if it is on another domain, the _report._dmarc authorization record. Not all providers send reports, and very low volumes may not produce any.

Do reports contain the content of my emails?

No. Aggregate reports contain domains, IP addresses, volumes and results, with no subject or body. Handle them with care anyway, since they describe your sending flows.

What is the difference between rua and ruf?

rua receives the aggregate reports described here. ruf is for failure reports about individual messages. These are defined in RFC 9991, and many providers do not send them.

Do I need a tool to read these reports?

Not for one or two reports. Beyond that, manual reading quickly becomes difficult: a script or an analysis platform lets you combine data by source. The reading stays the same: source, alignment, volume.

Conclusion

Reading a DMARC report means answering three questions for each source: who is it, is it aligned, and what volume does it represent? If you would rather delegate this monitoring, see our DMARC monitoring service (page in French).

Sources