All tips
DKIM 5 min read

What DKIM actually does

DKIM signs the message itself, so the proof travels with the mail. That is why it survives forwarding when SPF does not.

DomainKeys Identified Mail attaches a cryptographic signature to outgoing messages. Your sending server holds a private key, and the matching public key is published in DNS. A receiver reads the signature header, fetches your public key, recomputes the hashes, and compares. If they match, two things are established: the signed parts of the message have not been altered since they left you, and whoever sent it held your domain's private key.

That second property is what makes DKIM more durable than SPF. SPF authorises an IP address, which is a fact about the path a message took. DKIM authenticates the message itself, so the proof travels with it.

The signature header

A DKIM-Signature header, trimmed

DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
  d=example.com; s=selector1; t=1700000000;
  h=from:to:subject:date:message-id;
  bh=2jmj7l5rSw0yVb/vlWAYkK/YBwk=;
  b=Xa9dK3...
  • d= is the signing domain. This is the identity DMARC checks for alignment, and the tag that matters most.
  • s= is the selector, naming which key under that domain to fetch from DNS.
  • h= lists the headers covered by the signature.
  • bh= is the hash of the body.
  • b= is the signature itself, over the headers in h= plus the body hash.
  • a= is the algorithm, almost always rsa-sha256.
  • c= is canonicalisation: how whitespace and header folding are normalised before hashing.

How a receiver verifies it

The receiver reads s= and d= from the signature, then queries the TXT record at <selector>._domainkey.<domain>. Nothing enumerates selectors, so the receiver can only check the one the message told it about. It fetches the public key, recomputes the body hash, compares it to bh=, then verifies b= over the headers listed in h=. Any mismatch is a failure.

Two details in that process cause most real-world breakage. The first is that only the headers in h= are protected, so anything not listed can be added or altered freely without invalidating the signature. The second is canonicalisation: strict mode (c=simple) fails if any hop adjusts a single space, while relaxed mode tolerates the whitespace and header-folding changes that mail servers routinely make. Use relaxed on both sides unless you have a specific reason not to.

Canonicalisation in practice

The two halves of c= are header and body

c=simple/simple     strictest, breaks easily in transit
c=relaxed/relaxed   tolerant of whitespace and folding, the usual choice
c=relaxed/simple    headers relaxed, body byte-exact

Several signatures on one message

A message may carry more than one DKIM signature, and this is normal rather than suspicious. Your mail platform may sign with its own domain as well as yours, and a mailing list may add its own signature on the way through. Each is verified independently.

For DMARC, only a signature whose d= aligns with the From domain counts. A vendor signing with their own domain produces a valid signature and a DMARC failure at the same time, which is one of the most common and most confusing states to land in. Alignment and the d= tag covers how to spot and fix it.

Key strength

Use 2048-bit RSA. 1024-bit keys are still widely accepted and still verify, but they are the floor rather than a target, and they are within reach of a well-resourced attacker. Ed25519 keys are defined in RFC 8463 and are dramatically shorter, which sidesteps the DNS record-length awkwardness of RSA, but support among receivers remains patchy. If you adopt Ed25519, publish an RSA key alongside it and sign with both.

A 2048-bit key in base64 exceeds the 255-character limit for a single DNS TXT string, so it must be published as multiple quoted strings within one record. Most DNS providers handle the split for you. Those that do not will silently truncate, producing a key that looks present and never verifies.

Where signing happens matters

The signature must be applied after every modification your own infrastructure makes. If a security gateway appends a disclaimer, rewrites links, or re-encodes the body on the way out, and it sits after the signing step, it invalidates the signature you just applied. Signing has to be the last thing that touches the message before it leaves. This is the usual explanation when mail from one internal system verifies and mail from another does not, despite both using the same key.

What DKIM does not do

A valid signature says a message was signed by the holder of a domain's private key and has not been altered in its signed parts. It says nothing about whether the content is legitimate or wanted. A spammer can register a domain, publish a key, and sign their mail perfectly. Signature validity is a statement about integrity and control of a key, not about trustworthiness.

On its own, DKIM also does not require the signing domain to have anything to do with the From address. That requirement comes from DMARC, and without it a valid signature over a spoofed From header proves nothing useful to the recipient.

Checking your own

Look up a selector with the DKIM tool to confirm the record parses, the key is present, and the size is what you expect. Then send a real message to a mailbox you control and read the Authentication-Results header on arrival: dkim=pass header.d=example.com is the outcome you want, with your own domain in d=, not your provider's. When you are ready to put a key in place, publishing your first DKIM key walks through it.

Look up a DKIM selector and key strength
dkimbasicscryptography