egressif.

Resources / Authentication

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.

Last checked: June 21, 2026

DKIM (DomainKeys Identified Mail) lets a domain “claim some responsibility for a message by associating the domain with the message via a cryptographic signature” (RFC 6376 §1). Unlike SPF, it does not care about the connecting IP. It cares about a signature, computed over chosen headers and the body, that a receiver can verify using a public key the signing domain publishes in DNS. That difference - signature over content versus check on an IP - is why DKIM survives forwarding where SPF does not.

The 60-second version

  • The signer adds a DKIM-Signature: header. The two load-bearing tags are d= (the signing domain) and s= (the selector); together they form the DNS lookup s._domainkey.d (RFC 6376 §3.1, §3.6.2.1).
  • A valid signature proves only two things: the d= domain signed it, and the signed parts were not modified in transit. Nothing more (RFC 6376 §1.5).
  • A signature failure does not force rejection (RFC 6376 §1).
  • c= selects canonicalization. Default is simple/simple; most senders use relaxed/relaxed because simple is brittle (RFC 6376 §3.5, §3.4).
  • l= (body length) is a footgun: it lets content be appended after the signed region. Avoid it.
  • No certificate authority is involved; the public key comes straight from the signer’s DNS (RFC 6376 §1.4).
SENDERprivate keys=mar2026signMESSAGEDKIM-Signatured= s= b= bh=RECEIVERverifierfetch keyDNSs._domainkey.dp= public keyVERIFYsignature +body hash
The DKIM-Signature travels with the message; the receiver fetches the public key from selector._domainkey DNS and verifies the signature and body hash.

Selectors, d=, and s=

A domain can have many keys live at once. DKIM subdivides the key namespace with selectors: the s= tag in the signature names which key, and the verifier looks it up under the _domainkey subtree (RFC 6376 §3.1).

DKIM-Signature: ... d=example.com; s=mar2026; ...
                         │             │
                         │             └── selector
                         └──────────────── signing domain (SDID)

DNS query:  mar2026._domainkey.example.com   (TXT record holding the public key)

Selector names may contain periods, which act as DNS label separators: for d=example.com and s=foo.bar, the query is foo.bar._domainkey.example.com (RFC 6376 §3.6.2.1). All keys live under the _domainkey subdomain, and the TXT RR for a given selector MUST be unique - multiple records for one selector gives undefined results (RFC 6376 §3.6.2.1).

The d= value is the Signing Domain Identifier (SDID), the mandatory output of DKIM and the domain a receiver treats as having taken responsibility (RFC 6376 §2.5). For DMARC, the DKIM-Authenticated Identifier is exactly this d= value (RFC 9989 §4.4.1).

The DKIM-Signature header tags

All defined in RFC 6376 §3.5. Tag values are case-sensitive unless noted.

TagRequiredWhat it is
v=REQUIREDversion; MUST be 1
a=REQUIREDsigning algorithm, e.g. rsa-sha256
b=REQUIREDthe base64 signature value
bh=REQUIREDbase64 hash of the canonicalized body
d=REQUIREDsigning domain (SDID); the domain queried for the key
s=REQUIREDselector; with d= forms s._domainkey.d
h=REQUIREDcolon-separated list of signed header names; MUST NOT be empty
c=OPTIONALheader/body canonicalization (default simple/simple)
i=OPTIONALAUID; its domain MUST equal or be a subdomain of d=
l=OPTIONALbody length count - see the warning below
q=OPTIONALquery method (default and only defined value dns/txt)
t=RECOMMENDEDsignature creation time (Unix epoch)
x=RECOMMENDEDsignature expiration (Unix epoch); MUST be greater than t=
z=OPTIONALdiagnostic copy of selected headers at signing time

The h= tag is worth dwelling on: it lists which headers are protected. Anything not in h= is unsigned and can be altered or added without breaking the signature. Sensible signers include From: (and DMARC effectively requires the From: to be signed for the DKIM identifier to be meaningful).

The published key record

The public key lives at <selector>._domainkey.<domain> as a TXT record (RFC 6376 §3.6.1).

mar2026._domainkey.example.com.  3600 IN TXT  "v=DKIM1; k=rsa; p=MIIBIjANBgkq...QAB"
TagRequiredWhat it is
v=RECOMMENDEDversion; MUST be DKIM1 if present, and MUST be the first tag; other values -> record discarded
h=OPTIONALacceptable hash algorithms (default: all)
k=OPTIONALkey type (default rsa)
n=OPTIONALhuman notes
p=REQUIREDbase64 public key; an empty p= means the key is revoked
s=OPTIONALservice type (default *; or email)
t=OPTIONALflags: y = testing mode, s = i= must not be a subdomain of d=

Two facts to internalize: an empty p= is the revocation signal, and the t=y testing flag means verifiers “MUST NOT treat differently from unsigned email” (RFC 6376 §3.6.1). Leaving t=y on a production key effectively neuters it.

Canonicalization: simple vs relaxed

Mail is modified in transit in trivial ways - whitespace gets rewritten, lines get re-folded, a trailing blank line appears. Canonicalization decides how forgiving the signature is about that. There are two algorithms each for the header and the body, chosen by c=header/body; the default is simple/simple (RFC 6376 §3.4, §3.5).

AlgorithmHeader behaviorBody behavior
simpleno changes at all; header names not case-folded, whitespace untouched (§3.4.1)ignores empty lines at end of body; folds trailing *CRLF to one CRLF; empty body canonicalizes to a single CRLF (§3.4.3)
relaxedlowercases header names, unfolds continuations, collapses WSP runs to one SP, strips trailing WSP and WSP around the colon (§3.4.2)strips trailing-of-line whitespace, collapses internal WSP runs to one SP, ignores trailing empty lines (§3.4.4)

simple is strict to the point of fragility: a single mail server that adjusts whitespace can break a simple signature. relaxed/relaxed tolerates the cosmetic rewrites that normal relays perform, which is why it is the common production choice. Neither tolerates a content change inside the signed region - that is the point.

The l= body-length trap

l= tells the verifier how many octets of the body are covered by the hash. Anything past that count is unsigned. RFC 6376 §3.5 flags this directly: misuse “allows appending content.” An attacker (or a careless intermediary) can add text, HTML, or an entire trailing message after the signed region and the signature still validates over the original l= octets. Unless you have a very specific reason and understand the exposure, do not set l=; sign the whole body.

Key rotation (and why you never reuse a selector)

Rotation is just publishing a new key under a new selector and moving signing to it, then retiring the old one. The spec is blunt about the wrong way to do it: reusing a selector with a new key “makes it impossible to tell forged messages from messages that failed due to key rotation,” and “signers are ill-advised to reuse selectors for new keys” (RFC 6376 §3.1).

A safe rotation looks like:

1. Publish new key:      mar2026._domainkey.example.com  (v=DKIM1; p=<new>)
2. Switch signing to s=mar2026 once DNS has propagated.
3. Leave the old selector published long enough for in-flight mail to verify.
4. Revoke the old key by setting its p= to empty, or remove the record.

New selector per rotation, overlap during propagation, and revoke (empty p=) rather than silently delete if you want the revocation to be explicit.

Algorithms and the crypto updates

RFC 6376 itself defines two signing algorithms, rsa-sha1 and rsa-sha256, and says signers MUST implement and SHOULD sign with rsa-sha256, while verifiers MUST implement both (RFC 6376 §3.3). Its original key-size baseline was RSA keys of at least 1024 bits for long-lived keys (RFC 6376 §3.3.3).

Two later RFCs update this:

  • RFC 8301 updates DKIM’s cryptographic algorithm and key-usage requirements, raising the minimum acceptable RSA key length above the original 1024-bit baseline and tightening hash-algorithm guidance. (We are deliberately not stating its exact threshold here; see the note at the end of this page.)
  • RFC 8463 adds a new signature method, Ed25519-SHA256 (ed25519-sha256), as an alternative to RSA (confirmed from RFC 6376’s “Updated by” record). Ed25519 keys are far shorter than RSA keys for comparable strength, which also helps them fit in a DNS TXT record without splitting.

Practically: sign with rsa-sha256 (or Ed25519 where your platform and receivers support it), use a comfortably modern RSA key length, and do not sign with rsa-sha1.

What DKIM survives that SPF does not

This is the reason DMARC accepts DKIM as an alternative path. SPF checks the connecting IP; the moment a message is forwarded or relayed, the IP changes and SPF fails for your domain. DKIM checks a signature over the message content, so it keeps validating as long as the signed parts are not modified (RFC 6376 §1.5; the forwarding/IP failure mode is described in RFC 8617 §1, §2).

The flip side: DKIM breaks when an intermediary changes signed content - a mailing list that rewrites the Subject: or appends a footer alters bytes inside the signed region, and the signature fails. So DKIM survives a plain forward but not a modifying list. That residual gap is exactly what ARC was built to bridge.

For DMARC, a message can carry multiple DKIM signatures, and DMARC passes if any DKIM-Authenticated Identifier (d=) aligns with the Author (From:) domain (RFC 9989 §4.4.1).

Common confusion / what does NOT change

  • “A DKIM pass proves who wrote the email.” No. It proves the d= domain signed it and the signed bytes are intact (RFC 6376 §1.5).
  • “DKIM needs a CA / a paid certificate.” No. The key is published in your own DNS; there is no certificate authority (RFC 6376 §1.4).
  • “A DKIM failure should bounce the mail.” Not on its own; RFC 6376 §1 says failure does not force rejection. Rejection policy is DMARC’s job.
  • “Set l= to be tolerant of footers.” That is the appending vulnerability. Don’t.
  • “Reuse one selector forever.” That makes rotation and forgery indistinguishable (RFC 6376 §3.1).
  • t=y is harmless.” On a live key it tells verifiers to treat your signed mail as unsigned.

What Egressif does

We sign with aligned DKIM on your domain using a modern key, so that DMARC has a path that survives forwarding even when SPF cannot. We sign the headers that matter (including From:), avoid l= entirely, and rotate keys by publishing a fresh selector and revoking the old key with an empty p= rather than reusing a name. Because DKIM is the half of DMARC that holds up across relays and lists, we treat a broken or t=y key as a real incident, not a cosmetic one.

Note on RFC 8301: our verified research confirms the original RFC 6376 §3.3.3 baseline of 1024-bit RSA and that RFC 8301 raised the minimum, but the exact updated key length and the precise hash-deprecation wording were not independently verified against RFC 8301’s text at author time, so this page does not assert a specific number for them.

Related references

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.

Talk to our team