Deliverability

What is DKIM, and how does DKIM signing work?

DKIM answers a narrow question: did somebody holding this domain's private key sign this message, and has the signed part arrived unchanged? Everything else people expect of it, that the sender is trustworthy or that the visible From address is genuine, comes from other mechanisms layered on top. SPF vs DKIM vs DMARC is the comparison; this page is what happens inside the signature.

What does a DKIM signature actually cover?

A list of headers you choose, and a hash of the body. Not the message.

The signer picks which header fields to sign and names them in the h= tag. Everything else in the message is outside the signature. That is deliberate, because mail acquires headers in transit (Received, spam scores, list headers) and a signature over the whole message would break at the first hop.

The body is handled differently. It is hashed, and only the hash goes in the signature, in the bh= tag. So a verifier recomputes the body hash and compares, then verifies the signature over the chosen headers plus that hash.

The practical consequence is the part worth remembering. A header that is not in h= is not protected. An intermediary can add a second Subject or a Reply-To and the signature still verifies, because the signature never made a claim about them.

Where does the public key live?

Under a selector, which is the piece that makes the whole thing operable.

The signature carries a domain in d= and a selector in s=, and the verifier turns that pair into a DNS lookup. RFC 6376 states the rule directly:

All DKIM keys are stored in a subdomain named "_domainkey". Given a DKIM-Signature field with a "d=" tag of "example.com" and an "s=" tag of "foo.bar", the DNS query will be for "foo.bar._domainkey.example.com".

The selector layer is not decoration. It is why you can rotate a key by publishing a new selector, signing with it, and retiring the old record once nothing in flight still references it. It is also why several platforms can sign for the same domain at once, each under its own selector, without any of them coordinating. Bird generates a selector per organization for exactly that reason, so two organizations sending from one domain never share a key; the DKIM, SPF & DMARC guide has the record shape.

Why does the same message verify in one place and fail in another?

Canonicalization, almost always.

Before hashing, both signer and verifier normalize the message so that harmless rewriting in transit does not look like tampering. There are two algorithms for headers and two for the body, and the signer names its choices in the c= tag.

AlgorithmWhat it tolerates
simpleAlmost nothing. Header folding, added whitespace, or a changed final line break fails
relaxedCase and whitespace changes in header names, folded headers, trailing whitespace

Most signers use relaxed/relaxed because mail transfer agents legitimately refold long headers. A simple/simple signature is more precise and much easier to break by accident. When a message verifies at your outbound gateway and fails two hops later, the change that did it is usually invisible to the eye and lethal to simple.

Which algorithms and key sizes are still valid?

SHA-1 is gone, and there is a floor under RSA key length.

RFC 8301 updated the original specification on both points:

Signers MUST sign using rsa-sha256. Verifiers MUST be able to verify using rsa-sha256. rsa-sha1 MUST NOT be used for signing or verifying.

and

Signers MUST use RSA keys of at least 1024 bits for all keys. Signers SHOULD use RSA keys of at least 2048 bits.

Yahoo states the same floor in its own sender guidance, asking senders to authenticate "with a minimum 1024-bit key length". A separate standard, RFC 8463, adds Ed25519-SHA256 as a second signing algorithm, so a message can carry two signatures for the same domain while verifiers catch up.

Why does DKIM break on mailing lists?

Because a list edits the body, and the body hash is not negotiable.

This is the mirror image of SPF's weak spot. SPF depends on the sending IP, so it breaks on forwarding and survives editing. DKIM depends on the content, so it survives forwarding and breaks on editing. A list that appends an unsubscribe footer or rewrites a subject line has changed the signed material, and the signature fails, on a message that is entirely legitimate.

The specification offers one escape and warns against it in the same breath. The l= tag signs only the first N octets of the body, so an appended footer leaves the signed prefix intact. RFC 6376 explains what that buys an attacker:

Use of the "l=" tag might allow display of fraudulent content without appropriate warning to end users.

An intermediary can append content of their own to the unsigned remainder, and in a mail client that content can dominate what the reader sees. So l= trades a verification failure for a spoofing surface, which is why the mainstream answer to the mailing-list problem became ARC instead: a way for the list to record that authentication passed before it made its edits.

What does a passing signature entitle you to?

Very little on its own, which is the last thing to get straight.

A valid signature proves that the holder of a key for d= took responsibility for the signed content. It does not prove the message is wanted, that the sender is reputable, or that d= has anything to do with the address in the From line. A spammer can DKIM-sign their own domain perfectly.

Tying the signature to the domain your recipient reads is DMARC alignment, and turning a passing signature into inbox placement is reputation, which is a separate discipline entirely.

Buduj na tej samej sieci.

Testowy klucz API otrzymasz od razu. Dostęp produkcyjny odblokujesz po dodaniu metody płatności i zweryfikowaniu nadawcy.

Zacznij od jednego kanału.
Dodaj kolejne, gdy będziesz gotowy.

Testowy klucz API otrzymasz od razu. Dostęp produkcyjny odblokujesz po dodaniu metody płatności i weryfikacji nadawcy.

Używasz Claude Code, Cursor lub Codex? Skopiuj prompt konfiguracyjny, a Twój agent zainstaluje za Ciebie Bird CLI i umiejętności. Wybierz swój:

Cursor