MailDingo

SPF, DKIM, DMARC and ARC

DKIM explained

How a DKIM signature is built (d=, s=, bh=, b=), what canonicalization tolerates, what a pass really proves about the sender, why lists and footers break signatures, and how keys rotate.

5 min read · updated 2026-10-26 · 11 RFC sections cited

DKIM (DomainKeys Identified Mail) is a digital signature added to a message by the sending side. A pass means two things: the domain named in the signature's d= tag took responsibility for the message, and the signed parts have not changed since it was signed. It does not mean that domain is the one in the From: line, or that the message is safe. Linking the signature to the visible sender is DMARC's job.

The pieces of a signature

A signing server adds a DKIM-Signature header. A typical one, trimmed:

DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=example.com;
 s=mail2026; t=1793001600; h=from:to:subject:date:message-id;
 bh=Zm9vYmFyYmF6cXV4Zm9vYmFyYmF6cXV4Zm9vYmE=;
 b=dGhpcyBpcyBub3QgYSByZWFsIHNpZ25hdHVyZSBqdXN0IGEgcGxhY2Vob2xkZXI...
  • d= is the signing domain. This is the identity a pass vouches for.
  • s= is the selector. The receiver fetches the public key from DNS at <selector>._domainkey.<domain>, here mail2026._domainkey.example.com (RFC 6376 §3.6.2.1).
  • h= lists the header fields that were signed. From must always be among them (RFC 6376 §5.4).
  • bh= is a hash of the body. b= is the signature itself, computed over the signed headers plus the DKIM-Signature header (with b= empty).
  • a= is the algorithm. rsa-sha256 is the norm. rsa-sha1 must no longer be used for signing or verifying (RFC 8301 §3.1). Ed25519 keys (ed25519-sha256, RFC 8463) also exist but are less common.
  • c= is the canonicalization, explained below.

Two hashes, two kinds of failure

Verification computes two things in order (RFC 6376 §3.7). First it hashes the body and compares that with bh=. Then it checks b= against the signed headers using the public key. That gives two distinct ways to fail:

  • Body hash mismatch: someone changed the body. A footer, a rewritten link, a converted attachment or a different line ending is enough. Receivers often note this as body hash did not verify.
  • Signature mismatch: the body is fine but a signed header changed (a list added [team] to the Subject, for example), or the key in DNS no longer matches.

The analyser shows the header.d and header.s the receiver recorded, so you can tell which signature a result refers to when there are several.

Canonicalization: how much change is tolerated

Mail servers make small cosmetic changes in transit. Canonicalization defines what gets normalized before hashing (RFC 6376 §3.4):

  • simple tolerates almost nothing: headers must be byte-identical; for the body only trailing empty lines are ignored.
  • relaxed lowercases header names, collapses runs of whitespace and unfolds wrapped header lines, and ignores whitespace at line ends in the body.

c=relaxed/relaxed (headers/body) is the common choice. If no c= is given, both default to simple. Neither mode survives real content changes; canonicalization is about whitespace and folding, nothing more.

There is also an optional l= tag that signs only the first N bytes of the body so that list footers do not break it. RFC 6376 §8.2 warns that it lets an attacker append content after the signed part. Treat a signature with l= cautiously.

What a pass proves, and what it doesn't

A DKIM pass is strong evidence about one domain: whoever controls d= signed this exact content. That is useful, but:

  • Any domain can sign any message. An email service may sign with its own domain (d= the provider) for a customer whose From: is example.com. A scammer can sign with a domain they own. The pass is real in both cases. Only when d= matches the From: domain, exactly or at the organizational level, does it say anything about the visible sender. That is alignment, and the DMARC specification (RFC 9989 §4.4.1) requires alignment precisely because "has a valid signature" is not enough.
  • A pass says nothing about honesty. A phishing message from a look-alike domain can be perfectly signed.
  • Replay is possible. Someone can take a validly signed message and resend it to thousands of people; the signature still verifies (RFC 6376 §8.6). Signing To: and Date: limits how convincing this is, but does not prevent it.

The result codes you may see in Authentication-Results are defined in RFC 8601 §2.7.1: pass, fail, neutral, none, policy, temperror and permerror.

What breaks signatures

In rough order of how often you will meet them:

  1. Mailing lists that tag the Subject, add a footer or strip attachments. See forwarding and mailing lists.
  2. Security gateways that rewrite links for click-time scanning, add "External sender" banners or defang attachments. If this happens before your provider verifies the signature, it fails.
  3. Forwarding with modification, for example an auto-forward rule that adds a note.
  4. Key problems on the sender side: the selector record was deleted, mistyped, or the key was rotated before mail in transit was verified. A missing key usually shows as permerror or fail depending on the receiver.
  5. Re-encoding by an old relay that converts 8-bit content to quoted-printable or similar.

A failed signature is treated as if the message were unsigned. It is not, by itself, a sign of forgery. What matters is whether some aligned check passed. ARC was designed to carry the original result across intermediaries that break DKIM.

Selectors and key rotation

Selectors exist so a domain can publish several keys at once (RFC 6376 §3.1): one per mail provider, per region, or per time period. Rotation works by publishing a new key under a new selector, switching signing to it, then removing the old record once mail in flight has been delivered. An empty p= in the key record marks the key as revoked, and verifiers treat signatures using it as failed (RFC 6376 §6.1.2).

For readers, selectors are a useful clue: names like google, selector1, s1, or a provider-specific token often hint at which service sent the message, though selector names are chosen freely and prove nothing.

Checking it yourself

Copy the full headers (see how to view headers) and paste them into the analyser. It lists every DKIM signature with its d= domain, shows the result your provider recorded for each, and tells you whether any passing signature aligns with the From: domain. It cannot fetch keys from DNS itself, so it reports what the receiving server found at delivery time.

Got a suspicious email?

Paste its headers into the analyser. It runs on your device and explains every result on this page.

Open the analyser

Next in SPF, DKIM, DMARC and ARC: DMARC explained →