What DKIM signs and what it does not protect
DomainKeys Identified Mail (DKIM) lets a sending mail server attach a cryptographic signature to outgoing messages. The signature covers a defined set of message headers and the body, allowing the receiving server to verify that the signed content was not altered in transit.
A DKIM signature typically covers these headers: From, To, Subject, Date, MIME-Version, and Content-Type. The DKIM-Signature header itself specifies which headers were signed in its h= tag. The body is hashed and included in the bh= tag.
DKIM does not protect:
- Envelope sender -- the SMTP
MAIL FROMaddress is outside the DKIM scope. SPF covers that. - Unsigned headers -- any header not listed in the
h=tag can be modified or added by intermediaries without breaking the signature. - Message confidentiality -- DKIM provides integrity and authentication, not encryption. The message content is still visible to any relay.
- Replay attacks -- a valid DKIM-signed message can be resent by anyone. DKIM proves the original domain signed it, but not that the current sender is authorized.
DKIM's primary value is in combination with DMARC: it provides a forwarding-resistant authentication mechanism. Unlike SPF, which breaks when messages are forwarded through intermediate servers, DKIM signatures travel with the message and remain valid as long as the signed content is unchanged.
Key types: RSA vs Ed25519
DKIM supports two key algorithms: RSA and Ed25519 (RFC 8463). The choice affects key size, DNS record length, and security margin.
RSA keys
RSA is the original and most widely supported DKIM key type. Three key sizes are in common use:
- 1024-bit RSA -- the historical default. Still accepted by most receivers, but considered weak by modern standards. NIST deprecated 1024-bit RSA in 2013. Some DKIM validators will flag it as a warning.
- 2048-bit RSA -- the current recommended minimum. Provides adequate security margin for the foreseeable future and is supported by all major email providers. This is what you should use if you only deploy one key type.
- 4096-bit RSA -- offers a larger security margin but creates DNS TXT records that exceed 255 bytes, requiring the record to be split into multiple strings. Some DNS providers and resolvers mishandle multi-string TXT records, which can cause verification failures. Avoid 4096-bit unless you have confirmed your DNS infrastructure handles it correctly.
Ed25519 keys
Ed25519 (Edwards-curve Digital Signature Algorithm) uses elliptic-curve cryptography. The public key is only 44 bytes in base64, making the DNS record trivially small. Ed25519 is faster to sign and verify than RSA, and 256-bit Ed25519 provides security roughly equivalent to 3072-bit RSA.
The downside is compatibility: not all mail servers and validators support Ed25519 yet. If you deploy Ed25519 as your only DKIM key, some receivers will fail to validate the signature. The recommended approach is to dual-sign: configure your mail server to produce both an RSA and an Ed25519 signature on each message. Receivers that support Ed25519 will verify the stronger key; others will fall back to RSA.
Recommendation
Deploy 2048-bit RSA as your baseline. If your mail server supports dual-signing (Postfix 3.6+, Stalwart, some hosted providers), add Ed25519 as a second selector. Do not deploy Ed25519 as the sole key unless you have confirmed all your recipients' mail servers support it.
Selector naming conventions
A DKIM selector is the label used to locate the public key in DNS. The full DNS name is <selector>._domainkey.<domain>. Selectors are arbitrary strings, but consistent naming conventions make key management significantly easier.
Common naming strategies:
- Date-based:
202604,2026q2-- encode the deployment date or quarter. Makes it obvious when a key was created and when it should be rotated. - Provider-based:
google,sendgrid,mailchimp-- identify which system uses this key. Useful for organizations with multiple sending services, each needing its own DKIM key. - Combined:
google-202604,ses-2026q2-- both provider and date. This is the most informative convention and scales well as the number of senders and rotation cycles grows. - Sequential:
s1,s2,selector1,selector2-- simple but provides no context about age or purpose. Microsoft 365 usesselector1/selector2by convention.
Avoid selectors that contain sensitive information (internal hostnames, environment names). Selectors are publicly visible in DNS and in every message's DKIM-Signature header.
Key rotation strategy
DKIM keys should be rotated periodically to limit the impact of key compromise. A compromised private key allows an attacker to sign messages as your domain until the key is revoked. Rotation every 6-12 months is a reasonable cadence for most organizations.
The rotation process must be phased to avoid breaking signature validation during the transition:
- Generate a new key pair and choose a new selector name (e.g.,
202610to replace202604). - Publish the new public key in DNS under the new selector. Verify that the DNS record is resolvable from external resolvers before proceeding. Allow at least 24-48 hours for DNS propagation if your TTL is high.
- Configure the mail server to sign with the new selector. At this point, outgoing messages use the new key. Both old and new public keys should remain in DNS.
- Wait for the old key's message lifetime to expire. Messages signed with the old key may still be in transit or queued. Wait at least 7 days (longer if your retry window is extended) before removing the old key.
- Revoke the old key by publishing an empty key record:
old-selector._domainkey.example.com. IN TXT "v=DKIM1; p=". This explicitly tells validators that the key is revoked, rather than leaving them to guess whether a missing record is a DNS error.
If you use DMARC forensic reporting (ruf=), update the reporting address before revoking the old key so you can monitor for any lingering failures.
Practical examples
Generate a 2048-bit RSA key pair
# Generate private key
openssl genrsa -out dkim-202604.private 2048
# Extract public key in DNS-compatible format
openssl rsa -in dkim-202604.private -pubout -outform PEM \
| grep -v '^-' | tr -d '\n'
The output is a base64-encoded public key. This value goes into the p= tag of the DNS record.
Generate an Ed25519 key pair
# Generate Ed25519 private key
openssl genpkey -algorithm ed25519 -out dkim-ed25519.private
# Extract public key
openssl pkey -in dkim-ed25519.private -pubout -outform PEM \
| grep -v '^-' | tr -d '\n'
DNS TXT record format
Publish the public key under the selector subdomain. For selector 202604 on example.com:
202604._domainkey.example.com. IN TXT "v=DKIM1; k=rsa; p=MIIBIjANBgkqhki..."
For Ed25519:
ed202604._domainkey.example.com. IN TXT "v=DKIM1; k=ed25519; p=MCowBQYDK2Vw..."
Tags in the DKIM DNS record:
v=DKIM1-- version (required)k=rsaork=ed25519-- key type (default isrsaif omitted)p=-- base64-encoded public key (required; empty value means revoked)t=s-- optional; strict mode, requires exact domain match (no subdomain signing)t=y-- optional; testing mode, receivers should not treat failures as definitive
Test a DKIM record with dig
# Look up the DKIM public key for selector "202604" on example.com
dig +short TXT 202604._domainkey.example.com
# Expected output (truncated):
# "v=DKIM1; k=rsa; p=MIIBIjANBgkqhki..."
If the query returns no result, the selector may be wrong, the record may not have propagated, or the domain may not have DKIM configured for that selector. Try common selectors like google, selector1, selector2, s1, or default.
Verify the DKIM-Signature header
When you receive a message, the DKIM-Signature header shows the selector and domain used:
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=example.com; s=202604; t=1712678400;
h=from:to:subject:date:mime-version:content-type;
bh=abc123...=;
b=xyz789...=
Key fields: d= is the signing domain, s= is the selector, a= is the algorithm, h= lists signed headers, bh= is the body hash, and b= is the signature.