DKIM2
Learn what DKIM2 adds to DKIM: a signature chain that records each hop, the SMTP envelope, and header or body changes, plus the domain policy TXT record at _domainkey. The public key still lives at selector._domainkey.
TL;DR DKIM2 (DomainKeys Identified Mail v2) is an IETF draft for signing email. Each hop that handles a message can add a signature that covers the current headers and body, the SMTP envelope, and a description of any changes that hop made. Receivers check the signatures with a public key in DNS.
The public key is a TXT record at the same name DKIM already uses, {selector}._domainkey.{domain}. DKIM2 also defines a domain policy TXT record at _domainkey.{domain}.
DKIM2 is an Internet-Draft. This page follows draft-ietf-dkim-dkim2-spec-09 (1 November 2026) and draft-ietf-dkim-dkim2-dns-03 (2 November 2026). Both can be replaced. Keep publishing SPF, DKIM, and DMARC.
Message-Instance header with m=1, and adds a DKIM2-Signature header with i=1.MAIL FROM and RCPT TO used on the way out.Message-Instance with the next m= number. A recipe in that header describes how to rebuild the previous version, so the earlier hash can still be checked.DKIM2-Signature (i=2, then i=3, and so on) and records the envelope it will use.From domain has to match a signing domain.The spec calls a message that passes the latest hash and signature check provisionally verified. A fully verified message also has a continuous chain, a matching envelope, and an Authentic From.
The protocol lets a forwarder skip a new signature when it changes nothing and the envelope it sends still matches the signature already on the message. The best-practices draft tells a participant to sign anyway when the message leaves their network, including when they did not edit it. Sign at that exit hop, once.
DKIM2 uses two TXT names.
Public key. Same name as DKIM:
{selector}._domainkey.{domain}google._domainkey.example.com. TXT "v=DKIM1; k=rsa; p=MIGfMA0GCSq..."Domain policy. The _domainkey name itself, with no selector:
_domainkey.{domain}_domainkey.example.com. TXT "v=DKIM1; f=strict"Periods in a selector are DNS labels. A selector of foo.bar is queried at foo.bar._domainkey.example.com, and that name can be delegated with a CNAME the way many DKIM providers already do.
DKIM2 reads the same key record as DKIM. The version tag stays v=DKIM1 on purpose, so a key you already published can verify both. Records that start with any other v= value are ignored. If more than one v=DKIM1 TXT remains at that name, the lookup is an error.
| Tag | Required | Meaning |
|---|---|---|
v=DKIM1 | Recommended | Must be first, and must be exactly DKIM1. If v= is omitted, verifiers treat the record as DKIM1. |
k= | No | Key type. rsa is the default. Also ed25519 and mldsa44. |
p= | Yes | Base64 public key. An empty p= revokes the key. |
DKIM2 ignores the older h=, n=, s=, and t= tags on a key record, including t=y test mode. Publish a new selector when you rotate a key, and leave the old selector in DNS until mail signed with it has finished traveling.
| Key type | p= contents | DKIM2 |
|---|---|---|
rsa | ASN.1 RSA public key, base64 | Verifiers must accept 1024-bit through 4096-bit keys. Signers should use 2048 bits or more. |
ed25519 | The 32-octet public key, base64 | Verifiers must accept it. |
mldsa44 | The 1312-octet ML-DSA-44 public key, base64, with no extra wrapper | Defined for DKIM2. The signature itself is 3,228 base64 characters, so the mail header will be folded. |
The domain policy record is new, and DKIM does not read it. It is a TXT record at _domainkey.example.com. It always starts with v=DKIM1. The only defined flag is strict, in a colon-separated f= list.
_domainkey.example.com. TXT "v=DKIM1; f=strict"f=strict means a key at a subdomain, such as mail.example.com, cannot make a From address at example.com Authentic. Omit the record, omit f=, or omit strict, and subdomain keys are allowed to do that. That matches the loose habit many domains already have with DKIM selectors on delegated subdomains.
The record applies only to the domain that publishes it. Subdomains do not inherit it, and parent zones do not supply it. A temporary DNS failure looking up the policy is a temporary error for the match that needed it. Two policy records that both start with v=DKIM1 are a permanent error.
DKIM2 puts two trace headers on the message. There is no version tag inside them. The header names are the version. A breaking revision would use a new header name.
m= and h= are required. r= is optional.
| Tag | Meaning |
|---|---|
m= | Revision number. The originator uses 1. The next revision is one higher. Gaps or duplicates mean the message is not fully verified. |
h= | One or more algorithm:header-hash:body-hash sets. Algorithms are sha256 and sha512. |
r= | Base64 JSON recipes that rebuild the previous headers or body. |
In h=, a comma means every set in that group must pass. A pipe means any group may pass. sha256:abc:def,sha512:ghi:jkl|sha256:mno:pqr passes when both of the first pair pass, or when the set after the pipe passes. A signer that wants to introduce a new hash can put a familiar one on the other side of a pipe.
i=, m=, t=, d=, and s= are required. The header also needs either nd=, or both mf= and rt=.
| Tag | Meaning |
|---|---|
i= | Signature sequence. The originator uses 1. Later hops increment it. |
m= | Highest Message-Instance number present when this signature was added. |
t= | Unix time when the signature was created, seconds since 1970-01-01 00:00:00 UTC. |
d= | Signing domain. This is the domain used to query DNS for the key. |
s= | One or more selector:algorithm:signature values. Algorithms are rsa-sha256, ed25519-sha256, and mldsa44. |
mf= | Base64 of the SMTP MAIL FROM, including the angle brackets. <> is allowed, and that is what a bounce uses. |
rt= | Base64 of each SMTP RCPT TO, comma-separated. A blind-carbon-copy address must not appear on a copy delivered to someone else. |
nd= | Domain that will sign the next DKIM2-Signature. Used when mail arrives at one domain and leaves from another. When nd= is present, mf= and rt= are omitted. |
n= | Optional nonce, up to 64 printable ASCII characters, with no semicolon. Signers use it as a local handle for later bounces. |
f= | Comma-separated flags: exploded, feedback, feedhere. |
s= uses the same comma and pipe grouping as h=. A comma group passes only when every signature in it passes. A pipe means any group may pass. That is how a signer can offer Ed25519 and RSA together, or require a hybrid of two algorithms.
Example, with the envelope values decoded underneath:
Message-Instance: m=1; h=sha256:HEADERHASH:BODYHASH
DKIM2-Signature: i=1; m=1; t=1762646400; d=example.com;
mf=PGFsaWNlQGV4YW1wbGUuY29tPg==;
rt=PGJvYkBleGFtcGxlLm5ldD4=;
s=mail:ed25519-sha256:BASE64SIGmf= decodes to <alice@example.com>. rt= decodes to <bob@example.net>. The public key is at mail._domainkey.example.com. HEADERHASH, BODYHASH, and BASE64SIG stand in for real values.
Received and Return-Path are not covered by the hashes. Verifiers treat the message as if those headers were absent.
A recipe is JSON, stored base64 in r=. It tells a verifier which header lines or body lines to copy, and which literal lines to put back, so the previous revision can be rebuilt and its hash checked. A null body recipe means the previous body cannot be rebuilt. Header changes cannot use a null recipe. Use a null body recipe when the change removed something that should not travel onward, such as a redacted secret or a stripped attachment. Downstream verification of the body then stops at that hop.
Replay. A DKIM signature stays valid if someone resends the same signed bytes to a new recipient. DKIM2 records RCPT TO in the signature. Sending that message to a recipient who is not in rt= breaks the chain unless the sender adds their own signature, which names their domain. The exploded flag marks a hop that intentionally sent the message to more than one address. It is never set on i=1. Receivers can treat a flood of identical m=1 hashes that arrived through an intermediary, with no exploded flag, as replay.
Bounces. A delivery status notification goes to the MAIL FROM in the latest signature. That signature's d= domain has to align with that MAIL FROM, so a verified message does not bounce to an unrelated forged address. If MAIL FROM is <>, no notification is sent. A forwarder that passes a bounce back removes the signatures and revisions it added on the way out, undoes its own changes, and sends a new DKIM2-signed notification to the previous hop.
A From address is Authentic when its domain matches the relevant signing domain, or either name is a parent of the other.
d=example.com can authenticate From: user@mail.example.com.d=mail.example.com can authenticate From: user@example.com only when _domainkey.example.com does not set f=strict.The check walks labels. It does not use the public suffix list. A From with more than one address, or with an IP address instead of a domain, is never Authentic, and the message cannot be fully verified.
The key query is the same one you already run for DKIM. You still need the selector. In a DKIM2-Signature header it is the text before the first colon in s=, not a separate s= tag the way DKIM uses.
dig mail._domainkey.example.com TXTdig _domainkey.example.com TXTThe DKIM checker fetches that same key TXT. Enter the selector from the left side of s=. It does not parse DKIM2-Signature headers or the domain policy record. For the policy record, query _domainkey.example.com TXT directly.
Most mail you can open today will not have a DKIM2-Signature header. Absence of that header means the sender has not started signing with the draft. It says nothing about the DKIM key.
| DKIM | DKIM2 | |
|---|---|---|
| Status | RFC 6376 | Internet-Draft |
| Public key | selector._domainkey.example.com TXT | Same name, same v=DKIM1 record |
| Extra DNS | None | _domainkey.example.com TXT, only when you want f=strict |
| What is signed | Selected headers and the body | Hashes of the headers and body, plus the SMTP envelope at each hop |
| A forwarder edits the message | The signature fails if signed content changed | The hop records a recipe and signs the new revision |
| Recipients | Not in the signature | RCPT TO is in the signature, so a replay to a new recipient fails the chain |
From check | DMARC alignment, in a separate record | Required for a fully verified message |
| Bounces | Not authenticated by the signature | Sent back along the signed path |
| Policy in DNS | None. DMARC publishes p= | No p=reject equivalent in the current drafts |
SPF still answers a question DKIM2 does not answer for unsigned mail: which hosts may use your domain in MAIL FROM during the SMTP transaction, before any signature is checked. DMARC still publishes what receivers should do when authentication fails, and it still sends aggregate reports. The DKIM2 best-practices draft leaves both of those jobs in place, and it recommends signing with DKIM and DKIM2 together until DKIM2 is actually widespread. Sections of that draft about retiring DMARC or SPF are still open questions, marked as such by the author.
→ See also: SPF Record, DKIM Record, DMARC Record, TXT Record
These drafts are work in progress. Cite them as drafts, and expect the text to move.
Related: SPF Record · DKIM Record · DMARC Record · TXT Record · DKIM Checker