DKIM in practice: selectors, keys and services
Module 4: Deliverability: SPF, DKIM and DMARC in practice · Reading time: 12 minutes
Learning objective: After this lesson you can parse a DKIM-Signature header, set up DKIM with your own domain for any sending service, check whether a selector works, and explain how to replace keys safely.
Key concepts: DKIM-Signature, d= (signing domain), s= (selector), h= (signed headers), bh= and b=, canonicalisation (c=), <selector>._domainkey.<domain>, TXT with p= or CNAME to the service, key length 2048 bit (RFC 8301), chunks of 255 characters, ed25519 (RFC 8463), key rotation, empty p= (revoked), DKIM and forwarding
Why DKIM is the most important of the three
SPF says which servers are allowed to send mail, but it breaks on forwarding and looks at the Return-Path, which for many services isn't yours. DKIM puts a signature inside the message itself. That signature survives forwarding (as long as the message isn't changed) and is tied to a domain that you choose. That's why, in practice, DKIM is often the only thing that makes DMARC pass for newsletters, invoices from accounting software, and forwarded mail.
The basics (how the key sits in DNS, what a selector is) are covered in the DNS course, lesson 4.4. Here we go further: what exactly is in a signature, and how do you set up DKIM for each service?
Parsing a signature
Open the headers of an email you've received (lesson 1.5). At the top, if the message is signed, you'll see something like:
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=example.com; s=x;
t=1762588800; h=from:to:subject:date:message-id:mime-version:content-type;
bh=2jUSOH9NhtVGCQWNr9BrIAPreKQjO6Sn7XIkfJVOzv8=;
b=Gm7yW3q...long string of characters...Qx9A==| Tag | Meaning |
|---|---|
v=1 | DKIM version |
a=rsa-sha256 | Algorithm: RSA key, SHA-256. Also possible: ed25519-sha256 |
c=relaxed/relaxed | Canonicalisation: how strictly minor changes (spaces, capitalisation in header names) are treated, for the headers and the body. relaxed is common and more forgiving than simple |
d=example.com | The signing domain. This domain vouches for the message. DMARC compares this with the From address |
s=x | The selector: which key of that domain was used |
t= | Time of signing (seconds since 1970) |
h= | Which headers are signed. from must always be included |
bh= | A fingerprint (hash) of the message body |
b= | The signature itself |
The recipient fetches the public key from <s>._domainkey.<d>, in this case x._domainkey.example.com, and checks whether b= matches the headers from h= and the fingerprint bh=. If a single letter changes along the way, in the body or in a signed header, the check fails.
In Authentication-Results you'll see the outcome, for example dkim=pass header.d=example.com header.s=x. A message can carry several signatures, for instance one from your domain and one from the service itself. For DMARC, only a signature whose d= matches your From domain counts.
Every service gets its own selector
A domain can have many DKIM keys at the same time, each under its own selector. That's exactly the point: every service that sends mail on your behalf signs with its own key.
| Sender | Selector (example) | How it appears in DNS |
|---|---|---|
| Hosting mail server | x or default | TXT with the key, created by the panel |
| Microsoft 365 | selector1, selector2 | two CNAME records pointing to Microsoft |
| Google Workspace | google (default) | TXT with a key you generate in the admin console |
| Newsletter service | for example k2, k3, mte1 | usually CNAME records pointing to the service |
TXT or CNAME?
- With a TXT record, you place the public key in your DNS yourself. If the service wants a new key, you have to update the record.
- With a CNAME record, you point the selector to a name at the service, for example
k2._domainkey.example.com CNAME dkim2.mailer.example.The service then manages the key itself and can replace it without you having to do anything. That's why large services opt for CNAME, often using two of them, so they can switch between an active key and a new one.
Note: a CNAME can't sit alongside another record on the same name. If there's already a TXT on selector1._domainkey, remove it first.
The most important step: turning DKIM on at the service
With many services, DKIM with your own domain is not switched on by default. They then sign with their own domain (d=mailer.example). The message is signed, but it isn't aligned with your From address. For DMARC, that doesn't count. In the service's settings, this is often called "verify domain", "domain verification", "authentication", or "custom sending domain". Only once you've added the records and switched it on in the service will it sign with d=example.com.
Keys: length, chunks and algorithm
- Length. RFC 8301 says: at least 1024 bit, and senders should use at least 2048 bit. Use 2048. A key of 512 bit is treated as invalid by recipients.
- Chunks of 255 characters. A TXT record consists of strings of at most 255 characters. A 2048-bit key is roughly 400 characters and won't fit in one string. The record then consists of two or more strings placed one after another (
"v=DKIM1; k=rsa; p=MIIBIj..." "...IDAQAB"), which the recipient joins together. Most panels do this automatically. If it goes wrong, you get a truncated key and every signature fails. So always copy a key in full, without extra spaces or quotation marks in the middle. - ed25519 (RFC 8463) is a more modern algorithm with short keys. Not all recipients check it yet. Those who use it therefore sign with two signatures: an RSA one and an ed25519 one.
Replacing a key
It's good practice to replace a key now and then, and certainly if you suspect the private key has leaked (for example after a server breach or a departing administrator). Do it like this:
- Create a new key under a new selector, for example
s2026, and put the public key in DNS. - Wait until the record is visible everywhere (the TTL, see DNS course lesson 6.1).
- Have the server sign with the new selector.
- Leave the old key in place for a few more days: mail that was already in transit or gets checked again will still refer to it.
- Revoke the old key by emptying
p=(v=DKIM1; p=), or remove the record.
With services using CNAME records, the service does this for you.
What makes DKIM fail
- The message is altered in transit: a mailing list that adds
[listname]to the subject or appends a footer, a virus scanner that adds a line beneath the message, a forwarding server that converts the formatting. - Wrong or truncated key in DNS.
- Selector doesn't exist: a typo in the name, or
selector1._domainkey.example.com.example.com(the domain name doubled, because the panel already appends it itself). - Key revoked (empty
p=) while the server still signs with that selector.
Checking whether it works
- Send a message from the service to an address at Gmail or Outlook.com.
- Open the headers and find the
DKIM-Signature: note downd=ands=. - Check
Authentication-Resultsfordkim=pass, and whetherheader.d=is your domain. - Look up the selector:
dig TXT s._domainkey.example.com(or with an online tool). There should be ap=with a long key, or a CNAME leading to such a record.
In practice: what this looks like in a panel
With a WebOké hosting package, DKIM is switched on by default, using the selector x: the record is called x._domainkey.<yourdomain>. In DirectAdmin you'll find it under DNS Administration; if your DNS is hosted elsewhere, copy that record over there. In My WebOké, the Set E-mail card shows which value is expected and whether it's found. With other providers the selector has a different name (default, mail, dkim), but you find it the same way: in the panel, or in the s= of a signed message.
Summary
- DKIM is the check that survives forwarding and that you link to your own domain per service; for DMARC, only a signature with your domain in
d=counts. - In the
DKIM-Signatureyou'll findd=(domain) ands=(selector); the key sits at<s>._domainkey.<d>. - Every service gets its own selector; CNAME records let the service replace keys itself. Make sure you actually switch on DKIM with your own domain in the service.
- Use 2048 bit; watch out for truncated keys when copying.
- Replace a key with a new selector and only revoke the old one afterwards.
Quiz
Exercise
Exercise Z4.3: Checking a DKIM selector. Send a message from your own domain (or from a service that sends on your behalf) to an address of your own at a different provider. Open the headers and enter the values of d= and s= from the DKIM-Signature, and what Authentication-Results shows for dkim=. The program looks up the selector live, follows any CNAME, checks the key (present, not empty, length) and tells you whether d= is aligned with the domain you give as sender.
Further reading
The steps in these articles apply to WebOké panels; with other providers the process is similar.
- Free DNS course 4.4: DKIM: the signature under your mail
- DirectAdmin guide 5.8: Turning on and checking DKIM
- Setting up DKIM when DNS is hosted on an external server
- WebOké manual 6.7: The Set up email card (MX, SPF, DKIM, DMARC)
- RFC 6376 (DKIM), RFC 8301 (key length and algorithms), RFC 8463 (ed25519)
