DKIM (DomainKeys Identified Mail)
RFC 6376 reference plus RFC 8301 (rsa-sha256 required, 1024–4096-bit keys) and RFC 8463 (ed25519-sha256) — signature and key record syntax, tag meanings, canonicalization, signing scope, and risks.
DKIM (RFC 6376) is a content-based authentication protocol: a domain takes responsibility for a message by adding a DKIM-Signature header containing cryptographic hashes of selected headers and the body, verifiable against a public key published in DNS. A validating signature proves the signed content was not altered after signing and ties the message to the d= domain — the identifier DMARC aligns against (see DMARC). Unlike SPF, DKIM survives forwarding as long as the signed content isn't modified.
The DKIM-Signature header — tag reference
| Tag | Req? | Meaning |
|---|---|---|
v= |
Required | Version; must be 1. |
a= |
Required | Signing algorithm: rsa-sha256 or ed25519-sha256 (RFC 8463). rsa-sha1 MUST NOT be used (RFC 8301). |
b= |
Required | The signature itself, base64. Whitespace ignored. |
bh= |
Required | Hash of the canonicalized body (limited by l= if present), base64. |
c= |
Optional | Canonicalization as header/body; each is simple or relaxed. Default simple/simple; c=relaxed alone means relaxed/simple. |
d= |
Required | SDID — the signing domain claiming responsibility; must have a key record in DNS. This is the DMARC alignment identifier. |
h= |
Required | Colon-separated, ordered list of signed header fields. Must not be empty and must not include the DKIM-Signature being created. May list the same name multiple times and may list nonexistent fields (see oversigning below). |
i= |
Optional | AUID — agent/user identity, an address whose domain must equal or be a subdomain of d= (exactly equal if the key record has flag t=s). Default: @ + the d= value. |
l= |
Optional | Body length count: number of canonicalized body octets covered by bh=. Default: entire body. Security risk — see below. |
q= |
Optional | Key retrieval method; only dns/txt is defined (default). |
s= |
Required | Selector — names the key within the domain (see key record below). |
t= |
Recommended | Signature timestamp, Unix seconds. Verifiers may ignore signatures with future timestamps. |
x= |
Recommended | Absolute expiration timestamp; must be > t=. Not an anti-replay defense. |
z= |
Optional | Diagnostic copy of selected header fields at signing time, ` |
Signing scope: which headers to sign
- The From: field MUST be signed (it is the identity DKIM exists to protect and the field DMARC evaluates). In practice also sign Subject, Date, To, Reply-To, Message-ID, MIME headers, and List-* fields.
- Oversigning: listing a header name in
h=one more time than it occurs signs a "null" instance, so any later addition of that header (e.g., a second From: or Subject: injected downstream) breaks the signature. Recommended for From, Subject, To, Reply-To. - Multiple instances of a header are signed bottom-up; you cannot selectively sign one instance.
The l= body-length risk
l= lets a signature cover only the first N body octets so intermediaries can append content (e.g., list footers) without breaking it. This means anything appended after N octets is unverified — an attacker can replay a signed message with malicious content appended and the signature still validates. This was exploited in practice ("DKIM l= vulnerability", 2024). Do not sign with l=; verifiers should treat l= signatures with suspicion or ignore the tag's exemption.
The DNS key record
Published as a TXT record at:
<selector>._domainkey.<domain>
| Tag | Default | Meaning |
|---|---|---|
v= |
DKIM1 |
Version; if present, must be first tag. |
p= |
— (required) | The public key, base64. An empty p= means the key is revoked. |
k= |
rsa |
Key type: rsa or ed25519 (RFC 8463). |
h= |
all allowed | Colon-separated acceptable hash algorithms (sha256; sha1 obsolete). |
s= |
* |
Service type: * or email. |
t= |
none | Flags: y = testing mode; s = the i= domain must exactly equal d= (no subdomain AUIDs). |
n= |
empty | Human-readable notes for administrators. |
Example (Ed25519, from RFC 8463):
brisbane._domainkey.football.example.com. IN TXT
"v=DKIM1; k=ed25519; p=11qYAYKxCrfVS/7TyWQHOg7hcvPapiMlrwIaaPcHURo="
Selector hygiene: selectors allow multiple concurrent keys (per system, per ESP, per date). Rotate keys by publishing a new selector, switching signing, then revoking the old key. Never re-use a selector with a new key — you lose the ability to distinguish legitimately-signed old mail from forgeries.
Algorithms and key sizes (RFC 8301, RFC 8463)
| Rule | Requirement |
|---|---|
| Signing algorithm | Signers MUST sign with rsa-sha256. rsa-sha1 MUST NOT be used for signing or verifying (SHA-1 is historic). |
| RSA key size — signers | MUST use ≥ 1024-bit keys; 2048-bit recommended (current operational baseline). |
| RSA key size — verifiers | MUST validate keys from 1024 to 4096 bits; MAY support larger. MUST NOT treat signatures made with keys < 1024 bits as valid. |
| Ed25519 (RFC 8463) | a=ed25519-sha256, key record k=ed25519, p= is the base64 Ed25519 public key. Keys are 256 bits → the encoded key is only 44 octets, fitting one 255-byte TXT string (large RSA keys often need split strings). |
| Dual signing | For compatibility, sign with both rsa-sha256 and ed25519-sha256 using different selectors (one key record per selector). Verifier support for Ed25519 is still not universal. |
Canonicalization
Canonicalization normalizes content before hashing to tolerate in-transit rewriting; it does not alter the transmitted message.
| Algorithm | Rules |
|---|---|
simple (header) |
Headers presented exactly as they appear — any change breaks the signature. |
relaxed (header) |
Lowercase header names; unfold continuation lines; collapse whitespace runs to a single space; strip trailing whitespace; remove whitespace around the colon. |
simple (body) |
Strip trailing empty lines; ensure body ends with a single CRLF. |
relaxed (body) |
Strip end-of-line whitespace; collapse internal whitespace runs to a single space; strip trailing empty lines; ensure final CRLF. |
relaxed/relaxed is the practical default — simple header canonicalization breaks whenever any MTA re-folds or re-wraps headers.
Verification behavior
- Outcomes per signature: SUCCESS, PERMFAIL (unrecoverable — bad signature, revoked/undersized key, syntax error), TEMPFAIL (transient — e.g., DNS timeout).
- A failed signature is treated as if the message were unsigned — DKIM failure is not itself grounds for rejection; it simply provides no positive identifier. (DMARC is what turns "no aligned pass" into policy.)
- Multiple signatures are evaluated independently on their own merits; verifiers keep checking until one verifies. A message can legitimately carry signatures from the author domain and one or more intermediaries.
- Verifier output must include the
d=domain and result — surfaced downstream in the Authentication-Results header.
Deliverability notes
- Mailbox providers increasingly key reputation to the DKIM d= domain, and favor DKIM over SPF for DMARC alignment, feedback-loop enrollment, and sender tooling.
- Gmail/Yahoo bulk-sender requirements effectively make an aligned DKIM signature with a ≥1024-bit key (2048 recommended) mandatory at scale.
- DKIM does not prevent replay: a spammer can resend a legitimately signed message verbatim to new recipients and the signature still passes, spending the d= domain's reputation. Mitigations: short
x=expirations, per-recipient/stream selectors, and monitoring.