Canny Pigeons

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

RFCTitleReplaces
RFC 9989DMARC — the protocol, the record format and policy discoveryRFC 7489 and RFC 9091 (the experimental PSD DMARC)
RFC 9990DMARC Aggregate Reporting — the XML you receive at rua=The reporting sections of RFC 7489
RFC 9991DMARC Failure Reporting — the per-message ruf= reportsThe 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.com

Three rules keep it bounded and predictable:

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

Three tags removed

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 publishReceivers apply
p=reject; t=yquarantine
p=quarantine; t=ynone
p=none; t=ynone — 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:

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 senderGet that sender DKIM-signing. The RFC makes this a MUST for enforced domains.
is on a domain whose users post to mailing listsHold 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 elseNothing. 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.com

Paste 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

Walk to p=reject on the data, not a percentage

Point rua= at Canny Pigeons and every sender, pass rate and alignment result is on one screen — the evidence RFC 9989 tells you to gather before enforcing. Free for one domain, forever.

Start free