Resources / Authentication
DMARC in 2026 (RFC 9989, 9990, 9991)
The RFC most "DMARC explained" articles still cite is obsolete. In May 2026 DMARC was re-issued as three Standards-Track RFCs. Here is everything that changed - tags, the Tree Walk, reporting, and the new p=reject guidance - in plain language, with records you can copy.
Last checked: June 21, 2026
If you read a “how DMARC works” article today, it almost certainly cites RFC 7489. That document is now obsolete. As of May 2026, DMARC is defined by three Standards-Track RFCs that jointly replace it: RFC 9989 (core protocol), RFC 9990 (aggregate reporting), and RFC 9991 (failure reporting). Together they also absorb RFC 9091 (the experimental PSD-DMARC extension).
The work was known for years as “DMARCbis.” It is not “DMARC2”: the DNS record version is still v=DMARC1, and your existing records keep working. What changed is the spec’s status (DMARC is now a Proposed Standard, not merely Informational) and a set of concrete, operationally meaningful refinements.
The 60-second version
- The version tag is unchanged:
v=DMARC1. No record is broken by this. - Three tags are removed:
pct,rf,ri. - Three tags are added:
np(non-existent-subdomain policy),psd(public-suffix marker),t(testing mode). - The Public Suffix List is gone, replaced by a DNS-based “Tree Walk” (max 8 lookups) for finding the Organizational Domain.
- Receivers should not reject a message on
p=rejectalone, and the spec discouragesp=rejectfor domains whose users post to mailing lists. - Reporting moved into its own two RFCs, with a new XML namespace and a required DKIM selector in reports.
The rest of this page is the detail, with records you can copy.
What DMARC still does (unchanged)
DMARC lets the owner of the visible From: domain (the Author Domain) publish a DNS policy telling receivers what to do when mail claiming that domain fails authentication, and where to send reports.
A message passes DMARC when either SPF or DKIM passes and that passing identifier is aligned with the From: domain. Not both - either. This is the single most misunderstood point and it did not change.
Alignment is unchanged too:
- Relaxed (
adkim=r/aspf=r, the defaults): the identifier shares the same Organizational Domain.mg.example.comaligns withexample.com. - Strict (
adkim=s/aspf=s): the identifier domain is identical to theFrom:domain.
A DMARC pass only proves the domain was used with authorization. RFC 9989 is explicit that it asserts nothing about whether the message is wanted - reputation, content, and engagement still decide inbox placement.
Why it needed an update
RFC 7489 worked, but a decade of deployment exposed real problems, and DMARCbis targets each one:
- The Public Suffix List was a single, externally-maintained file (by Mozilla), updated out of band. A missing or stale entry produced wrong Organizational Domains.
- The
pcttag was effectively useless: in practice only0and100were used, and intermediate values behaved differently across receivers. - Non-existent subdomains had no policy: an attacker could send from
fake.example.comand, if no_dmarcrecord existed there, no DMARC policy applied. - PSD-DMARC (RFC 9091) for registry-level domains (
.bank,.gov,co.uk) was only experimental.
Tag changes, with the full comparison
| Tag | RFC 7489 | DMARCbis (RFC 9989) | Status |
|---|---|---|---|
v | DMARC1 | DMARC1 | Unchanged |
p | none / quarantine / reject | identical | Unchanged |
sp | subdomain policy | identical | Unchanged |
adkim / aspf | r / s | identical (strict encouraged where you control signing) | Unchanged |
fo | 0 / 1 / d / s | identical | Unchanged |
rua | URIs (with size-limit syntax) | URIs, size-limit syntax dropped, stricter external auth | Modified |
ruf | URIs | defined in RFC 9991, stricter external auth | Modified |
pct | 0-100 | - | Removed |
ri | report interval (seconds) | - | Removed |
rf | report format | - | Removed |
np | - | none / quarantine / reject | New |
psd | - | y / n / u | New |
t | - | y / n | New |
Removed: pct, rf, ri
pct- removed because it was inconsistently implemented; only0and100were reliable. Graduated rollout now usest(below).ri- the aggregate-report interval had de facto standardized at 24 hours; receivers ignored other values.rf- only one report format (afrf) was ever deployed.
They still parse harmlessly if left in place (receivers ignore unknown tags), but you should remove them.
New: np - non-existent subdomain policy
np sets a policy for subdomains that do not exist in DNS - closing the spoofing gap above. Values match p. The fallback order is np (if the subdomain is NXDOMAIN) → sp → p.
_dmarc.example.com. 3600 IN TXT "v=DMARC1; p=quarantine; np=reject; rua=mailto:dmarc@example.com"
Here, existing subdomains inherit p=quarantine, while mail from any non-existent subdomain is rejected.
New: psd - public-suffix marker
psd declares whether the publishing domain is a Public Suffix Domain. y = it is a PSD (the Organizational Domain is one label below); n = a normal Organizational Domain; u = undetermined (default; the Tree Walk continues upward). Ordinary senders leave psd absent or set psd=n - it is for TLD/registry operators.
New: t - testing mode (the pct replacement)
t is binary: t=y downgrades the published policy by one level at compliant receivers (reject → quarantine, quarantine → none); t=n (default) applies it normally. Reports are still sent, so you can watch results before enforcing.
_dmarc.example.com. 3600 IN TXT "v=DMARC1; p=reject; t=y; rua=mailto:dmarc@example.com"
Important transition gotcha: DMARC-v1 receivers (still the majority in 2026) ignore the unknown t tag and apply p=reject directly. t=y is not a universal “safe test” switch - it only downgrades at receivers that already implement DMARCbis. Do not pair it with pct=0; remove pct first.
The Public Suffix List is gone: the DNS Tree Walk
Determining the Organizational Domain no longer consults the PSL. Instead the receiver walks up the DNS tree, querying _dmarc.<domain> and removing the leftmost label until it finds a record (using the psd tag to know when it has reached the boundary), capped at 8 queries.
# newsletter.example.com
Query 1: _dmarc.newsletter.example.com -> no record
Query 2: _dmarc.example.com -> "v=DMARC1; p=reject; psd=n" (Organizational Domain = example.com)
# contact.bank.co.uk (co.uk is a public suffix)
Query 1: _dmarc.contact.bank.co.uk -> no record
Query 2: _dmarc.bank.co.uk -> no record
Query 3: _dmarc.co.uk -> "v=DMARC1; p=reject; psd=y" (Org Domain = bank.co.uk, one label below the PSD)
| Aspect | PSL (RFC 7489) | DNS Tree Walk (DMARCbis) |
|---|---|---|
| Source of truth | A static list maintained by Mozilla | The DNS itself |
| Freshness | Periodic download | Real-time DNS queries |
| Coverage | Manual, can be incomplete | Any domain publishing _dmarc |
| Standardization | Community project | IETF Standards Track |
In practice the Tree Walk adds at most one or two DNS lookups for a typical domain, and caching (including cached NXDOMAIN) absorbs most of it. Publish _dmarc with a TTL of at least 3600s; those records are the Tree Walk’s anchor points.
”p=reject” is no longer a blanket reject
The change most likely to surprise an operator: RFC 9989 makes it normative that a receiver should not reject a message solely because the policy is p=reject. DMARC is one signal among several. In the absence of other knowledge, failing mail under p=reject is to be treated more like quarantine than refused outright. The spec further advises that domains whose users post to mailing lists should not publish p=reject at all, because list software routinely breaks alignment.
This is not a weakening of DMARC. It is the standard catching up to a real failure mode (legitimate forwarded and list mail getting destroyed by a policy it never anticipated). The corollary is important and is exactly where infrastructure choice matters: p=reject is appropriate for domains where every step of the send is controlled end to end, and risky for general-purpose domains that you do not fully control.
Reporting changes (RFC 9990 and 9991)
Aggregate reports (RFC 9990) remain XML, sent at least every 24 hours, and are still the single most useful DMARC signal. What changed:
- New XML namespace:
urn:ietf:params:xml:ns:dmarc-2.0. - A DKIM selector is now required in the report, so you can tell which key produced which result.
- New fields reflect DMARCbis (testing mode,
np, how the policy was discovered) and apassdisposition; thepct-erasampled_outoverride is gone. - Each
ruaURI receives its own report. External destinations (a report address in a different domain) must be authorized with a_report._dmarcrecord, or the URI is ignored.
Failure reports (RFC 9991) are the per-message reports. They got their own document, clearer privacy language, and mandatory rate-limiting. Most large providers (Google, Yahoo, Microsoft) send few or none for privacy reasons - treat aggregate reports as your foundation and failure reports as an occasional supplement.
What did NOT change (and common confusion)
- The evaluation model: still “aligned SPF or aligned DKIM,” never “SPF and DKIM and DMARC all passing independently.”
- Your records:
v=DMARC1is unchanged; nothing needs to be rebuilt by a deadline. - DMARC still does not guarantee inbox placement - it proves authorized domain use, nothing more.
- DKIM2 is a separate effort. You will hear about it, but the DMARC refresh does not require it; today’s DMARC still relies on SPF and DKIM exactly as before.
A practical migration path
# Before (RFC 7489 era)
_dmarc.example.com. 3600 IN TXT "v=DMARC1; p=quarantine; pct=100; ri=86400; rf=afrf; rua=mailto:dmarc@example.com; fo=1"
# 1. Remove the dead tags (pct, ri, rf)
_dmarc.example.com. 3600 IN TXT "v=DMARC1; p=quarantine; rua=mailto:dmarc@example.com; fo=1"
# 2. Close the non-existent-subdomain hole
_dmarc.example.com. 3600 IN TXT "v=DMARC1; p=quarantine; np=reject; rua=mailto:dmarc@example.com; fo=1"
# 3. Escalate to reject, testing first at DMARCbis receivers
_dmarc.example.com. 3600 IN TXT "v=DMARC1; p=reject; t=y; np=reject; rua=mailto:dmarc@example.com; fo=1"
# 4. Enforce (after clean reports), tighten DKIM alignment where you control signing
_dmarc.example.com. 3600 IN TXT "v=DMARC1; p=reject; np=reject; adkim=s; aspf=r; rua=mailto:dmarc@example.com; fo=1"
If your rua/ruf points at a third-party monitoring domain, remember the external-authorization record on that domain, and update it whenever you change providers (a silent way reports stop arriving).
What this means for you, and what Egressif does
If your DMARC knowledge predates 2026: the pct rollout trick is gone (use t), the PSL is no longer how the Organizational Domain is found, rf/ri are removed, and p=reject is explicitly not a blanket reject instruction. Add np=reject to shut the subdomain hole. None of this breaks existing records.
Egressif runs p=reject on the domains it operates. That is responsible only because we control the whole path: SPF and DKIM are published and aligned on your domain, every sending source is accounted for, and there are no unmanaged intermediaries quietly breaking alignment. That is precisely the case the standard reserves p=reject for - a domain controlled end to end - rather than a general-purpose mailbox whose users post to mailing lists. We keep the records complete and current as sources change, use np to block non-existent subdomains, and watch the aggregate reports so a new source that fails alignment surfaces as a signal we act on, not a silent placement drop weeks later.
Related references
- Email Authentication: SPF, DKIM, DMARC, ARC, BIMI SPF, DKIM, and DMARC are not interchangeable, and none of them on their own tells a receiver a message is safe. This is the map: what each layer checks, what a pass actually proves, and how alignment, ARC, and BIMI sit on top.
- SPF Deep Dive (RFC 7208) SPF authorizes which hosts may use your domain in the SMTP envelope. This is the full RFC 7208 picture: record format, every mechanism and qualifier, the hard 10-lookup limit that breaks records, the result codes, and the mistakes that quietly cause permerror.
- DKIM Deep Dive (RFC 6376) DKIM signs a message so a domain can take cryptographic responsibility for it. This is the full RFC 6376 picture: selectors, the signature and key tags, simple vs relaxed canonicalization, the l= body-length trap, key rotation, and the crypto updates from RFC 8301 and RFC 8463.
- ARC: Authenticated Received Chain (RFC 8617) ARC preserves a message's authentication result across the intermediaries that break SPF and DKIM. This is the RFC 8617 picture: the three header fields, how a chain is built and validated, the chain-validation states, and the honest limits - ARC is advisory, not a pass.
- BIMI: Logos, DMARC, and Mark Certificates BIMI puts a brand logo next to authenticated mail, but it authenticates nothing itself - it rides on enforced DMARC. This covers the prerequisites, the SVG Tiny PS logo, VMC and CMC mark certificates, the DNS record, and the honest provider-support reality.
Tell us what you run today.
Domains, rough volume, current providers, and what hurts. You will get a straight answer on fit, and a real number, in one conversation.