LetterDuck
Deliverability

What is DKIM? Selectors, keys, and signatures

The signature that rides inside the message: what it covers, how selector records work, why keys should be 2048 bits, and what rotation looks like in practice.

DKIM (DomainKeys Identified Mail, RFC 6376, published 2011) puts a cryptographic signature on every message you send, and it is the only email authentication that survives forwarding. Your server signs the message with a private key; the receiver verifies it against a public key you publish in DNS. A valid signature proves two things at once: the message really was handled by the domain in the signature, and the signed parts were not altered in transit.

DKIM is the second leg of the authentication trio we map out in our deliverability handbook, and the counterpart to SPF, which authorizes sending servers by IP. SPF authenticates the connection; DKIM authenticates the message. The distinction sounds academic until a message leaves the original connection behind, at which point SPF has nothing to say and DKIM keeps working.

What the signature actually covers

A common misreading: DKIM does not sign "the email." It signs a hash of the body plus a hash over an explicit list of headers, and only what is listed is protected.

The signer computes a hash of the message body and stores it in the signature's bh= tag. It then builds a second hash over the headers named in the h= tag, in order, with the signature itself appended, and signs that with the private key to produce b=. RFC 6376 requires exactly one header in the list: From. Everything else is the signer's choice, and good signers include Subject, Date, To, and the MIME headers, because an unsigned header can be altered or added in transit without breaking the signature.

Two details worth knowing before you read your first header:

Canonicalization (c=) decides how forgiving verification is about whitespace and header formatting. relaxed/relaxed tolerates the folding and re-wrapping that real mail servers do to messages in flight; simple breaks if a single space changes. Sane platforms default to relaxed/relaxed, and this choice is a big part of why modern DKIM usually survives intermediate hops.

The l= tag limits the body hash to the first N bytes, letting anyone append content to a signed message without invalidating it. It exists for mailing-list compatibility and it is a hole. If your platform sets l=, ask why.

Selectors: what s1._domainkey means

The public key does not live at a fixed address. The signature's s= tag names a selector, and the receiver queries:

<selector>._domainkey.<domain>    TXT

So s=s1 with d=example.com sends the verifier to s1._domainkey.example.com. The names are arbitrary and every platform picks its own convention: Google Workspace uses google, SendGrid uses s1 and s2, Microsoft 365 uses selector1 and selector2. When a provider hands you two or three CNAME records at setup, those are selector records delegating the key lookup to infrastructure they control, which lets them rotate keys without asking you to touch DNS again.

Selectors are the mechanism behind two things you want. First, multiple simultaneous senders: your mail host signs with one selector, your newsletter ESP with another, each verifying against its own key, no coordination required. Second, rotation: publish a new key at a new selector, switch signing to it, and retire the old one later, with zero downtime.

The record itself looks like this (chunked, for reasons in the next section):

s1._domainkey.example.com.  TXT  ( "v=DKIM1; k=rsa; "
    "p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC...IDAQAB" )

The p= value is the base64 public key. An empty p= is the standard way to say a key is revoked.

Key length: 2048 in 2026

Use 2048-bit RSA keys. The floor is 1024: Google's sender guidelines require at least 1024 bits and recommend 2048, and NIST deprecated 1024-bit RSA for signatures back in 2013. RFC 8301 (2018) updated DKIM's algorithm rules to match, requiring verifiers to handle keys from 1024 to 2048 bits and retiring SHA-1 signing outright. In 2026 there is no good reason to generate a new 1024-bit key, and several deliverability platforms now flag them in audits.

One operational consequence of 2048: the base64 public key no longer fits in a single 255-character TXT string, so the record must be split into two quoted strings that resolvers concatenate. Most DNS providers handle the split automatically; a few older panels do not, and the failure is silent, so after publishing, always verify with:

dig +short TXT s1._domainkey.example.com

If the output is empty or visibly truncated, your panel mangled the split.

Rotation: the honest version

M3AAWG (the industry working group on messaging abuse) recommends rotating DKIM keys at least every six months. The honest observation from running mail: most small senders never rotate, and nothing visibly breaks, because a DKIM private key leak is a quiet, low-probability event. That is precisely the argument for making rotation somebody else's job. If your signing runs through a provider that manages keys behind delegated CNAMEs, rotation happens without you. If you hold your own keys, the parallel-selector method is the whole trick: generate a new key, publish it at s2, switch signing to s2, leave s1 published for at least a week so in-flight mail still verifies, then blank its p= value.

How to read a DKIM header

Open any message in Gmail, choose Show original, and find the DKIM-Signature header. A representative one:

DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=example.com; s=s1; t=1718200000;
        h=from:to:subject:date:mime-version:content-type;
        bh=4bRPuiVJrcsFY2Vd8MLtaCvMc3F7dQ38rapUqzHTGjY=;
        b=KxLZY0vN3q...

Read it in this order: d= is the domain claiming responsibility, s= is the selector (so the key is at s1._domainkey.example.com), a= is the algorithm (rsa-sha256 is the modern standard; treat rsa-sha1 as broken), c= is canonicalization, h= is the list of protected headers (check From is there; check Subject is too), bh= is the body hash, and b= is the signature itself. The t= tag is the signing timestamp. Gmail summarizes the verdict at the top of the same view: DKIM: PASS with domain example.com is what healthy looks like.

The d= domain is the one to squint at. A pass means that domain signed the message. It does not mean that domain matches the From address your reader sees.

Why a DKIM pass alone proves little

Any domain can sign any message. A spammer signing with d=spammer-infra.net gets a perfectly valid DKIM pass while displaying your domain in the From line. The pass is real; it just vouches for the wrong party. What closes the gap is alignment, enforced by DMARC: the signature counts only when its d= domain matches the visible From domain. DKIM is the strongest link in the chain, and it still needs the chain; the full picture of how the three records interlock is in our SPF, DKIM, and DMARC overview.

Survivability is what earns DKIM its keep. When Gmail was rejecting 73% of the mail we forwarded to an archive in June 2026, the mechanism was exactly this split: forwarding rewrites the sending IP, so SPF failed on every forwarded message, and only a message with an intact, aligned DKIM signature had any remaining way to pass DMARC. The signature rides inside the message; the connection details do not.

So: confirm every service that sends for you signs with your domain in d=, check the key length on your active selectors with a dig (a p= value around 220 characters is a 1024-bit key worth replacing; around 390 is 2048), and put a note in the calendar to rotate anything you self-manage. Then send yourself a test and read the header you just learned to read.