SPF authorises a host. DKIM authenticates a message. The difference is the whole of why DKIM survives a forward and SPF does not, and it starts with knowing exactly which bytes the signature commits to.
Two hashes, not one
A signer computes two things, and both end up in the header it adds.
- The body hash. A SHA-256 digest of the message body, canonicalised. It lands in the
bh=tag. - The signature. An RSA or Ed25519 signature over a canonicalised copy of the headers named in
h=— plus the DKIM-Signature header itself, with its ownb=value blanked. It lands inb=.
The body is therefore covered indirectly: the signature covers bh=, and bh= covers the body. That indirection is the reason a receiver can report the two failures separately, and it is what makes body hash did not verify such a precise diagnostic.
What a verifier does
1. Read the DKIM-Signature header. 2. Fetch the key at <s>._domainkey.<d> 3. Canonicalise the body, hash it, compare to bh= 4. Canonicalise the h= headers, verify b= against the key 5. Report one result
Step 3 before step 4 is not arbitrary — RFC 6376 §6.1.3 has the verifier check the body hash first precisely so that a body modification is reported as a body modification rather than as a generic signature failure.
What is not covered
- Any header not named in h=. A header absent from the list can be added, changed or removed freely without touching the signature.
- The envelope. DKIM never sees MAIL FROM or RCPT TO. A signed message can be re-sent to a completely different recipient and the signature still verifies — which is the mechanism behind replay.
- The connecting IP. Deliberately. That is SPF’s evidence, and tying the signature to it would destroy the property that makes DKIM worth having.
- Time. Unless the signer sets
x=, the signature does not expire.
A signature is a statement about bytes, not about intent
A valid signature says: the domain in d= held the private key for selector s=, and these headers and this body are as that domain released them. It says nothing about who sent it, to whom, from where, or whether the domain meant to send it at all.