CertaDNS
Skip to lesson

DKIM Fundamentals · lesson 3 of 4

Anatomy of a DKIM-Signature header

After this lesson you can

Read a DKIM-Signature header and say which domain is making the claim and which headers it covers.

Assumes you have read Selectors, and finding the key.

The DKIM-Signature header carries everything a receiver needs to check it. Being able to read one turns a DKIM failure from a mystery into one of about four specific causes.

The header, annotated

DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=example.com; s=sel1; t=1757635200;
h=from:to:subject:date:message-id;
bh=2jmj7l5rSw0yVb/vlWAYkK/YBwk=;
b=dzdVyOfAKCdLXdJOc9G2q8LoXSlEniSbav+yuU4zGeeruD00lszZ...
  1. d= — the signing domain. The domain taking responsibility. This is the tag that alignment will compare against the From header, so it is the most important one on the line.
  2. s= — the selector. Combined with d= it gives the DNS name of the public key: sel1._domainkey.example.com.
  3. a= — the algorithm. rsa-sha256 in practice; rsa-sha1 is deprecated by RFC 8301 and should be treated as a finding.
  4. c=canonicalisation, header then body.
  5. h= — the list of headers covered. Anything not in this list is unsigned and can be changed or added in transit without breaking the signature.
  6. bh= — the body hash. Checked first, and separately from the signature.
  7. b= — the signature itself, over the headers in h= plus this header with b= emptied.

Verification is two checks, not one

This is the part worth remembering, because it tells you where a failure came from:

  • The body hash. The receiver canonicalises the body, hashes it, and compares with bh=. If this fails, the body changed in transit — and the signature is never even checked.
  • The signature. Over the headers listed in h=. If the body hash matched but this fails, a signed header changed, or the key does not match the one that signed.

Good diagnostics report these separately. "Body hash did not verify" means something rewrote the message — a mailing list footer, a link-rewriting gateway, a disclaimer appender. "Signature did not verify" with a good body hash means a header problem or a key mismatch. Those are different investigations.

The h= tag, and what it leaves open

A signature only covers the headers it names. RFC 6376 §5.4 requires From and nothing else, so a minimal signature covering only from is valid and leaves the subject line free to be altered in transit without any signature breaking.

Header in h=Consequence
fromRequired. Without it the signature would assert nothing about who the message is from.
subjectStrongly advisable. Otherwise the subject is modifiable in transit.
to, date, message-idUsual, and sensible.
A header listed twiceOver-signing: it signs the absence of a second copy, so an intermediary cannot add one.

Over-signing, briefly

Listing a header name in h= more times than it appears in the message signs the fact that there is no further copy. Without it, an intermediary can prepend a second Subject: header; the original is still signed and still verifies, while many mail clients display the new one. Most sending platforms do this for you and it is not something you normally configure.

More than one signature

A message may carry several DKIM-Signature headers, and this is normal rather than suspicious. A platform commonly signs with its own domain while also signing with yours. A receiver evaluates each independently, and for DMARC purposes it only takes one valid signature whose d= aligns with the From header.

This is why "DKIM passed" is an incomplete statement. The useful question is always which domain passed, and that is the d= tag.

Try it on a real domain

Free, no account, public DNS only.

Last reviewed