Every tag in a DKIM-Signature header either tells the verifier where to find something or constrains what it will accept. Read one properly and you can predict the result before the verifier produces it.
A signature, annotated
(1)DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;(2) d=example.com; s=mail202609;(3) h=from:to:subject:date:message-id;(4) bh=2jmj7l5rSw0yVb/vlWAYkK/YBwk=;(5) t=1757894400; x=1758499200;(6) b=dzdVyOfAKCdLXdJOc9G2q8LoXSlEniSb...
v=1is the only version there has ever been.a=is the algorithm, andc=is header/body canonicalisation.d=is the signing domain — the one DMARC compares against the From header. Withs=it gives the DNS name to query:mail202609._domainkey.example.com.h=is the ordered list of headers covered. Order matters: the verifier canonicalises them in exactly this sequence.bh=is the body hash. This is the value compared in step one of verification.t=is the signing timestamp andx=an expiry. Both optional, andx=is rare.b=is the signature itself. During verification this field is treated as empty, because it cannot cover itself.
The tags worth knowing
| Tag | Meaning | Notes |
|---|---|---|
d= | Signing domain | The one that matters for DMARC alignment. |
s= | Selector | With d=, forms the DNS name of the key. |
a= | Algorithm | rsa-sha256 in practice. rsa-sha1 is dead — RFC 8301 forbids it. |
c= | Canonicalisation | header/body. Almost always relaxed/relaxed. |
h= | Signed headers | Ordered. Repeating a name oversigns it. |
bh= | Body hash | Checked first, separately. |
b= | Signature | Blanked while verifying itself. |
l= | Body length | Signs only the first N octets. Rarely a good idea. |
i= | Identity | An address within d=. Informational for DMARC. |
x= | Expiry | After this, verifiers may treat the signature as invalid. |
q= | Query method | Only dns/txt is defined. |
d= is not necessarily the domain in the From header
A message can carry From: billing@yourbank.com and a perfectly valid signature with d=mailer.somevendor.com. DKIM passes. DMARC does not, because d= and the From domain are unrelated. When a vendor says “we sign everything with DKIM”, this is the question to ask them.
More than one signature
A message may carry several DKIM-Signature headers, and each is verified independently. This is normal: a platform signs as itself, and a gateway adds a second signature as your domain on the way out.
- A verifier reports a result per signature.
- DMARC needs only one of them to pass and align.
- A failing signature alongside a passing aligned one is not a problem to chase.
Why b= has to be blanked during verification
The signature covers the DKIM-Signature header, because otherwise an attacker could rewrite h= or d= at will. But it cannot cover its own value — the value does not exist until the computation finishes. RFC 6376 §3.7 resolves it by defining the header as signed with b= treated as empty, on both sides. Every other tag in the header is genuinely covered.