DKIM setup means generating a key pair with your sending service, publishing the public key as a TXT or CNAME record at selector._domainkey.yourdomain, and then switching signing on. Use 2048-bit RSA where your DNS host allows it, give every sending service its own selector, and check that the signature's d= domain is yours.
A DKIM key with a typo in it fails quietly. Mail still goes out, most of it still reaches the inbox, and nothing looks wrong until the day you move DMARC to reject and the accounting system’s invoices vanish. A few extra minutes of checking during DKIM setup saves that afternoon.
How DKIM works
DomainKeys Identified Mail, specified in RFC 6376, adds a cryptographic signature to outgoing mail. The signature lives in a DKIM-Signature header and covers the body plus a chosen list of headers, typically From, To, Subject, Date and Message-ID. Receivers read two fields from it, the signing domain d= and the selector s=, and use them to fetch the public key from DNS:
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=example.com; s=s2026;
h=from:to:subject:date:message-id; bh=…; b=…
Here the receiver looks up s2026._domainkey.example.com. If the signature checks out, it knows two things: someone with the private key sent the message, and the signed parts were not changed in transit.
Unlike SPF, DKIM usually survives forwarding, because the signature travels with the message. It does break when a mailing list rewrites the subject line or appends a footer.
One selector per service
There is no rule that a domain needs a single key. The opposite works better: give every sender its own selector.
| Service | Selector | Record type |
|---|---|---|
| Google Workspace | google (default) | TXT, key generated in the Admin console |
| Microsoft 365 | selector1, selector2 | CNAME to a Microsoft-hosted record |
| Typical ESP (newsletter, transactional) | set by the vendor | usually CNAME |
| Your own Postfix with OpenDKIM or rspamd | your choice, e.g. s2026 | TXT |
When you drop a vendor, you delete its record and nothing else is affected. With CNAME-based setups the vendor hosts the actual key and can rotate it without you touching DNS. That is the main reason many providers prefer CNAMEs.
Key length: why 2048 bits
RFC 8301 says signers must use RSA keys of at least 1024 bits and should use at least 2048. Google’s Gmail sender guidelines say the same: 1024 minimum, 2048 recommended if your DNS provider can handle it.
The catch is size. A 2048-bit public key is close to 400 characters of base64, and a single TXT string tops out at 255. The record therefore gets split into two strings that receivers join back together:
s2026._domainkey.example.com. 3600 IN TXT ( "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu3x…"
"…kQIDAQAB" )
Decent DNS panels split automatically. A few older ones truncate instead, which breaks every signature. A quick sanity check: an RSA public key with the usual exponent 65537 ends in IDAQAB. If yours doesn’t, something got cut off.
Ed25519 keys (RFC 8463) are far shorter, but not every receiver verifies them. If you use Ed25519, sign with RSA as well.
Generating a key on your own server
Hosted services do this behind a button. On a self-run server, generate the pair yourself:
openssl genrsa -out s2026.private 2048
openssl rsa -in s2026.private -pubout -outform der 2>/dev/null | openssl base64 -A
The second command prints the public key as one long base64 line. That goes after p= in the TXT record. The private key stays readable only by the signing daemon’s user.
Then confirm the record is visible:
$ dig +short TXT s2026._domainkey.example.com
"v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu3x…" "…kQIDAQAB"
An empty p= means the key has been revoked. Some domains publish that on purpose. The real example.com answers every selector this way, which is a neat pattern for domains that should never send mail:
$ dig +short TXT google._domainkey.example.com
"v=DKIM1; p="
Reading the result in a real message
Send a test to a Gmail or Outlook.com address and open the raw source (in Gmail: the three-dot menu, then Show original). The line that matters is Authentication-Results:
Authentication-Results: mx.google.com;
dkim=pass [email protected] header.s=s2026 header.b=Ab3xY9…;
spf=pass (google.com: domain of [email protected] designates 198.51.100.25 as permitted sender);
dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=example.com
If header.i or header.d shows the vendor’s domain instead of yours, the vendor is still signing with its own key. That passes DKIM but does nothing for DMARC. Nearly every platform has a setting called something like “authenticate your domain” or “custom sending domain”.
Errors you will actually see
| Result | Usual cause |
|---|---|
dkim=neutral (body hash did not verify) | Something modified the body after signing, often a disclaimer or scanning gateway |
dkim=temperror / no key for signature | Record missing or not yet propagated; signing switched on too early |
dkim=fail (bad signature) | Truncated key, stray line break or wrong key pasted |
dkim=pass with vendor’s d= | Custom domain authentication not set up |
DKIM alone does not tell receivers what to do with unsigned or failing mail. That policy comes from DMARC, covered in DMARC setup. The list of permitted sending servers is the job of SPF record setup.
Rotating keys without downtime
Selectors make rotation boring, which is what you want. Publish a new selector (s2027), wait for the TTL to pass, switch the signer to it, and leave the old record in place for a week, since messages can sit in queues or be re-verified later. Then set the old key to p= or delete it.
All of this happens in your DNS zone. If your domain currently lives inside a web hosting bundle that won’t let you add TXT records or CNAMEs, that is a good reason to move it. At betadomain you can check whether your name is available and compare renewal prices across every extension; the .co.uk page shows €15.99 a year if you are UK-based. Once signing works, the bigger picture of locking down your domain is in prevent email spoofing.
Step by step
- Pick a selector per senderAssign each service that sends as your domain its own selector, or use the one the provider dictates, such as google for Google Workspace or selector1 and selector2 for Microsoft 365.
- Generate the keyLet the service generate a 2048-bit key. On your own server, create one with openssl genrsa and export the public half as base64.
- Publish the DNS recordCreate a TXT record at selector._domainkey.yourdomain with v=DKIM1; k=rsa; p=…, or the CNAME your provider specifies.
- Turn on signingEnable signing only after the record resolves publicly. Check it first with dig +short TXT selector._domainkey.yourdomain.
- Inspect a test messageSend a message to an external mailbox and look for dkim=pass header.d=yourdomain in Authentication-Results. A vendor domain there means alignment is still missing.
Found your domain? You can check and register it directly at domain registration without teaser pricing – yearly price from €2.99.
FAQ
What is a DKIM selector?
A selector is a label you choose that tells receivers where to find a particular public key, for example google or s1. It appears as s= in every DKIM-Signature header. Selectors let one domain run many keys side by side, one per service.
Is a 1024-bit DKIM key still acceptable?
It still verifies, and RFC 8301 sets 1024 bits as the floor. The same RFC says signers should use 2048 bits, and Google recommends 2048 for Gmail if your DNS provider supports long records. For a new setup there is no reason to go shorter.
How often should I rotate DKIM keys?
No standard forces a schedule. Rotating every six to twelve months is common practice, and immediately if a private key may have leaked. With a second selector you can rotate without any gap in signing.
Gmail shows dkim=pass but DMARC fails. Why?
The service is probably signing with its own domain, so d= is the vendor's domain rather than yours. DMARC requires the signing domain to align with the From domain. Look for a custom or authenticated sending domain option in the service.