You know that DKIM signs your emails. But what exactly is inside that DKIM-Signature header? Let’s break down every field and follow the verification process from start to finish.

A Real DKIM Header, Dissected

DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
  d=example.com; s=selector2024;
  h=from:to:subject:date:mime-version:content-type;
  bh=2jUSOH9NhtVGCQWNr9BrIAPreKQjO6Sn7XIkfJVOzv8=;
  t=1714123456;
  b=dHJ5aW5nIHRvIHJlYWQgdGhpcyBzaWduYXR1cmU/IE5pY2Ug
    dHJ5IDspIFRoaXMgaXMganVzdCBhIGR1bW15IGV4YW1wbGU=

Every Field Explained

v=1: Version

The DKIM protocol version. Only one version exists (1), defined by RFC 6376. This field is mandatory.

a=rsa-sha256: Algorithm

Two elements combined:

  • Cryptosystem: rsa (most common) or ed25519 (emerging, RFC 8463)
  • Hash function: sha256 (standard) or sha1 (obsolete and vulnerable, do not use)
CombinationStatus
rsa-sha256Standard, recommended
rsa-sha1Obsolete, some providers reject it
ed25519-sha256Future standard, partial support

c=relaxed/relaxed: Canonicalization

Defines how content is normalized before computing the signature. The format is headers/body:

Simple mode:

  • Headers: no modification (case-sensitive, whitespace-sensitive)
  • Body: removes duplicate empty lines at the end of the message

Relaxed mode:

  • Headers: converts to lowercase, reduces multiple spaces, removes trailing whitespace
  • Body: same + reduces multiple spaces on each line

In practice, relaxed/relaxed is the standard choice because it tolerates minor changes made by relay servers (added spaces, case changes).

d=example.com: Signing Domain

The domain responsible for the signature. This domain must align with the From: header for DMARC to validate DKIM alignment.

The public key will be looked up in this domain’s DNS zone.

s=selector2024: Selector

Identifies which public key to use among those published for the domain. The full DNS record will be:

selector2024._domainkey.example.com TXT "v=DKIM1; k=rsa; p=MIIBIjANBg..."

Selectors enable key rotation without downtime: publish a new key on a new selector before switching.

h=from:to:subject:date:...: Signed Headers

The list of headers included in the signature. Only From: is technically mandatory, but in practice you always include:

  • from, to, subject, date (basic integrity)
  • mime-version, content-type (message structure)
  • message-id (uniqueness)
  • reply-to, cc (if present)

A header not listed can be modified in transit without breaking the signature. A listed header that changes will invalidate the signature.

bh=2jUSOH9N...: Body Hash

The hash of the canonicalized message body, encoded in Base64. Computed using the hash algorithm defined in a= (sha256).

This field allows verifying that the body hasn’t been modified independently of the full signature.

t=1714123456: Timestamp

The Unix timestamp of when the signature was created. Allows the receiving server to verify the signature isn’t too old (some providers reject signatures older than a few days).

b=dHJ5aW5n...: The Signature

The final result: the RSA (or Ed25519) signature of the canonicalized headers + body hash, encoded in Base64. This value is decrypted with the public key for verification.

The Verification Process, Step by Step

When a receiving server gets an email with a DKIM signature:

1. Format Validation The server checks that all mandatory fields are present (v, a, b, bh, d, h, s).

2. Body Canonicalization The body is normalized according to the algorithm defined in c= (right side).

3. Body Hash Computation and Comparison The hash of the canonicalized body is computed with sha256 and compared to bh=.

  • If mismatchbody hash did not verify → DKIM fail

4. Public Key Retrieval The server makes a DNS query for s=._domainkey.d= and retrieves the TXT record containing the public key.

5. Header Canonicalization The headers listed in h= are canonicalized according to the algorithm defined in c= (left side).

6. Signature Verification The signature b= is decrypted with the public key. The result is compared with a computed hash of the canonicalized headers + body hash.

  • If match → DKIM pass
  • If mismatchsignature did not verify → DKIM fail

Optional Fields

FieldDescription
x=Signature expiration (Unix timestamp)
i=Identity of the signing agent (e.g., user@example.com)
l=Number of body bytes included in the hash (dangerous, discouraged)
q=dns/txtKey retrieval method (only dns/txt exists)
z=Copy of original headers (for diagnostics)

Warning: the l= field is a known vulnerability. If present, an attacker can append content to the message body without breaking the signature. Never use it.

How to Analyze a DKIM Signature

  • Header Analyzer: paste raw headers for a visual analysis of each DKIM field
  • DKIM Checker: verify the published DNS record for your selector
  • Free audit: send a test and see the full result

Further Reading