DMARC Report Analyzer
Open a DMARC aggregate report to see which servers send mail as your domain and whether that mail passes DMARC. Your browser reads the file; it is never uploaded.
Choose a file or drop it here. Your browser reads it; nothing is uploaded.
What a DMARC report analyzer shows
When your domain publishes a DMARC record with an rua= address, mail providers that support DMARC send you aggregate reports: one XML file per receiver and period, usually compressed. The standard asks receivers to send them at least once every 24 hours. Each file lists, for every server that sent mail with your domain in the From address, how many messages it sent, whether DKIM and SPF passed in a way that counts for DMARC, and what the receiver did with the mail.
The XML is written for machines, not people. This DMARC analyzer turns one report into a summary: how many messages passed DMARC, which sending IP addresses failed, what policy you published and what the receiver applied. Every row of the file is also shown as a table, so you can compare it with the XML.
Your file stays on your device. The report is read by your browser with the same analysis engine that runs our other checks. There is no upload: we never receive the file, its contents or its name. When you open a file, your browser may fetch the analyzer's program code from this site; that request carries nothing from your file.
What the analyzer accepts:
- plain
.xml, gzip-compressed.xml.gzand.ziparchives (the format is detected from the file's first bytes, not from its name); a.zipwith several reports is read in one go, up to 64 files; - both report formats in use: the original one from RFC 7489 and the newer one from RFC 9990, which some receivers already send.
What it does not do: it does not repeat the receiver's DKIM and SPF checks (it reports the receiver's own results exactly as written), and it does not look up who owns an IP address, because that would need network requests.
How to read the result
DMARC pass, fail and unknown
The panel at the top of the result sums up every message in the file: a colored icon and a short label. It shows Pass when the whole file was read and every message passed DMARC, Review when some failed or have no clear result, and Unknown when the file has no message counts to add up, none of its messages has a clear result, or every message we read passed but part of the file could not be read or was stopped by a safety limit: the messages we did not read could have failed. It never shows Fail for the whole file: failing mail in a report is often someone else's, stopped by your policy.
A message passes DMARC when the receiver found either DKIM or SPF aligned with your domain; it fails when both are reported as failing. When the report leaves one of them out or uses a value outside the standard, and the other one did not pass, the result is Unknown. We never count a missing value as a failure. The numbers are messages, taken from each row's count.
A failure is not always your problem. Failing mail is usually one of three things: a service of yours that is not set up yet, your mail forwarded by someone else (a forwarding address or a mailing list), or someone sending with your domain, which DMARC is there to stop. The sources table and the override reasons tell them apart.
DKIM aligned and SPF aligned
DMARC does not only ask whether DKIM or SPF passed, but for which domain. A DKIM signature counts only when its domain (d=) matches the domain in the From address; SPF counts only when the envelope sender (the bounce address) does. By default the match is relaxed: mail.example.com matches example.com. With adkim=s or aspf=s in your record the domains must be identical.
That is why the table has two sets of columns. DKIM aligned and SPF aligned are the receiver's verdict for DMARC. DKIM signatures and SPF check are the raw results. In the sample report, the newsletter service passes SPF for bounces.newsletter.example.net, which does not align with example.com, so SPF aligned is fail; its DKIM signature is for example.com, so the messages still pass DMARC.
What receivers did: none, quarantine, reject
The applied policy is what the receiver did with the messages of a row: none (delivered as usual), quarantine (usually the spam folder) or reject (refused). Reports in the RFC 9990 format may also say pass. Seeing none while your record says p=quarantine is normal for mail that passed DMARC. For failing mail it means the receiver made an exception, and the Override reason column says why:
forwarded,mailing_list,trusted_forwarder: the receiver believes the mail was relayed, which breaks SPF and often DKIM;sampled_out: your record used the oldpcttag to apply the policy to only a share of failing messages, so receivers that follow the older standard (RFC 7489) applied one step less than your policy to the rest. A test-mode record from our DMARC generator haspct=0next tot=y, so these receivers may report your failing mail this way. The newer report format (RFC 9990) has nosampled_out: receivers that follow the newer standard do not readpct, and for a record witht=ythey may reportpolicy_test_modeinstead;policy_test_mode: your record hast=y, which asks receivers to apply one step less than your policy;local_policyandother: the receiver's own rules; the comment next to it may explain.
A receiver does not have to give a reason at all: it is optional in both report formats.
Sending sources: whose servers are these?
The sources table groups rows by sending IP address, most messages first. Go through the addresses with failures and ask which service they belong to. The header of a message you received from that service, a reverse DNS lookup of the address, or the IP ranges your email provider publishes usually answer it. A service you use is fixed as described below; an address you cannot connect to any service is most likely someone using your domain, and there is nothing to fix on your side.
Rows without a message count
Every row should say how many messages it covers. When count is missing or is not a whole number, we show the row with an unknown count and leave it out of the totals rather than guess 0 or 1. The note under the summary says how many rows that affects. If the totals ever become too large to add up exactly, the summary says so too.
When the file cannot be read
If a file, or one file inside a .zip, cannot be read as a report, it is listed with one of these reasons. The other reports in the same archive are still shown.
- The file is too large. We read files up to 32.0 MiB. RFC 7489 notes that a commonly observed receiver limit is ten megabytes, so a larger file is rarely a single report; check that you picked the attachment and not a whole mailbox export.
- The file is empty or contains no XML elements at all.
- Not an XML report. The file is something else, for example the email itself (
.eml) or a PDF. Save the report attachment from the email and open that. - Broken XML. The markup is damaged, so the data cannot be read reliably. The detail line gives the line and column where the parser stopped.
- Not a DMARC aggregate report. It is valid XML, but its top element is not
<feedback>. - DOCTYPE declaration. DMARC reports never need one, and a DOCTYPE is how XML bombs and external-entity attacks work, so such a file is refused outright.
- Damaged .gz file. The compressed data is incomplete or its checksum does not match, often because the download was cut short. Save the attachment again.
- Damaged .zip file. The archive is inconsistent: cut short, a checksum mismatch, or files that overlap each other inside the archive (a known trick of zip bombs).
- Empty .zip archive: it contains no files.
- Encrypted or unusual .zip entry. The file inside is password-protected or uses a compression method other than the two common ones. Extract it with your archive tool and open the XML.
- A .zip inside a compressed file. Extract the inner archive first, then open it here.
- Compressed too many times over. We open at most 3 layers (for example a
.zipholding a.gz). - A safety limit was reached before any report data could be read, for example an XML element with hundreds of attributes at the very start. See the limits below.
- Something went wrong inside the analyzer. That is our bug, and the result is unknown. The other reports in the file are unaffected. If you can, tell us at the address at the bottom of the page which receiver sent the file; please do not send the file itself unless we ask.
- Your browser could not open the file. This happens when the file was moved, renamed or changed after you chose it. Nothing was analyzed or uploaded; choose the file again.
- The analyzer stopped in your browser. The whole file then shows “Could not read this file”. This usually means the browser ran out of memory on a very large file; try a desktop browser. It says nothing about your mail.
Problems inside a report that was still read
Real reports are not always tidy. When something is off but the report is still readable, we show the data and list the problem under it with where it was found and how often. Values are never invented: a value we could not use is shown as “not in the report” or as Unknown.
- Missing element: something both report formats require is absent, such as the reporting organization, the report ID, the date range, your policy, a row's source IP, count or result.
- Repeated element: an element that may appear once appears twice; the first one is used.
- Unexpected element: an element that is in neither format (and is not a declared extension) is ignored.
- Elements inside a value: a field that should hold plain text contains other elements, so its value is not used.
- Unknown value: a field holds a value outside the allowed list (for example a disposition other than none, quarantine, reject or pass). It is shown as written and counted as Unknown.
- Unexpected capital letters: a known value is written in another case, such as
PASS. We read it in lower case and note it, because the report formats define these values in lower case. - Empty value: the element is there but holds nothing.
- Not a whole number: a count or a timestamp contains something else, so it is left out rather than guessed.
- Number too large: a count or timestamp is beyond what can be added up exactly, so it is left out.
- Not an IP address: the source IP is not a valid IPv4 or IPv6 address. It is shown as written.
- Dates in the wrong order: the report period ends before it begins.
- Unknown format marker: the report declares an XML namespace that belongs to neither report format. We still read it by element names.
- Unexpected version: the report's
<version>is not 1.0, the only version both formats define. - No rows: the report contains no
<record>at all, although the format requires at least one. - Unreadable characters: some bytes are not valid in the file's text encoding. They are replaced with � and counted.
- Unknown text encoding: the XML declares an encoding we do not know, so it was read as UTF-8.
- Contradictory encoding: the file's byte-order mark and its declared encoding disagree.
- Extra data after the report: the
.gzfile has damaged bytes after a complete, verified report. The report itself is fine. - Unread text after the report: more than 65,536 characters follow the end of the report; they were not read.
- Checksum not verified: a safety limit stopped reading a compressed file before its checksum could be checked, so a damaged file cannot be ruled out for the part shown.
- File name does not match the report: report names follow the pattern
receiver!your-domain!begin!end.xml.gz, and the domain or dates in the name differ from the ones inside. The data inside is what the table shows.
Safety limits
A report file comes from outside, so the analyzer has limits that stop damaged or hostile files (such as zip bombs) from freezing your browser. Real reports stay far below them. When a limit is reached, the result says so in a dashed box, the summary is marked partial, and it shows exactly what was read; nothing is cut silently.
| Limit | Value | What you get when it is reached |
|---|---|---|
| File size | 32.0 MiB | Nothing: the file is not analyzed. |
| Decompressed data, all layers and files together | 64.0 MiB | Everything read up to that point. |
| Files analyzed in one .zip | 64 | The first 64; the rest are listed as not analyzed. |
| Compression layers | 3 | The inner layers are not opened. |
| Separate parts in one .gz stream | 1,000 | The parts read up to that point. |
| XML nesting depth | 32 levels | The report up to that point (real reports need 6). |
| Rows in one report | 200,000 | The first 200,000 rows. |
| Text in one element | 65,536 characters | The text, cut at that length. |
| Elements in one part of the report | 10,000 | The extra elements are ignored. |
| Attributes on one XML element | 64 | The report up to that point. |
| Different problems listed per report | 1,000 | The first 1,000, with the number left out. |
Long reports on screen
To keep the page fast, the table of rows shows the first 1,000 rows of each report and the sources table the first 200 addresses. A note under the table says when that happens. The totals always include every row, and the downloaded JSON contains all of them.
How to fix sources that fail DMARC
For every failing source that is yours, make at least one of DKIM or SPF pass for your own domain. DKIM is the better choice: it usually survives forwarding, and one signature covers the service whatever servers it uses.
- Turn on DKIM signing with your domain in the sending service. It gives you one or more records to publish (TXT or CNAME, at a name ending in
._domainkey). - Align SPF if the service allows it. Many services can use a bounce address at your domain (often called a custom return-path or MAIL FROM domain). Adding the service to your SPF record helps only if that bounce domain is yours.
- Wait for the next reports (usually a day) and open them here. The source should now show DKIM aligned as Pass.
Google Workspace
In the Google Admin console go to Menu > Apps > Google Workspace > Gmail and select Authenticate email. Generate a record (2048-bit if your DNS host supports it; the default selector is google), publish it as a TXT record at google._domainkey, then come back to the same screen to turn authentication on. SPF for Google Workspace is v=spf1 include:_spf.google.com ~all, merged into your one SPF record.
Microsoft 365
In the Microsoft Defender portal go to Email & collaboration > Policies & rules > Threat policies > Email authentication settings and open the DKIM tab. Select your domain; Microsoft shows two CNAME records to publish, at selector1._domainkey and selector2._domainkey. After they are live, turn on signing there. SPF for Microsoft 365 is v=spf1 include:spf.protection.outlook.com -all, again merged into your one SPF record.
Zoho, SendGrid, Mailgun, Amazon SES and other services
Look for domain authentication, sender authentication or DKIM in the service's settings for your sending domain. It lists the records to add (usually two or three CNAME or TXT records) and checks them for you. Where the service offers a custom bounce or MAIL FROM domain under your domain, set that up too, so SPF aligns as well.
Forwarded mail and mailing lists
Mail that passes through a forwarder or a mailing list reaches the receiver from the forwarder's servers, so SPF fails, and a list that edits the message breaks DKIM. Do not add those servers to your SPF record. DKIM without changes to the message survives forwarding, and many receivers make an exception for known lists (the Override reason column shows it).
Moving from p=none to quarantine and reject
RFC 9989 recommends starting with p=none and a report address, fixing every legitimate source the reports reveal, and only then moving to enforcement. When all your own sources pass for a couple of weeks of reports, change p=none to p=quarantine, and later to p=reject. From then on, failures in the reports are mostly mail that receivers kept out of the inbox; the Applied policy and Override reason columns show where a receiver made an exception.
How to get DMARC reports for your domain
Add a report address to the DMARC record at _dmarc.example.com (TXT):
v=DMARC1; p=none; rua=mailto:[email protected]Several addresses are separated by commas. If the address is at another domain (for example a reporting service), that domain has to agree to receive your reports by publishing a TXT record v=DMARC1; at example.com._report._dmarc.its-domain; otherwise receivers skip it. The steps to add a TXT record at Cloudflare, GoDaddy and Namecheap are in our TXT record guide.
What a DMARC aggregate report looks like
A report is one <feedback> document: who sent it and for which period, the policy the receiver found for your domain, then one <record> per group of messages. A shortened row from our sample report:
<record>
<row>
<source_ip>198.51.100.25</source_ip>
<count>96</count>
<policy_evaluated>
<disposition>none</disposition>
<dkim>pass</dkim>
<spf>fail</spf>
</policy_evaluated>
</row>
<identifiers>
<header_from>example.com</header_from>
</identifiers>
<auth_results>
<dkim><domain>example.com</domain><result>pass</result></dkim>
<spf><domain>bounces.newsletter.example.net</domain><result>pass</result></spf>
</auth_results>
</record>Read it as: 96 messages from 198.51.100.25 claimed to be from example.com; their DKIM signature for example.com aligned, SPF passed only for the service's own bounce domain, so the messages passed DMARC on DKIM and were delivered normally. The sample uses addresses reserved for documentation (RFC 5737 and RFC 3849) and example domains, not real senders.
Report files are named receiver!your-domain!begin!end.xml.gz, with the period as Unix timestamps, so the name alone tells you who sent it and for which day. The analyzer compares the name with the contents and notes any difference.
Frequently asked questions
What is a DMARC aggregate report?
A summary, usually one per day, that mail providers send to the address in your DMARC record's rua= tag. It lists the servers that sent mail with your domain in the From address, how many messages each sent, and whether they passed DKIM, SPF and DMARC. It contains no message content. The per-message failure reports (ruf=) are a different kind of report and are not read here.
Is my DMARC report uploaded to your server?
No. Your browser reads the file and runs the analysis on your device. There is no upload, and nothing about the file is sent to us. Our privacy policy says the same.
Why does a message fail DMARC when SPF passes?
Because SPF passed for a different domain. SPF checks the bounce address, which many sending services set to their own domain. DMARC needs the passing domain to match your From domain. See DKIM aligned and SPF aligned.
How do I open a .xml.gz or .zip DMARC report?
Save the attachment and drop it on this page as it is; you do not need to extract it. To read it by hand, open a .zip with any archive tool, or run gunzip report.xml.gz on macOS or Linux, and open the XML in a text editor.
Why am I not receiving DMARC reports?
Check that your DMARC record at _dmarc has an rua=mailto: address, that the mailbox exists, and, if it is at another domain, that this domain publishes the _report._dmarc record described above. Receivers are asked to send reports at least once a day, so expect the first ones a day or so after mail went out. Not every mail provider sends them.
Is this DMARC analyzer free?
Yes. There is no sign-up and no limit on how many files you open, because the work happens in your browser. A .zip with up to 64 reports is read in one go.
Page updated .