DMARC RFC 9989: what changed and what to do
What RFC 9989 changed in DMARC compared with RFC 7489: the DNS tree walk, new np, psd and t tags, removed pct, rf and ri, and what your record needs now.
By Exmoor Software8 min read
In May 2026 the IETF published DMARC as a Standards Track protocol in RFC 9989. It obsoletes RFC 7489, the 2015 specification most DMARC deployments were built on, and RFC 9091, an experiment for public suffix domains. Reporting moved into two companion documents: RFC 9990 (aggregate reports) and RFC 9991 (failure reports).
The short answer: your existing v=DMARC1 record keeps working. The version tag did not change, and receivers following either specification ignore tags they don’t know. Look closer if you use pct or publish DMARC only on subdomains.
The changes at a glance
| Area | RFC 7489 (2015) | RFC 9989 (2026) |
|---|---|---|
| Status | Informational, independent submission | IETF Standards Track |
| Documents | one | three: RFC 9989, 9990, 9991 |
| Organizational domain | Public Suffix List | DNS Tree Walk |
| New tags | — | np, psd, t |
| Removed tags | — | pct, rf, ri |
Size limit after a report URI (!10m) | allowed | obsolete, ignored |
| Version tag | v=DMARC1 | v=DMARC1 |
RFC 7489 was not the product of IETF work: the Independent Submissions Editor published it as an Informational RFC (Appendix C.1), based on the work of DMARC.org, an industry consortium whose members included large mailbox providers. RFC 9989 is an IETF Standards Track document, developed in the IETF DMARC working group. It is also far more detailed about what domain owners should do (Section 5.1): aligned SPF and DKIM, a mailbox for reports, p=none first, then a decision about enforcement.
The DNS Tree Walk replaces the Public Suffix List
DMARC needs an organizational domain for two jobs: finding a policy when the From domain has no record of its own, and deciding whether two domains align in relaxed mode. RFC 7489 took it from a Public Suffix List — a list of suffixes such as com or co.uk — without saying which list or how often to refresh it.
RFC 9989 uses DNS queries instead (Section 4.10). For mail from news.mail.example.com with no record of its own, the receiver walks up the tree:
_dmarc.news.mail.example.com ; the From domain itself
_dmarc.mail.example.com
_dmarc.example.com
_dmarc.com
Long names are shortened first, so a walk never takes more than eight queries.
- Policy: the From domain’s own record wins (policy from
p). Otherwise the record of its organizational domain applies — or, failing that, that of a public suffix domain:spfor subdomains that exist,npfor subdomains that don’t,pwhen those tags are missing (Section 4.10.1). - Alignment: the organizational domain is the domain with the fewest labels on the path that publishes a DMARC record, unless a
psdtag says otherwise (Section 4.10.2). With a record at_dmarc.example.com, bothmail.example.comandbounce.example.combelong toexample.com— the same answer the Public Suffix List gave.
For ordinary setups — one record at example.com, perhaps with overrides on some subdomains — both methods agree. The RFC notes that strict alignment and explicit records for every From domain avoid any difference between old and new receivers (Appendix C.3).
New tags: np, psd and t
np — non-existent subdomains
np sets the policy for subdomains that don’t exist in DNS (the query returns NXDOMAIN), such as a made-up billing-team.example.com in a phishing message. A name with any DNS record counts as existing (Appendix A.4). Without np, sp applies, then p.
_dmarc.example.com. 3600 IN TXT "v=DMARC1; p=quarantine; np=reject; rua=mailto:dmarc-reports@example.com"
Receivers still implementing RFC 7489 ignore np and fall back to sp or p.
psd — public suffix domains
psd=y is for operators of public suffixes, such as a top-level domain registry; RFC 9989 requires them to include it (Section 5.2). psd=n declares a domain to be an organizational domain of its own, for example a department that manages its own part of the namespace (Section 5.1.8). The default u means “use the tree walk”. If you own an ordinary domain, leave psd out.
t — testing mode
t=y asks receivers to apply one level less than the stated policy: quarantine is treated as none, reject as quarantine. Whoever checks DMARC — a receiver or an intermediary such as a mailing list — may also apply its own special handling, such as rewriting the From header. Reporting is unaffected, and t has no effect on p=none. Remove it, or set the default t=n, when you are ready to enforce.
Removed tags: pct, rf and ri
IANA now lists these tags as historic (Section 9.3). RFC 9989 no longer defines them, so receivers following it don’t act on them; receivers still implementing RFC 7489 do.
| Tag | What it did | What to do now |
|---|---|---|
pct | Applied the policy to a percentage of failing mail | pct=0: use t=y. pct=100: delete. In between: see below |
rf | Chose the failure report format | Delete; RFC 9991 defines the format |
ri | Requested a report interval | Delete; receivers should report at least daily (Section 8) |
Why pct went away
According to Appendix A.6, pct was rarely applied accurately unless it was 0 or 100, and implementations differed widely. pct=0, however, had become useful: some intermediaries and mailbox providers took it as a signal to rewrite the From header, which helped domain owners prepare for enforcement. t=y keeps that function under a clearer name and is meant to work like pct=0, while t=n corresponds to pct=100.
The effect matches: under RFC 7489, failing mail not selected by pct for reject was quarantined, and mail not selected for quarantine got normal handling — one level down, as with t=y.
If you use a value between 1 and 99
This is where the change can bite. With p=reject; pct=25, an RFC 7489 receiver rejects about a quarter of failing mail and quarantines the rest. An RFC 9989 receiver ignores pct and rejects all of it. Decide what you want:
- Your reports are clean: remove
pctand enforce fully. - You are not ready: add
t=y, so updated receivers quarantine instead of rejecting while older ones keep followingpct. Or step back top=quarantinewithoutpct.
During the transition you can keep pct=0 and t=y side by side: both kinds of receivers then apply one level less than p.
Reports moved to RFC 9990 and RFC 9991
The rua and ruf tags work as before; the reports are now specified separately:
- Aggregate reports (RFC 9990) keep the XML format, with a clarified schema, one policy domain per report and the DKIM selector required for every reported signature (RFC 9990, Appendix C).
- Failure reports (RFC 9991) may include headers or the whole failed message. RFC 9989 notes that most receivers refuse to send them for privacy reasons (Section 10.2).
- External report addresses still need authorization: a TXT record
v=DMARC1atexample.com._report._dmarc.followed by the report domain (RFC 9990, Section 4).
A size limit after a report URI, as in mailto:reports@example.com!10m, is obsolete and should be ignored. And instead of requiring support for at least two report addresses, RFC 9989 says a report should go to each address listed (Appendix C.7).
Stronger words about p=reject
Section 7.4, building on RFC 7960, spells out what p=reject does to forwarded mail, aliases and mailing lists:
- Domains with
p=rejectmust not rely on SPF alone and must sign with DKIM: forwarding breaks SPF, while DKIM usually survives. - Domains whose users may post to mailing lists should not publish
p=reject. If they do, they should first runp=nonefor at least a month, thenp=quarantinefor as long, and compare the results. - Receivers must not reject mail solely because of
p=reject; without other evidence they must treat failing mail as if the policy werequarantine.
The RFC admits that many receivers reject such mail anyway, and that mailing-list software works around it by rewriting the From address. For a domain sending only transactional and marketing mail, p=reject remains a sensible goal; where staff use mailing lists, weigh the trade-off.
Does my record need to change?
| Your record | Change needed? |
|---|---|
v=DMARC1; p=…; rua=… without pct, rf or ri | No |
Contains pct=100, rf=afrf or ri=86400 | No, but you can delete them |
Contains pct=0 | Add t=y |
Contains pct between 1 and 99 | Yes: remove it or add t=y |
| DMARC records only on subdomains | Add a record at the registered domain |
| From domains with more than eight labels | Publish records at those exact names (Section 5.1.8) |
Migration checklist
- Run the DMARC checker on your domain and every subdomain you send from. It follows the RFC 9989 tree walk and flags removed tags.
- Make sure the registered domain, such as
example.com, has a DMARC record. - Replace
pct=0witht=y(keeping both for a while is fine) and resolve anypctbetween 1 and 99. - Delete
rf,riand size suffixes such as!10m. - Consider
np=reject: non-existent subdomains send no legitimate mail. - Before
p=reject, confirm that every legitimate source passes DKIM with ad=domain aligned to the From address — with the DKIM checker and a real message in the email header analyzer. - Leave
psdout unless you run a public suffix or a delegated part of the namespace. - Keep reading aggregate reports. Receivers move to RFC 9989 at their own pace, and where the specifications differ, the reports show what each one did.
For the full rollout from p=none to p=reject, see How to configure DMARC correctly.
References
- RFC 9989 — Domain-Based Message Authentication, Reporting, and Conformance (DMARC)
- RFC 9990 — DMARC Aggregate Reporting
- RFC 9991 — DMARC Failure Reporting
- RFC 7489 — the original DMARC specification (obsoleted by RFC 9989)
- RFC 9091 — Experimental DMARC extension for Public Suffix Domains (obsoleted by RFC 9989)
- RFC 7960 — Interoperability issues between DMARC and indirect email flows