TL;DR
DKIM (DomainKeys Identified Mail) adds a cryptographic signature to every outgoing email, allowing recipients to verify that the message was authorized by the domain owner and was not tampered with in transit. Defined in RFC 6376, DKIM is the most resilient authentication mechanism in the email stack โ unlike SPF, it survives forwarding. This guide details the signing architecture, dissects every tag in the DKIM-Signature header, compares RSA and Ed25519 algorithms, and covers key rotation, canonicalization, over-signing, and common failure modes.
๐ Table of Contents
- How DKIM Works
- DKIM-Signature Header Anatomy
- The Selector Concept
- RSA vs Ed25519
- Canonicalization: Simple vs Relaxed
- Key Rotation Procedure
- DKIM + DMARC Alignment
- Over-Signing
- Best Practices
- Common Failures
- Tools
- Sources & References
1. How DKIM Works
DKIM uses asymmetric cryptography (public/private key pair) to sign emails. The sending server holds the private key; the public key is published in DNS. When a recipient receives the message, it retrieves the public key and verifies the signature.
Key Generation
The domain owner generates an RSA (or Ed25519) key pair. The private key is installed on the mail server or ESP. The public key is published as a DNS TXT record at selector._domainkey.example.com.
Message Signing
The sending MTA selects headers to sign (e.g., From, To, Subject, Date) and the message body. It canonicalizes them (normalizes whitespace), hashes the result, and encrypts the hash with the private key.
Signature Insertion
The encrypted hash (signature) and metadata are placed in a DKIM-Signature header prepended to the message. This header includes the selector, algorithm, signed headers list, and the base64-encoded signature value.
DNS Lookup
The receiving MTA reads the DKIM-Signature header, extracts the selector (s=) and domain (d=), and queries s._domainkey.d for the public key TXT record.
Verification
The receiver re-canonicalizes the signed headers and body, computes the hash, and uses the public key to decrypt the signature. If the hashes match, the signature is valid โ the message is authentic and unmodified.
DMARC Evaluation
If the d= domain aligns with the From: header domain (relaxed or strict), DMARC considers DKIM as a passing authentication result.
๐ก DKIM does not encrypt the message content. It only provides a digital signature that proves origin and integrity. The message itself is still transmitted in cleartext (unless TLS is used at the transport layer).
2. DKIM-Signature Header Anatomy
Every DKIM-signed message contains a DKIM-Signature header with the following tags:
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=example.com; s=selector1; t=1712880000;
x=1713484800; h=from:to:subject:date:message-id:mime-version;
bh=2jUSOH9NhtVGCQWNr9BrIAPreKQjO6Sn7XIkfJVOzv8=;
b=LjxLMKpHN2kQz... (signature value)
| Tag | Required | Meaning | Values |
|---|---|---|---|
v |
Yes | Version |
1 (always) |
a |
Yes | Signing algorithm |
rsa-sha256, rsa-sha1 (deprecated), ed25519-sha256
|
d |
Yes | Signing domain (DMARC alignment key) | e.g., example.com
|
s |
Yes | Selector (lookup key for public key) | e.g., selector1, google, s1
|
h |
Yes | Signed header fields | Colon-separated list of header names |
b |
Yes | Signature data (base64) | Cryptographic signature value |
bh |
Yes | Body hash (base64) | Hash of the canonicalized body |
c |
No | Canonicalization (header/body) |
simple/simple (default), relaxed/relaxed, relaxed/simple
|
t |
No | Signature timestamp (Unix epoch) | e.g., 1712880000
|
x |
No | Signature expiration (Unix epoch) | e.g., 1713484800
|
l |
No | Body length limit (bytes signed) | Integer โ avoid using |
i |
No | Agent or user identifier | Must be a subdomain of d=
|
q |
No | Query method |
dns/txt (default, only value) |
z |
No | Copied header fields (for diagnostics) | Pipe-separated copies of signed headers |
๐ซ Never use the l= (body length) tag. It tells verifiers to only check the first N bytes of the body, allowing attackers to append malicious content after the signed portion. RFC 6376 ยง8.2 explicitly warns about this vulnerability.
3. The Selector Concept
A selector is a label that lets a single domain have multiple DKIM keys simultaneously โ essential for key rotation and multi-service environments. The public key is published at ._domainkey..
๐ Definition โ A DKIM selector is an arbitrary string chosen by the domain owner that identifies a specific public key record in DNS. It is specified in the s= tag of the DKIM-Signature header and used to construct the DNS query: selector._domainkey.domain.com.
Selectors by Provider
| Provider | Typical Selector(s) | DNS Record Location |
|---|---|---|
| Google Workspace | google |
google._domainkey.example.com |
| Microsoft 365 |
selector1, selector2
|
selector1._domainkey.example.com |
| SendGrid |
s1, s2
|
s1._domainkey.example.com |
| Mailchimp | k1 |
k1._domainkey.example.com |
| Amazon SES | Auto-generated (CNAME-based) | 3 CNAME records per domain |
| Postmark |
20240101 (date-based) |
CNAME to Postmark DNS |
โก Pro Tip: Use descriptive selectors that include the date or purpose: google-2024, marketing-q1. This makes key rotation audits much easier โ you can tell at a glance which keys are current and which are deprecated.
4. RSA vs Ed25519
RFC 8463 (2018) introduced Ed25519 as an alternative to RSA for DKIM signatures. Here's how they compare:
| Property | RSA-SHA256 | Ed25519-SHA256 |
|---|---|---|
| RFC | RFC 6376 | RFC 8463 |
| Key Size | 1024โ4096 bits (2048 recommended) | 256 bits (fixed) |
| Signature Size | ~342 bytes (2048-bit) | 88 bytes (fixed) |
| DNS TXT Record Size | ~400 bytes (2048-bit public key) | ~60 bytes |
| Performance | Slower signing & verification | Significantly faster |
| Security | Secure at 2048+ bits | 128-bit equivalent security |
| Receiver Support | Universal | Growing (Gmail, Fastmail support it) |
๐ฏ Dual-sign with both RSA-2048 and Ed25519. Receivers that support Ed25519 benefit from smaller signatures and faster verification. Receivers that don't will fall back to the RSA signature. Each signature uses a different selector.
โ ๏ธ 1024-bit RSA keys are deprecated. RFC 8301 (2018) requires a minimum of 2048 bits for RSA DKIM keys. Some receivers (notably Gmail) will reject 1024-bit signatures. Rotate immediately if you're still using 1024-bit keys.
5. Canonicalization: Simple vs Relaxed
Canonicalization normalizes the message before hashing to tolerate minor modifications by intermediate mail servers. The c= tag specifies the algorithm for headers and body separately (e.g., c=relaxed/relaxed).
| Mode | Headers | Body |
|---|---|---|
| Simple | No changes โ headers must be byte-identical | Trailing empty lines removed; no other changes |
| Relaxed | Header names lowercased; whitespace folding normalized; trailing whitespace removed | Whitespace sequences reduced to single space; trailing whitespace on lines removed; trailing empty lines removed |
# simple/simple โ very strict, breaks easily:
Subject: Hello World โ exact bytes must match
# relaxed/relaxed โ tolerant of whitespace changes:
Subject:Hello World โ extra spaces and case changes are normalized
subject: hello world โ both canonicalize to the same form
โก Pro Tip: Always use c=relaxed/relaxed. Intermediate servers (mailing lists, forwarding services, antivirus gateways) frequently modify whitespace. Simple canonicalization causes unnecessary DKIM failures in real-world mail flows.
6. Key Rotation Procedure
DKIM keys should be rotated periodically (every 6โ12 months) to limit exposure if a private key is compromised. The selector mechanism makes zero-downtime rotation straightforward.
Generate new key pair
Create a new RSA-2048 or Ed25519 key pair with a new selector (e.g., dkim-202604).
Publish new public key
Add the new TXT record at dkim-202604._domainkey.example.com. Wait for DNS propagation (TTL).
Switch signing to new selector
Configure your MTA/ESP to sign outgoing mail with the new private key and selector.
Monitor for failures
Watch DMARC reports and DKIM verification headers for a few days. Ensure the new key passes.
Revoke old key
After the overlap period (1โ2 weeks), publish an empty p= tag for the old selector: v=DKIM1; p=. This tells receivers the key is revoked.
Remove old DNS record
After another TTL cycle, delete the old selector's DNS record entirely.
๐ก An empty p= tag in a DKIM DNS record (RFC 6376 ยง3.6.1) is the official revocation signal. It tells verifiers that the key has been deliberately revoked, as opposed to a missing record which could be a DNS failure.
7. DKIM + DMARC Alignment
For DMARC to consider DKIM as a passing result, two conditions must be met:
DKIM signature must verify (valid cryptographic signature).
The
d=domain must align with theFrom:header domain.
| Scenario | DKIM d=
|
From Header | DMARC adkim
|
Aligned? |
|---|---|---|---|---|
| Exact match | example.com |
user@example.com |
Any | Yes |
| Subdomain (relaxed) | mail.example.com |
user@example.com |
r |
Yes |
| Subdomain (strict) | mail.example.com |
user@example.com |
s |
No |
| Third-party domain | sendgrid.net |
user@example.com |
Any | No |
โ ๏ธ Many ESPs sign with d=esp-domain.com by default. You must configure custom DKIM signing so the d= tag uses your domain (or a subdomain of it in relaxed mode) for DMARC alignment to work.
8. Over-Signing
๐ Definition โ Over-signing is a DKIM best practice where the h= tag includes headers that are not present in the message (e.g., listing Reply-To twice). This prevents attackers from adding a spoofed Reply-To header after signing โ any addition would invalidate the signature.
# Over-signing example: listing headers that don't exist in the message
h=from:to:subject:date:reply-to:reply-to:cc:cc
# "reply-to" is listed twice:
# First instance covers the actual Reply-To header (if present)
# Second instance "seals" the slot โ adding a new Reply-To breaks the signature
๐ฏ Over-sign these headers at minimum: From, To, Subject, Date, Reply-To, CC, Content-Type, MIME-Version, Message-ID. Over-signing prevents post-signature header injection attacks.
9. Best Practices
Use 2048-bit RSA minimum
1024-bit keys are deprecated (RFC 8301). Generate 2048-bit keys for all selectors.
Use relaxed/relaxed canonicalization
Simple canonicalization fails too easily with intermediate MTAs. Relaxed is the industry standard.
Sign with your domain
Ensure the d= tag matches your From: domain for DMARC alignment. Configure custom DKIM on every ESP.
Rotate keys every 6โ12 months
Use the selector system for zero-downtime rotation. Revoke old keys with an empty p= tag.
Over-sign critical headers
List From, Reply-To, Subject, and CC twice in the h= tag to prevent header injection.
Never use the l= tag
Body length limits allow content to be appended to signed messages. Always sign the full body.
10. Common Failures
๐ซ DNS record not found. The most common DKIM failure. Usually caused by a typo in the selector name, missing CNAME, or DNS propagation delay. Always verify with dig TXT selector._domainkey.example.com.
๐ซ Body hash mismatch (bh= tag). The body was modified after signing โ typically by a mailing list, antivirus gateway, or footer-appending service. Use relaxed body canonicalization and investigate the specific MTAs in the delivery chain.
โ ๏ธ Key too short. 512-bit and 1024-bit RSA keys are rejected by many receivers. Gmail logs dkim=neutral (body hash did not verify) for weak keys even when the signature is mathematically valid.
โ ๏ธ Expired signature. If the x= tag is set and the current time exceeds it, the signature is treated as invalid. Use generous expiration windows (7+ days) or omit x= entirely.
โ ๏ธ Testing with email headers. To debug DKIM, view the full message headers and look for Authentication-Results. Gmail shows dkim=pass, dkim=fail, or dkim=neutral with a reason string.
# Gmail Authentication-Results header example:
Authentication-Results: mx.google.com;
dkim=pass header.i=@example.com header.s=selector1 header.b=LjxLMKpH;
spf=pass (google.com: domain of user@example.com designates 198.51.100.42 as permitted sender);
dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=example.com
11. Tools
| Tool | Purpose |
|---|---|
| DKIM Record Checker | Look up any selector's public key and validate record syntax |
12. Sources & References
๐ RFC 6376 โ DomainKeys Identified Mail (DKIM) Signatures
๐ RFC 8463 โ A New Cryptographic Signature Method for DKIM (Ed25519-SHA256)
๐ RFC 8301 โ Cryptographic Algorithm and Key Usage Update to DKIM
๐ RFC 7489 โ DMARC
๐ Google Workspace โ Turn on DKIM signing
๐ Microsoft 365 โ Use DKIM to validate outbound email
๐ Cloudflare โ What is a DKIM record?
๐ M3AAWG โ Best Practices (includes DKIM guidance)
๐ฏ Key Takeaway: DKIM is the most durable email authentication mechanism โ it survives forwarding, validates message integrity, and provides the preferred alignment path for DMARC. Use 2048-bit RSA or Ed25519, always choose relaxed/relaxed canonicalization, sign with your own domain for DMARC alignment, over-sign critical headers, rotate keys every 6โ12 months, and never use the l= body length tag.
Originally published on StarNomina ToolBox. Try our free online tools โ no signup required.
Top comments (0)