Skip to content

DMARC Checker & Generator

How the checker finds and grades a DMARC record, every rule applied to its tags, what each finding means for spoofed and legitimate mail, and how the builder and the path to enforcement write the next record.

Open Markdown

The tool page is tamperbox.dev/dmarc-checker. It opens on a live check of tamperbox.dev; replace that domain to inspect your own. This page is the long version: how the record is found and read, every rule applied to it, what each finding means, and how the builder and the path to enforcement write the next record.

Where processing happens: a domain is sent to the Tamperbox server, which asks public DNS for the TXT record at _dmarc.<domain>. A pasted record is parsed and graded in your browser, and every draft you build stays on the page. Nothing is stored, and copying a draft does not publish it.

DMARC tells receivers what to do with mail that fails both aligned SPF and aligned DKIM, and where to send reports about it. The tool answers:

  1. Is there a valid record, and what does it say? One record at the exact name, every tag explained.
  2. How much does it protect? The policy, the percentage it applies to, and the subdomain policy.
  3. Will you hear about failures? Aggregate report addresses, their format, and whether an outside receiver needs to authorise them.
  4. What is the next safe step? A draft record for each step from monitoring to reject, with every change kept in History.

It does not read aggregate reports, so it cannot say whether your legitimate mail already passes.

example.com. When you stop typing, or on Enter, the server reads the TXT records at _dmarc.example.com and keeps the ones that begin with v=DMARC1. Two or more is a finding; none shows a starting draft.

Paste the record itself, with or without quotes: v=DMARC1; p=none; rua=mailto:dmarc@example.com. It is parsed in the browser and shown as “Pasted record”. Publication, and the policy a parent domain may publish, are not checked.

Drop a .txt file anywhere on the page, or use Open file. It is read in the browser.

The verdict names the policy’s effect: no policy, monitoring only, quarantining or rejecting a share or all of failing mail, or an invalid record, followed by where the record came from (published, pasted, or a draft). The chips show the policy with its percentage, whether reports are on, and whether you are looking at the published record, a pasted one, or a draft; each one is a button that scrolls to the section that explains it.

Everything found, worst first; passes fold into one line. The p=none finding carries a button that moves the draft one step forward. The finding reference lists them all.

Links that carry a derived value into another tool: the mail route of the report mailbox’s domain, BIMI readiness for the domain once the policy enforces, and DNSSEC on the zone. Each opens the destination with the value already in its box; nothing is put in the URL.

History logs every change: a rollout step, a builder edit, a Break it case or a Heal it repair, each with the record it replaced. Revert undoes the newest change and returns the draft to the record before it; Reset input returns to the published or pasted record. Heal it offers the repairs the tool found: add p=none, correct a misspelt policy, remove obsolete pct, make rua a mailto: address, choose which value to keep when a tag is duplicated, move a misplaced version tag to the front.

Four targets, each a complete record built from the current tags: Monitor (p=none), Test quarantine (p=quarantine; t=y), Quarantine all (p=quarantine), Reject (p=reject). The current step is marked “You are here”. Choosing a target applies it as a draft. The test step requests one level less enforcement under RFC 9989 section 4.7, so quarantine in test mode requests monitoring.

Policy, subdomain policy, percentage, aggregate and failure report addresses, DKIM and SPF alignment, and failure options. Every change applies at once and is graded like a published record.

The draft as one TXT record, with the name to publish it at and a copy button. Copying does not publish.

Every tag with its label and meaning; unknown tags are marked as ignored by receivers.

Each rule below names the section of RFC 9989, the DMARC specification, that it comes from. RFC 9989 obsoletes RFC 7489, the Informational predecessor; where the tool still follows RFC 7489, the rule says so, and Standards and conformance lists every difference.

The server asks public DNS, through one DNS-over-HTTPS resolver, for TXT records at exactly _dmarc.<domain> (RFC 9989, section 4.5). A record split into several strings is joined first: “the module performing DMARC evaluation MUST concatenate these strings” (section 4.5). Only records that begin with v=DMARC1 are kept, as in step 2 of the DNS tree walk, section 4.10.

  • Two or more records are discarded at that name and discovery continues toward a parent policy, following section 4.10. No first-record-wins policy is inferred.
  • No record: the verdict is “No DMARC record” and a starting draft, v=DMARC1; p=none, is prepared for the builder.

The lookup moves up the tree, bounded to eight queries, and stops at an explicit psd=n or psd=y boundary. Section 4.10.1 has receivers walk from the Author Domain to its Organizational Domain and then to a public suffix domain when no record exists at the exact name. The selected source domain is displayed. Domain existence is not queried, so inherited policy is shown for existing subdomains and np remains a limitation.

The record is split on semicolons, and each part must be name=value, as in the formal definition of section 4.8.

  • The first tag must be exactly v=DMARC1, case-sensitive. Section 4.7: “This tag MUST be the first tag in the list.” If it is not, “the entire record MUST be ignored.” The tool stops: “Not a DMARC record”. Heal it can move a misplaced v=DMARC1 to the front.
  • A part without =: FAIL, “Not a tag: X”.
  • A tag that appears twice: FAIL, “name appears twice”. DMARC uses the DKIM tag-list syntax (section 4.7), and RFC 6376, section 3.2 says “if a tag name does occur more than once, the entire tag-list is invalid.” Identical duplicates can be removed; conflicting values get one repair per value (“Keep p=none”, “Keep p=reject”). While duplicates remain, the policy is not graded and the builder, the path to enforcement and the record to publish are hidden.
  • p, sp and np accept only none, quarantine or reject (the dmarc-request rule of section 4.8); adkim and aspf only r or s (dmarc-rors). Anything else: FAIL, “name=value is not valid”.
  • No p: INFO, “No p= policy: defaults to none”. An otherwise valid record defaults to monitoring under section 4.7.
  • pct produces CHECK, “pct=X is obsolete”. It never reduces enforcement; RFC 9989 appendix A.6 removes percentage sampling.
  • A tag outside v, p, sp, np, t, psd, pct, rua, ruf, adkim, aspf, fo, rf, ri: CHECK, “Unknown tag X”. Section 4.7: “unknown tags MUST be ignored.”

The grade follows section 4.7. Missing p defaults to none; pct is ignored. Test mode t=y reduces reject to quarantine and quarantine to none. The display reports a requested policy, not a guarantee of receiver handling.

Record Severity Title Basis
p=reject, no test mode PASS p=reject Section 4.7, p
p=quarantine, no test mode PASS p=quarantine Section 4.7, p
p=quarantine; t=y CHECK DMARC test mode (t=y), p=none only monitors Section 4.7, t
p=reject; t=y CHECK DMARC test mode (t=y), p=quarantine Section 4.7, t
p=none CHECK p=none only monitors Section 3.2.12, Monitoring Mode
sp=none with an enforcing p CHECK sp=none on subdomains Section 4.7, sp
adkim=s or aspf=s INFO Strict alignment Section 3.2.10.2

For sp, section 4.7 says: “If both the “sp” tag is absent and the “np” tag is either absent or not applicable, the policy specified by the “p” tag MUST be applied for subdomains.” So sp=none beside an enforcing p opens every existing subdomain on purpose. The p=none and sp=none grades are Tamperbox recommendations: the specification allows both.

  • No rua: CHECK, “No rua reports”. Section 4.7: “If the tag is not provided, Mail Receivers MUST NOT generate aggregate feedback reports for the domain.” Reports are optional in the specification; the CHECK is a Tamperbox recommendation, since section 5.1.5 has the Domain Owner collect and analyse them before enforcing.
  • Each comma-separated rua entry (section 4.6) must be a mailto: URI with one @, optionally followed by a size limit such as !10m. Anything else: FAIL, “Invalid report address X”. This is stricter than the specification, where “Any valid URI can be specified” and “URIs involving schemes not supported by Mail Receivers MUST be ignored” (section 4.7). The size limit is obsolete syntax that reporters ignore (section 4.8).
  • An address on a domain that is neither the checked domain nor one of its subdomains: INFO, “Reports go to X”, naming the record the receiving domain must publish, <domain>._report._dmarc.<receiving-domain>. RFC 9990, section 4 says that when the Organizational Domains differ, “the following verification steps MUST be taken”. That record is not looked up. For a pasted record the domain is unknown, so no note is made.
  • Otherwise: PASS, “N report addresses”.

ruf, fo, rf and ri are explained but not validated.

The builder writes tags in a fixed order (v, p, sp, np, t, psd, pct, rua, ruf, adkim, aspf, fo, rf, ri), keeps unknown tags at the end, and leaves out tags that only repeat a default (pct=100, adkim=r, aspf=r, fo=0, rf=afrf, ri=86400). The adkim, aspf and fo defaults are those of section 4.7; the pct, rf and ri defaults are RFC 7489’s. Starting with v=DMARC1 keeps every draft valid under section 4.7.

A draft is graded by the same rules as a published record. The problems of the published record (duplicates, multiple records) are not carried into the draft’s findings, except the multiple-records finding, which the draft cannot fix.

The tool reads one DMARC record and grades its text. It is not a mail receiver: it evaluates no message, so SPF and DKIM results and identifier alignment are never computed. This section lists, per specification, what the tool implements, where it stops and where it is stricter or more lenient than the text.

DMARC was published as RFC 7489 (Informational, 2015). In May 2026 three Standards Track documents obsoleted it: RFC 9989 for the mechanism (which also obsoletes RFC 9091, the experimental public suffix domain policy), RFC 9990 for aggregate reports and RFC 9991 for failure reports, which also updates RFC 6591. The tool’s tag table still follows RFC 7489 in several places, listed below.

Section Requirement What the tool does
4.5 Records are TXT at _dmarc.<domain>; strings MUST be concatenated Looked up on the Tamperbox server through one public resolver; strings joined
4.10, step 2 Records not starting with v=DMARC1 are discarded; several records are all discarded Same filter; multiple records at a name are discarded
4.10.1 Without a record at the Author Domain, walk to the Organizational Domain and the public suffix domain Implemented with at most eight queries
4.10 The tree walk replaces the Public Suffix List and stops at a record with psd=y or psd=n Implemented; source domain is shown
3.2.13 A non-existent domain is one answering NXDOMAIN; np applies to those Not checked; np is only validated
5.3.1 A U-label Author Domain MUST be converted to an A-label The domain is converted to A-labels before the lookup

The lookup accepts v or V as the version tag name but requires the case-sensitive value DMARC1, following section 4.8.

All parsing happens in the browser, from the text the server returned or the text you pasted.

Section Requirement What the tool does
4.7, v First tag, value exactly DMARC1, else ignore the record Same: the record is not read
4.7 Unknown tags MUST be ignored CHECK finding, record still graded
4.8 Syntax errors MUST be discarded in favour of defaults or ignored Stricter: a malformed part or an invalid value is a FAIL and makes the verdict invalid
4.7, p Missing p is treated as p=none Defaults to monitoring with an informational finding
4.10.1 Invalid p, sp or np with a valid rua: act as p=none; otherwise no DMARC processing Not modelled; the tool reports the record as invalid
4.7, adkim, aspf r or s, default r Validated; default left out of drafts
4.8, fo 0 or 1 with d and s, colon-separated; ignored without ruf Explained, not validated
4.6, rua and ruf Comma-separated URIs; any valid URI rua must be mailto:; ruf is not checked
4.8 !size suffix is obsolete; reporters ignore it Accepted without comment

RFC 9989: tags removed and added since RFC 7489

Section titled “RFC 9989: tags removed and added since RFC 7489”

Appendix C.5 lists the tag changes. Under RFC 9989 a removed tag is simply an unknown tag, so receivers ignore it.

Tag Change in RFC 9989 What the tool does
pct Removed (appendix C.5.2, A.6) Warned as obsolete and ignored for grading; no percentage rollout step
rf Removed Known tag with an explanation; not flagged
ri Removed Known tag with an explanation; not flagged
t Added: y asks receivers to apply one level below the policy; default n Validated and used to downgrade the effective policy
np Added, imported from RFC 9091 Known; values validated; not graded
psd Added: y, n or u, default u Validated and used to stop discovery

Appendix A.6 explains the replacement: the t values y and n are “meant to be analogous” to pct=0 and pct=100. A receiver that follows RFC 9989 treats p=quarantine; pct=25 as full quarantine. Receivers still built on RFC 7489 may apply the percentage, which may differ from the current-policy grade shown here.

Section 7.4 says “domains that host users who might post messages to mailing lists SHOULD NOT publish Domain Owner Assessment Policies of “p=reject”“, and domains that publish p=reject “MUST apply valid DKIM signatures to their messages.” The tool grades p=reject as PASS and offers Reject as the last step of the path to enforcement without this caveat. It cannot know who sends from the domain, so weigh section 7.4 yourself before that step.

Section 5.1.7 ties the move to enforcement to “many months of consuming DMARC aggregate reports” in some cases. The tool does not read reports, so it cannot judge readiness.

Section Requirement What the tool does
RFC 9990, 3.5 Malformed URIs SHOULD be ignored; deliver to every remaining URI Flags the first malformed rua entry as a FAIL
RFC 9990, 4 When the policy’s Organizational Domain differs from the destination’s, query <policy-domain>._report._dmarc.<destination-host> Names that record for the first external address; does not look it up
RFC 9990, 4 The comparison is between Organizational Domains Approximated: an address outside the checked domain and its subdomains counts as external
RFC 9991, 5 The same verification applies to ruf Not done for ruf
RFC 9991, 2 Failure report options come from ruf and fo Explained only

The approximation errs both ways: a report address at the parent domain of a checked subdomain is called external although it shares the Organizational Domain, and no external note is made for a pasted record.

DMARC passes when SPF (RFC 7208) or DKIM (RFC 6376) produces an authenticated identifier aligned with the From domain (RFC 9989, section 4.4). The tool only reads the adkim and aspf modes and explains the difference between relaxed and strict alignment (sections 3.2.10.1 and 3.2.10.2). It checks no SPF record, no DKIM key and no message; use the SPF and DKIM checkers for those.

The _dmarc label is registered in the “Underscored and Globally Scoped DNS Node Names” registry of RFC 8552; RFC 9989 section 9.5 now holds that registration, and RFC 8553 updated RFC 7489 to use the registry. RFC 8616, section 6 updated RFC 7489 so that U-labels are converted to A-labels and rua and ruf hold conventional addresses; RFC 9989 section 5.3.1 carries the A-label rule. The tool converts the domain you enter to A-labels before the lookup and accepts any non-space characters around the @ of a report address.

Each finding the checker can emit, grouped by what it judges, with what it means for mail sent as the domain. The RFC section column names the rule behind the finding; “none” marks a Tamperbox recommendation that the specification does not require.

Problems that make receivers ignore the record or parts of it. Links point to RFC 9989 unless marked.

Finding Severity What it means for mail Fix RFC section
No DMARC record (verdict) FAIL No policy at this name; a parent policy may apply Publish the starting draft 4.10.1
N DMARC records FAIL Receivers discard every record at the name Delete all but one 4.10
Not a DMARC record (verdict) FAIL Receivers ignore the whole record Put v=DMARC1 first 4.7
Not a tag: X FAIL Receivers discard the part Write name=value 4.8
name appears twice FAIL The tag list is invalid; the policy is not graded Keep one value RFC 6376, 3.2
name=value is not valid FAIL Bad p, sp or np: p=none if rua is valid, else no DMARC; bad adkim or aspf: default r Use a valid value 4.10.1, 4.8
No p= policy: defaults to none INFO Receivers act as if p=none Add p=none 4.7
pct=X is obsolete CHECK Current receivers ignore percentage sampling Remove pct A.6
Invalid report address X FAIL Receivers skip that address Use mailto: 4.7
Unknown tag X CHECK Receivers ignore it Review or remove it 4.7

How much of the failing mail the policy acts on.

Finding Severity What it means for mail Fix RFC section
p=none only monitors CHECK Spoofed mail is still delivered Move to quarantine when reports are clean none (Tamperbox recommendation); 3.2.12 defines the mode
DMARC test mode (t=y) CHECK Effective policy is one level below the declared policy Review reports before disabling test mode 4.7
sp=none on subdomains CHECK Subdomains can be spoofed Remove sp or match p none (Tamperbox recommendation); 4.7 defines sp
p=reject, p=quarantine PASS Failing mail is refused or quarantined 4.7

Who receives aggregate reports and how strictly identities must match.

Finding Severity What it means for mail Fix RFC section
No rua reports CHECK You cannot see who sends as the domain Add rua=mailto:… none (Tamperbox recommendation); 4.7 makes rua optional
Reports go to X INFO The receiving domain must authorise the reports Publish the authorisation record there RFC 9990, 4
Strict alignment INFO Subdomain-signed or subdomain-bounced mail fails Relaxed is usually enough 3.2.10.2
N report addresses PASS Aggregate reports are on 4.6
  1. Make sure rua points at a mailbox or a reporting service you read. Raw aggregate reports are XML; a parsing service makes them readable.
  2. Read a few weeks of reports. List every source that sends as the domain: your mail host, newsletter tool, ticketing, invoicing, and anything you forgot.
  3. Make each one pass SPF or DKIM with a domain aligned with the From domain. Check their records with the SPF and DKIM checkers.
  4. Choose Test quarantine, review the draft p=quarantine; t=y, and publish it only after checking receiver compatibility. Current receivers treat this as monitoring. Remove test mode to request quarantine after reviewing legitimate mail.
  5. When the reports stay clean, move to Quarantine all, then Reject, the same way.

Publish the starting draft shown on the page, v=DMARC1; p=none; rua=mailto:dmarc@<domain>, at _dmarc.<domain> as a TXT record. Then follow the rollout above.

A provider migration usually leaves the old record beside the new one. Delete every record but one, then check the domain again.

A misspelt policy, a missing p, a bad percentage

Section titled “A misspelt policy, a missing p, a bad percentage”

Heal it offers the exact repair: the closest valid policy for a misspelling, p=none for a missing policy, removing obsolete pct. Each repair is a draft; copy and publish it.

Write each address as mailto:name@domain; separate several with commas. If the reports go to a domain other than yours (a reporting service), that domain must publish <yourdomain>._report._dmarc.<their-domain>; the service’s documentation says what to publish, and the INFO finding names the record.

Leave sp unset so subdomains follow p, or set it to the same policy. sp=none on an enforcing domain leaves every subdomain open to spoofing.

Each case is built from the record you entered or looked up.

Case What it does to your record Heal it offers
No policy Removes p= Add p=none
Policy typo Misspells the policy (rejected, quarantined, nnone) Change p=… to the valid value
Version not first Moves v=DMARC1 after the first tag Put corrected v=DMARC1 first
Bad report address Strips mailto: from rua Make rua a mailto: address
Invalid test mode Sets t=invalid Disable invalid test mode
Duplicate tag Adds a second, conflicting p= Keep p=none, Keep p=reject

The page opens on a live check of tamperbox.dev. Its published records and findings can change over time.

For the deterministic walkthrough below, enter harbor-supply.example. This reserved .example domain is answered from synthetic data in your browser; it sends no live lookup. Its record:

v=DMARC1; p=none; rua=mailto:dmarc@harbor-supply.example; ruf=mailto:forensics@harbor-supply.example; fo=1

Monitoring only: no DMARC enforcement requested. The findings are “p=none only monitors” (CHECK, with a button to the next step) and “1 report address” (PASS). Choose Test quarantine: the draft becomes v=DMARC1; p=quarantine; t=y; rua=…; ruf=…; fo=1, History logs the change with Revert, and the record to publish shows the draft at _dmarc.harbor-supply.example. Replace the sample with your own domain and every section, card and link is rewritten for it.

The Tamperbox MCP server runs the same checks. Search its catalog for the DMARC operation, inspect the input schema, and call it with the domain or the record. Keep the warning block with any conclusion:

  • The tool grades the policy text; whether legitimate mail passes is in the aggregate reports.
  • Parent policy is discovered through a bounded DNS tree walk; inherited np applicability is not verified because domain existence is not checked.
  • External report authorisation records are named, not looked up.
  • The pct tag is obsolete and does not reduce the effective policy. The t tag controls test mode.

See Connect an MCP client and Code mode for the calling pattern, and Security and privacy for where the domain travels.

  • The policy, not the reports: enforcement readiness is not assessed.
  • Parent policy is discovered through a bounded DNS tree walk; inherited np applicability is not verified because domain existence is not checked.
  • ruf, fo, rf and ri are explained, not validated.
  • The tag table recognizes t and psd; legacy rf and ri explanations remain and are not flagged as removed.
  • One DNS answer, from one public resolver, at one moment.
  • Nothing is stored; copying a draft does not publish it.
  • RFC 9989, Domain-Based Message Authentication, Reporting, and Conformance (DMARC), Proposed Standard, May 2026. Obsoletes RFC 7489 and RFC 9091. Sections used: 3.2.10 (alignment), 3.2.12 (Monitoring Mode), 3.2.13 (non-existent domains), 4.4 (identifier alignment), 4.5 (the record in DNS), 4.6 (reporting URIs), 4.7 (tags), 4.8 (formal definition), 4.10 and 4.10.1 (DNS tree walk and policy discovery), 5.1.5 and 5.1.7 (Domain Owner actions), 5.3.1 (A-labels), 7.4 (interoperability and p=reject), 9.5 (_dmarc registration), appendices A.6 (removal of pct) and C.5 (tag changes).
  • RFC 9990, DMARC Aggregate Reporting, Proposed Standard, May 2026. Obsoletes RFC 7489 in part. Sections used: 3.5 (report delivery) and 4 (verifying external destinations).
  • RFC 9991, DMARC Failure Reporting, Proposed Standard, May 2026. Obsoletes RFC 7489 in part and updates RFC 6591. Sections used: 2 (failure reports, ruf and fo) and 5 (verifying external destinations).
  • RFC 7489, DMARC, Informational, March 2015. Obsoleted by RFC 9989, RFC 9990 and RFC 9991. Cited only as the source of the pct, rf and ri tags the tool still knows.