DKIM: a signature on every message, and a selector to find the key.
DKIM lets a domain sign the mail it sends so a receiver can check that the message really came from that domain and was not altered on the way. The signature travels in a header; the public key sits in DNS at a name built from the selector and the domain. This page explains the mechanism and the selector. The record-by-record setup is on the SPF, DKIM and DMARC page.
How a signature is made and checked.
When a message leaves the sending service, the signer picks a set of headers to cover (at least From), normalises them and the body so harmless changes in transit do not break the check, hashes the body, and signs the headers plus that body hash with a private key. The result is a DKIM-Signature header added to the message. Nothing about the message itself is encrypted; the signature only proves two things, that the holder of the private key sent it and that the covered parts arrived unchanged.
The receiver reads two tags from that header, the signing domain in d= and the selector in s=, and asks DNS for a TXT record at <selector>._domainkey.<domain>. That record carries the public key in its p= tag. The receiver recomputes the body hash, verifies the signature with the public key, and records the outcome in an Authentication-Results header. An empty p= means the key has been revoked.
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=acme.com;
s=notix; t=1757721600;
h=from:to:subject:date:message-id:mime-version:content-type;
bh=frcCV1k9oG9oKj3dpUqdJg1PxRT2RSN/XKdLCPjaYaY=;
b=dzdVyOfAKCdLXdJOc9G2q8LoXSlEniSbav+yuU4zGeeruD00lszZVoG4ZHRNiYzR...
$ dig +short TXT notix._domainkey.acme.com
"p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC..."
The tags in the header.
| Tag | Status | Meaning |
|---|---|---|
v=1 | Required | The DKIM version. Always 1. |
a=rsa-sha256 | Required | The signing algorithm. rsa-sha1 is no longer allowed for signing or verifying. |
d=acme.com | Required | The signing domain: who is taking responsibility for the message. DMARC compares this to the From domain. |
s=notix | Required | The selector: which public key under the domain to fetch. Combined with d= it names the DNS record. |
h=from:to:subject:date | Required | The header fields covered by the signature, in the order they were hashed. |
bh= | Required | The hash of the canonicalised body. |
b= | Required | The signature itself, base64, over the selected headers and the body hash. |
c=relaxed/relaxed | Optional | Header and body canonicalisation. Defaults to simple/simple; relaxed survives whitespace changes in transit. |
t= and x= | Recommended | When the signature was made and when it expires, as Unix timestamps. |
i= | Optional | The agent or user the signer is signing for. Defaults to @ plus the d= domain. |
What the selector is for.
A domain has one name but can have many keys. The selector is the part of the DNS name that says which one. Without it, a domain could publish exactly one DKIM key, and every service that sends on its behalf would have to share the private half of it. With it, each sender publishes its own key under its own selector: your application mail through Notix under notix, your Google Workspace under google, a marketing tool under whatever it chooses. Each signs with a key only it holds, and a receiver checks each signature against the right record.
The selector is also how keys are rotated. Publish the new key under a new selector, switch the signer to it, leave the old record in place until mail signed with the old key has stopped arriving, then remove it. RFC 6376 warns against reusing a selector for a new key: once the old record is gone, a receiver cannot tell a legitimate message signed last week from a forged one, because both now fail the same way.
The Notix record.
When you add a domain, Notix generates an RSA key pair, keeps the private key with the sending infrastructure and shows you the public key to publish. The selector is notix. The record is a TXT at notix._domainkey on the domain you verified, and its value is p= followed by the public key. Verify a subdomain such as mail.acme.com and the record moves with it, to notix._domainkey.mail.acme.com; the dashboard shows the full name either way, and the DKIM row turns green once the record has propagated and been checked. Keys are 1024-bit RSA, which is the minimum RFC 8301 allows a signer to use and the minimum every verifier must accept; 2048 bits is the RFC's recommendation for new keys, and a key of either length verifies at every major mailbox provider today.
Alignment: the part DMARC cares about.
A valid signature proves the d= domain signed the message. It does not on its own prove that the address the reader sees in From is honest, because any domain can sign any message. DMARC closes that gap with alignment: a DKIM pass only counts for DMARC when the d= domain and the From domain match. In relaxed mode, the default, they need only share an organisational domain, so d=acme.com aligns with alerts@news.acme.com. In strict mode, set with adkim=s, the two must be identical. This is why a provider signing with its own domain gives you a DKIM pass and a DMARC failure at the same time, and why verifying your own domain is not optional if you publish a DMARC policy. The record options are on the DMARC page.
Reading the result.
Every large mailbox provider writes what it found into an Authentication-Results header you can read by viewing the original message. The DKIM part names the selector and signing domain it checked and gives a verdict; a failure usually carries a reason.
Authentication-Results: mx.google.com;
dkim=pass header.i=@acme.com header.s=notix header.b=dzdVyOfA;
spf=pass (google.com: domain of bounce@mail.acme.com designates ...) ...;
dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=acme.com
Authentication-Results: mx.google.com;
dkim=fail (body hash did not verify) header.i=@acme.com header.s=notix;
...
dkim=pass with dmarc=pass is the outcome you want. dkim=fail (body hash did not verify) means the message was changed after signing, most often by a forwarder or a gateway rewriting links. dkim=neutral or permerror with a note about the key usually means the DNS record is missing, has a typo in the name, or was published under a different selector from the one the signer uses. dkim=pass with dmarc=fail is the alignment problem above.
Rotation and hygiene.
Rotate keys on a schedule and immediately if a private key may have leaked. Use a fresh selector each time. Keep only the selectors that are still in use published; a stale record with a key nobody signs with is harmless, but a stale record with a key that was compromised is a forgery kit. Sign with rsa-sha256; rsa-sha1 has been forbidden since RFC 8301. And if a rotation ever changes the Notix record, the dashboard shows the new value and the DKIM status returns to pending until the new record is found.
Questions, answered.
What is a DKIM selector?
Where do I put the DKIM record?
Why does each sending service need its own selector?
What key size should a DKIM key be?
What is DKIM alignment, and why does DMARC care?
Why does my DKIM signature pass at the sender but fail at the receiver?
Keep reading.
Set up SPF, DKIM and DMARC
The three DNS records a sending domain needs, what each one proves, and the one-click path when your DNS provider supports Domain Connect.
LearnSPF records for transactional email
What an SPF record says, the include for a sending service, the ten-lookup limit and how to stay under it.
LearnDMARC record examples
Records for p=none, quarantine and reject, what alignment means, and how to read the aggregate reports before tightening.
ProductTransactional email API
OTPs, receipts and alerts with idempotency keys, a deliverability pre-check and a shared suppression list.
NotixDocs
The quickstart: verify a domain, copy an API key, send the first email.
Verify a domain and the record is written for you.
Add the domain, copy the TXT record the dashboard shows, and DKIM turns green when it propagates. Domain Connect providers get one click.