Skip to content
HN On Hacker News ↗

DKIM2 and DMARCbis have landed, and Stalwart speaks them first

▲ 84 points 72 comments by StalwartLabs 3d ago HN discussion ↗

Pangram verdict · v3.3

We believe that this document is fully AI-generated

99 %

AI likelihood · overall

AI
0% human-written 100% AI-generated
SEGMENTS · HUMAN 0 of 5
SEGMENTS · AI 5 of 5
WORD COUNT 1,753
PEAK AI % 99% · §2
Analyzed
Jul 8
backend: pangram/v3.3
Segments scanned
5 windows
avg 351 words each
Distribution
0 / 100%
human / AI fraction
Verdict
AI
Pangram v3.3

Article text · 1,753 words · 5 segments analyzed

Human AI-generated
§1 AI · 99%

Jul 6, 2026 - 27 min read Email authentication has quietly held the internet’s mail together for two decades, and it has just taken its biggest step forward yet. Two efforts arrived at once. DKIM2 (currently at draft -04) reworks DKIM so that a signature is no longer a lonely statement about content but one link in a verifiable chain of custody that follows a message from author to final recipient: forwarding stops breaking signatures, replayed mail no longer verifies, and a bounce can prove it is genuine. DMARCbis (published in May 2026 as RFC 9989, RFC 9990, and RFC 9991) is the long-awaited successor to DMARC: it replaces the static Public Suffix List with a live DNS tree walk, retires the tags that never worked, and folds a decade of hard-won operational lessons back into the standard. Both matter because email authentication is what keeps a phisher from putting your bank’s domain in the From: line, and until now the machinery that does it has been showing its age. This post walks through what each protocol changes and why it matters. It is also an announcement. As of Stalwart v0.16.12, both DKIM2 and DMARCbis are fully implemented, and Stalwart is the first mail server to support them. Anyone curious can sign and verify DKIM2 messages, and run DMARCbis checks, directly from the browser at the mail-auth playground, no install required. More on that at the end; first, the protocols. DKIM (DomainKeys Identified Mail, RFC 6376) does one deceptively simple thing: it lets a domain take responsibility for a message. The sending server hashes a chosen set of header fields and the body, signs the result with a private key, and staples the outcome to the message in a DKIM-Signature header. The matching public key lives in DNS at selector._domainkey.domain, so any receiver can fetch it, recompute the hashes, and confirm two things: the message really was authorised by that domain, and nothing covered by the signature changed along the way. That is the whole promise. A valid signature means “this domain vouches for this content.”

§2 AI · 99%

It says nothing about who the message was for, where it has been, or where it is going next. For nearly twenty years that was enough, and DKIM quietly became one of the load-bearing walls of email authentication. On its own, a DKIM pass is just a true statement about some domain. DMARC is what turns it into a decision. DMARC ties authentication to the domain a human actually sees, the one in the From: header, through a rule called identifier alignment: a DKIM result only counts toward DMARC if the signing domain (d=) lines up with the From: domain. Pass alignment on either DKIM or SPF and the message clears DMARC; fail both and it meets the domain’s published policy, which can mean quarantine or outright rejection. This is exactly why a broken DKIM signature is not a cosmetic problem. When DKIM breaks on a message from a domain publishing p=reject, and SPF cannot save it either, that message is gone. Which brings us to the reason DKIM2 exists: over two decades of real-world routing, DKIM1 signatures break far more often than anyone would like, and in a few cases they hold when we wish they wouldn’t. Issues with DKIM1Section titled “Issues with DKIM1” None of what follows is a knock on the original design. These are the seams that two decades of deployment pulled apart, and they are the exact list DKIM2 sets out to close. Anyone could be the recipient. A DKIM1 signature is bound to the content, not to a destination. Capture one legitimately signed message and you can replay it to millions of other addresses, unchanged, and every copy still verifies. The replay rides on the original signer’s good reputation, which is precisely what makes it valuable to abusers. Forwarding breaks the signature, silently and ambiguously. The moment a mailing list tags a subject, a gateway rewrites a link, or a forwarder appends a footer, the signed hashes no longer match and the signature fails. Worse, a verifier cannot tell an innocent [list] prefix from wholesale replacement by an attacker. Both look identical: broken. There was no record of the road travelled. DKIM1 leaves no trustworthy trace of the path a message took. The Received and Return-Path headers are unauthenticated and trivial to forge, so there is no chain of custody to reason about.

§3 AI · 99%

ARC was a patch that receivers struggle to trust. ARC tried to preserve authentication across intermediaries by having each hop attest to what it saw, but it sits alongside DKIM as a separate overlay, and in practice most receivers report that they cannot confidently trust ARC seals. Header signing was inconsistent. DKIM1 lets the signer choose which headers to cover and offers multiple canonicalization modes, which leaves gaps an attacker can slip unsigned headers through and makes signatures needlessly fragile. Bounces could not be trusted, and hurt bystanders. Because the return path can name a domain that never handled the message, a Delivery Status Notification (DSN) can land on a forged, innocent third party. This is backscatter, and the fear of it is why deferred bounces, the kind a provider would send after deciding a message is spam an hour later, are largely impractical today. Feedback was ad hoc. Intermediaries and senders exchange informal signals about how mail is performing, but there is no standard for requesting or routing that feedback, so it is inconsistent and often unhelpful. DKIM2, in a nutshellSection titled “DKIM2, in a nutshell” DKIM2 keeps everything that worked and changes the thing that did not. The cryptography is familiar: hash the message, sign it, publish the public key in DNS at the same _domainkey location DKIM1 already uses. What changes is that a signature stops being a lonely statement about content and becomes one link in a verifiable chain of custody that follows the message from originator to final recipient. To do that, DKIM2 splits the old single header into two, each with its own job. The Message-Instance header describes the message at a point in time. It carries a revision number, a set of cryptographic fingerprints over the headers and body at that revision, and, when a hop has changed something, a compact “recipe” that spells out how to undo the change (the mechanism covered later that makes forwarding survivable). The DKIM2-Signature header records the envelope the message actually travelled with, then signs over it.

§4 AI · 99%

Alongside the familiar DKIM pieces, the signing domain, the selector, the signature itself and a timestamp, it captures the SMTP MAIL FROM and RCPT TO of that hop, a sequence number so the signatures form an ordered chain, and a small set of flags that a sender or intermediary can raise to forbid fan-out, mark legitimate fan-out, or request feedback. Putting the envelope inside the signature is what lets consecutive hops be checked for consistency; recording who signed and in what order is what turns a pile of signatures into a chain. Two counters drive everything. One counts signatures, one per hop. The other counts message revisions, incremented only when a hop actually changes the content. A purely transparent forwarder that touches nothing does not even need to be DKIM2-aware. One mechanism per broken promiseSection titled “One mechanism per broken promise” The elegance of DKIM2 is that a handful of mechanisms retire the whole list above at once. Replay is answered by putting the envelope inside the signature. Each DKIM2-Signature records the MAIL FROM (mf=) and RCPT TO (rt=) it was sent with, and consecutive hops must line up: the sending domain of one hop has to match a recipient domain of the previous one. A message replayed to a different recipient no longer forms a valid chain. A sender can add donotexplode to forbid fan-out, and a mailing list marks legitimate fan-out with exploded. Forwarding breakage is answered by recipes. A hop that modifies the message records a reversible recipe, so downstream verifiers can undo the change and re-check every earlier signature instead of throwing the whole thing out. The missing chain of custody is the chain itself: each hop appends its own signature over the current snapshot and all prior signatures, forming a tamper-evident sequence from author to recipient. ARC’s role is absorbed natively. The chain does what ARC attempted, without a parallel set of headers, and DKIM2 explicitly ignores both legacy DKIM-Signature and ARC-* headers so the two schemes can coexist during migration. Inconsistent header signing is answered by a single fixed canonicalization and a defined hashing scheme, removing the per-signer guesswork. Backscatter is answered by routing bounces along the recorded chain, covered next. Feedback gets a standard channel through the feedback and feedhere flags.

§5 AI · 99%

One caveat, contrary to a common claim: DKIM2 can require more signature checks, not fewer. A modified message adds a signature at every hop, and a verifier may need to check the whole chain. What the draft does allow is checking the most recently applied signature first and stopping at the first failure, so an unmodified message can often be cleared with a single verification. Recipes: putting a message back the way it wasSection titled “Recipes: putting a message back the way it was” This is the mechanism that makes forwarding survivable, so it is worth seeing in full. A recipe is a small JSON object, base64-encoded into the r= tag, that tells a verifier how to turn the current message back into the previous one. It has two optional parts, "h" for header fields and "b" for the body, and each is a list of steps: {"c": [start, end]} copies a range of lines or header instances from the current message, inclusive. {"d": ["value", ...]} inserts literal values that used to be there. Two numbering rules matter. Header instances are counted bottom-up (the last Subject: is number 1, the one above it is 2), and body lines are counted top-down (the first line is 1). An empty step list [] for a header means “remove every instance.” A body recipe of null is a special case: it means the previous body genuinely cannot be reconstructed, which a verifier may accept from an entity it trusts, for example a contractually arranged redaction service. A message through two hopsSection titled “A message through two hops” Alice sends a note to a mailing list. Hop 1, the originator signs. The message leaves example.com: She stamps it with the first revision and the first signature (hashes abbreviated): Message-Instance: m=1; h=sha256:Hh1...:Bh1...DKIM2-Signature: i=1; m=1; t=1782394336;