Learn · Email authentication
DMARCbis: what the new DMARC standard changes
For eleven years DMARC ran on RFC 7489, a document that was never an Internet standard — it was published in 2015 as an Informational RFC outside any IETF working group. In May 2026 the IETF replaced it with three Standards Track documents, the result of the project known as DMARCbis. This guide covers what actually changed, what it means for a record you already publish, and the one piece of advice in the new text that surprised people. Everything below is checked against the RFC text itself.
The three documents
| RFC | Title | Replaces |
|---|---|---|
| RFC 9989 | DMARC — the protocol, the record format and policy discovery | RFC 7489 and RFC 9091 (the experimental PSD DMARC) |
| RFC 9990 | DMARC Aggregate Reporting — the XML you receive at rua= | The reporting sections of RFC 7489 |
| RFC 9991 | DMARC Failure Reporting — the per-message ruf= reports | The failure reporting sections of RFC 7489; updates RFC 6591 |
Splitting reporting out is more than housekeeping. Aggregate reports get their own versioned XML schema now (the namespace is urn:ietf:params:xml:ns:dmarc-2.0), which means the format can evolve without reopening the protocol document. If you read your own reports, or run a tool that does, this is the document to watch.
Policy discovery: the tree walk replaces the Public Suffix List
This is the largest technical change, and the one you will never see unless something goes wrong. DMARC has to answer two questions for every message: which record applies to the From domain, and what the organizational domain is, since relaxed alignment lets news.example.com align with example.com. RFC 7489 answered the second with the Public Suffix List — a text file maintained by volunteers, outside DNS, that receivers had to download and keep current.
RFC 9989 replaces it with the DNS tree walk. The receiver queries _dmarc at the From domain, then at each parent in turn, walking towards the root:
_dmarc.a.mail.example.com
_dmarc.mail.example.com
_dmarc.example.com
_dmarc.comThree rules keep it bounded and predictable:
- At most eight queries. A From domain with more than eight labels is shortened to seven before the walk starts, so no message can trigger an unbounded string of lookups.
- The walk stops at a
psdtag. A record that sayspsd=ndeclares "this is the organizational domain". A record that sayspsd=ydeclares "this is a public suffix", and the organizational domain is the name one label below it. - Otherwise, the shortest name wins. If no record carried a
psdtag, the organizational domain is the one with the fewest labels that published a valid record.
For the vast majority of domains the answer is identical to what the Public Suffix List gave. The RFC itself notes where the two can disagree — a receiver still running RFC 7489 logic could pick a different organizational domain than one running the tree walk — and states the way to avoid the problem entirely: publish an explicit DMARC record for every domain you send from, and use strict alignment where you can. If you already do the first, you have nothing to do here.
What changed in the record
The syntax is untouched. v=DMARC1; p=reject; rua=mailto:… is exactly as valid today as it was last year, and every tag in the DMARC record guide still means what it did. What moved is the edges of the tag list.
Three tags added
np=— the policy for subdomains that do not exist. Most subdomain spoofing uses names you never created (invoices.example.com,hr.example.com), and an attacker gets thesp=orp=fallback whether the name exists or not.np=rejectcloses that gap and costs you nothing, because nothing legitimate can send from a name that has no DNS. It was imported from the experimental RFC 9091; the policy guide covers how it sits alongsidesp=.psd=— the tree-walk marker described above. Registry operators publishpsd=y. You would publishpsd=nonly if your organizational domain sits somewhere the walk would otherwise get wrong, which for a normal company domain it will not. Leave it out.t=— test mode, the replacement for part of whatpct=did. Explained in the next section.
Three tags removed
pct=— the percentage of failing mail to enforce against. Gone; see below.rf=— the requested format for failure reports. There was only ever one format in practice.ri=— the requested interval between aggregate reports. Receivers sent daily regardless, and RFC 9990 no longer defines it.
Also removed: the size limit you could append to a report address, as in rua=mailto:reports@example.com!10m. Plain mailto: URIs only.
None of this breaks an existing record. RFC 9989 is explicit that unknown tags MUST be ignored, so a record that still says pct=100; ri=86400 is parsed as if those tags were not there. There is no deadline and no migration. The only thing an old tag does now is take up space.
Why pct is gone, and what t does instead
pct= was meant to let you ramp enforcement gradually: p=reject; pct=25 asked receivers to reject a quarter of failing mail and quarantine the rest. The RFC's own account of its removal is blunt. Receivers applied it accurately only at 0 and 100, the two values that needed no special code, and behaviour for anything in between varied from one implementation to the next. Meanwhile pct=0 had picked up an unofficial second life: some intermediaries and mailbox providers read it as "rewrite the From header on this mail so it survives forwarding", which turned out to be genuinely useful for spotting how much of your traffic flows through mailing lists and forwarders.
The t= tag keeps that useful part and drops the pretence of a percentage. t=y asks receivers to apply the policy one level below the one you published, and to apply whatever special handling they have (such as From rewriting) instead:
| You publish | Receivers apply |
|---|---|
p=reject; t=y | quarantine |
p=quarantine; t=y | none |
p=none; t=y | none — t has no effect on a policy of none |
Reports are unaffected: you still receive aggregate data as if the published policy were live, which is the point. Publish p=reject; t=y, watch what would have been rejected, then delete the tag. Aggregate reports under RFC 9990 carry a testing element so a report consumer can tell the two states apart.
If you still have pct= in your record, remove it. It has done nothing at most large receivers for some time, and a rollout plan built on it is a plan that never executed. Stage enforcement by moving p= itself, which is what the policy playbook has always recommended.
The advice on p=reject that people did not expect
RFC 7489 said little about when a domain owner should enforce. RFC 9989 says a great deal, and one passage has been quoted out of context more than any other, so here it is in context.
The interoperability section restates the well-known problem: mailing lists and forwarders rewrite or relay messages in ways that break SPF, and often DKIM, so mail from a p=reject domain posted to a list gets rejected at the far end. Worse, list software treats those rejections as dead addresses and unsubscribes the innocent recipients. The RFC draws three conclusions, each with a normative keyword:
- Domains that host users who post to mailing lists SHOULD NOT publish
p=reject, and the change summary generalises it to "domains for general-purpose email". The prescribed route for such a domain isp=nonefor at least a month, thenp=quarantinefor an equally long period, then a comparison of the disposition data before deciding. - Domains that publish
p=rejectMUST NOT rely on SPF alone and MUST DKIM-sign their mail, because a DKIM signature usually survives relaying and SPF never does. If your enforced domain has a sender that passes only on SPF, that sender is one forwarder away from a rejection. - Receivers MUST NOT reject solely because of
p=reject, and in the absence of any other analysis must treat failing mail as if the policy were quarantine. In other words, the standard now formally describes what the big mailbox providers were already doing.
Read carefully, this is not a retreat from enforcement. It is a statement about which domains carry human correspondence. A company domain where staff post to technical lists is the case the text is written for. A domain that sends invoices, notifications and campaigns from services you control is not, and p=reject remains the destination — reached by the same evidence-first walk the RFC describes, which is exactly what your aggregate reports are for. The pragmatic reading for a business with both kinds of mail is the one the RFC's own alignment text points at: put the humans and the machines on different domains or subdomains and enforce where you can.
What to do with your record today
| If your record… | Do this |
|---|---|
contains pct= | Delete it. If you were mid-rollout, replace it with t=y on the next policy level up. |
contains ri= or rf= | Delete them when you next touch the record. Harmless until then. |
has no np= | Add np=reject. Nothing legitimate sends from a subdomain that does not exist. |
uses a !10m size suffix on rua= | Remove the suffix. |
is at p=reject with an SPF-only sender | Get that sender DKIM-signing. The RFC makes this a MUST for enforced domains. |
| is on a domain whose users post to mailing lists | Hold at p=quarantine, or move human mail to its own subdomain, and let the reports decide. |
is v=DMARC1; p=reject; rua=mailto:… and nothing else | Nothing. It is a fully valid RFC 9989 record. |
A record with all of the above applied looks like this:
v=DMARC1; p=reject; np=reject; rua=mailto:reports@example.comPaste your domain into the free DMARC checker to see which tags you currently publish and which of the rows above apply.
What did not change
Almost everything you would notice day to day. Alignment works as before, relaxed by default. p=, sp=, rua=, ruf=, adkim=, aspf= and fo= keep their meanings. The aggregate report is still a compressed XML file, once a day, listing every source IP that used your domain with its SPF, DKIM and alignment results. Receivers were already ignoring pct and ri, already refusing to reject on DMARC alone, and already computing organizational domains in ways that agreed with the tree walk for ordinary domains. DMARCbis wrote down how DMARC actually works in 2026, promoted it to a real standard, and cleaned up the tags that never did what they said.
Free checks: DMARC checker SPF checker DKIM checker Report analyzer