Loading learning content...
SPF answers the question: 'Is this IP address allowed to send mail for this domain?'
But SPF has a fundamental blind spot: it says nothing about the message itself. A message could be intercepted and modified after passing SPF validation. A message could be forwarded legitimately, breaking SPF while remaining genuine. SPF alone provides sender IP authorization, not message authentication.
DKIM (DomainKeys Identified Mail) fills this gap through public-key cryptography. The sending domain cryptographically signs outgoing messages, and receiving servers verify these signatures against public keys published in DNS.
Defined in RFC 6376, DKIM provides:
DKIM is deployed on approximately 70% of email-sending domains, though proper configuration varies widely. Understanding DKIM is essential for any professional working with email infrastructure.
By the end of this page, you will understand DKIM's cryptographic foundations, signing and verification processes, key management practices, header structure, failure modes, and integration with SPF and DMARC. You'll be able to configure DKIM for mail servers, interpret signature headers, and troubleshoot verification failures.
DKIM leverages asymmetric (public-key) cryptography to authenticate email messages. If you're unfamiliar with public-key concepts, here's the essential background:
Private Key: Kept secret by the sending domain. Used to create digital signatures.
Public Key: Published openly (in DNS). Used by anyone to verify signatures.
The Fundamental Property: Data signed with the private key can only be verified with the corresponding public key—and possessing the public key doesn't allow creating new valid signatures.
SPF and DKIM solve different problems. SPF validates the sending IP (network-level). DKIM validates the message content (application-level). An attacker might pass SPF by sending from an authorized IP while modifying message content—DKIM would catch this. Conversely, a legitimately forwarded message might fail SPF but pass DKIM. Together, they provide defense in depth.
When a mail server signs a message with DKIM, it performs a precise sequence of operations to create a verifiable signature.
Email messages often get slightly modified in transit (whitespace changes, line wrapping, header folding). To ensure signatures remain valid despite these minor changes, DKIM defines canonicalization algorithms that normalize the message before signing/verification.
Header Canonicalization:
simple: Headers signed exactly as-isrelaxed: Convert header names to lowercase, collapse whitespace sequences to single space, remove trailing whitespaceBody Canonicalization:
simple: Body signed exactly as-is (trailing whitespace preserved)relaxed: Collapse whitespace in lines, remove trailing empty linesMost deployments use relaxed/relaxed (header/body) to maximize compatibility.
12345678910111213141516171819202122232425262728293031323334
# Example: relaxed canonicalization for headers Original header:"From: John Smith <john@example.com> " After relaxed canonicalization:"from:john smith <john@example.com>" # Changes applied:# 1. Header name lowercased: "From:" → "from:"# 2. Multiple spaces collapsed: " John" → "john"# 3. Trailing whitespace removed # Example: relaxed canonicalization for body Original body:"Hello World \r""This is a test. \r""\r""\r" After relaxed canonicalization:"Hello World\r""This is a test.\r" # Changes applied:# 1. Trailing whitespace on lines removed# 2. Trailing blank lines removedThe signer specifies which headers to include in the signature via the h= tag. Common choices:
From, To, Subject, Date, Message-IDContent-Type, Content-Transfer-Encoding, MIME-Version, Reply-ToFrom) prevents attackers from prepending a false From.Critical concept: Headers NOT in the h= list can be added or modified without breaking the signature. Attackers exploit this if Reply-To isn't signed—they add a malicious Reply-To that passes DKIM.
The canonicalized body is hashed (SHA-256 is standard). The hash value is included in the signature as the bh= tag. If any byte of the body changes, the hash changes, and verification fails.
The signing server:
DKIM-Signature header (without the b= value yet)DKIM-Signature)b= tagEvery DKIM-signed message contains a DKIM-Signature header with multiple tags encoding the signature and verification parameters. Understanding each tag is essential for troubleshooting.
12345678
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=example.com; s=selector1; h=from:to:subject:date:message-id:content-type; bh=2jUSOH9NhtVGCQWNr9BrIAPreKQjO6Sn7XIkfJVOzv8=; b=dzdVyOfAKCdLXdJOc9G2q8LoXSlEniSbav+yuU4zGeeruD00lszZ VoG4ZHRNiYzR0rgu8toJEOQr0EsnKZFV3hLTXWcdT6Jhc4SWMKSR2 hG1onPwMNFQwJQxQGzaNVMJl8TYJfSYUGj6bM2Lz5bNLxjUiUgB7I Xq8hJwGZzxCMoT8ZA=| Tag | Required | Description | Example Value |
|---|---|---|---|
v= | Yes | DKIM version (always 1) | v=1 |
a= | Yes | Signing algorithm | a=rsa-sha256 or a=ed25519-sha256 |
c= | No | Canonicalization (header/body) | c=relaxed/relaxed |
d= | Yes | Signing domain (SDID) | d=example.com |
s= | Yes | Selector (key identifier) | s=selector1 |
h= | Yes | Signed header fields | h=from:to:subject:date |
bh= | Yes | Body hash (Base64) | bh=2jUSO... |
b= | Yes | Signature data (Base64) | b=dzdVy... |
t= | No | Signature timestamp (Unix epoch) | t=1705488000 |
x= | No | Signature expiration time | x=1706092800 |
l= | No | Body length limit signed | l=1000 (security risk!) |
i= | No | Agent/User identifier (AUID) | i=user@example.com |
d= (Signing Domain Identifier - SDID)
The domain claiming responsibility for the message. This is what DMARC uses for alignment checking. The domain must have the corresponding public key in DNS.
s= (Selector)
A string that identifies which key to use when a domain has multiple keys. The full DNS lookup is: selector._domainkey.domain. Selectors enable key rotation without service disruption—deploy new key with new selector, update signing, eventually remove old selector.
h= (Signed Headers)
Colon-separated list of header field names included in the signature. Order matters—headers are signed in this order. Including a header multiple times (e.g., h=from:from:subject) prevents header prepending attacks.
bh= (Body Hash)
Base64-encoded hash of the canonicalized body. Verifiers compute this independently and compare to ensure body integrity.
b= (Signature)
The actual cryptographic signature over the headers and body hash. Base64-encoded. This is what the private key generates and the public key verifies.
The l= (body length) tag limits how many bytes of the body are signed. This was intended for mailing lists that add footers—but it creates a devastating vulnerability. An attacker can append arbitrary content to the body after the signed portion. Legitimate senders should NEVER use l=. Receivers should treat messages with l= suspiciously.
When a receiving mail server encounters a DKIM-signed message, it performs verification through a systematic process.
Step 1: Parse the DKIM-Signature header
d= (domain), s= (selector), h= (headers), bh= (body hash), b= (signature)Step 2: Retrieve the public key
{selector}._domainkey.{domain}p= (public key)Step 3: Verify body hash
c=) to the bodya= tagbh= valueStep 4: Verify header signature
h= in specified orderb= value)Step 5: Report result
12345678910111213141516171819202122
# DKIM public key DNS record structure # Query: selector1._domainkey.example.com# Response:selector1._domainkey.example.com. 300 IN TXT "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1234567890abcdef..." # Record breakdown:# v=DKIM1 - DKIM key record version (always DKIM1)# k=rsa - Key type (rsa or ed25519)# p=... - Base64-encoded public key material # Optional tags:# h=sha256 - Acceptable hash algorithms (default: allow all)# s=email - Service types (email restricts to email only)# t=y - Testing mode (domain is testing DKIM)# t=s - Strict mode (i= domain must exactly match d= domain) # Example: Ed25519 key (shorter, modern)selector2._domainkey.example.com. 300 IN TXT "v=DKIM1; k=ed25519; p=11qYAYKxCrfVS/7TyWQHOg7hcvPapiMlrwIaaPcHURo=" # Example: Key revocation (empty p= means key is revoked)oldselector._domainkey.example.com. 300 IN TXT "v=DKIM1; p="DKIM's security depends entirely on proper key management. Compromised or weak keys undermine the entire authentication scheme.
RSA Keys
Ed25519 Keys
Keys should be rotated periodically and immediately if compromise is suspected.
Rotation Process:
selector202601)p= empty)selector202601 makes rotation history clearp= to empty string, blocking forgery1234567891011121314151617181920212223242526272829
# Step 1: Generate new 2048-bit RSA key pair $ openssl genrsa -out dkim_private_2026.pem 2048$ openssl rsa -in dkim_private_2026.pem -pubout -out dkim_public_2026.pem # Step 2: Format public key for DNS (remove headers, join lines) $ cat dkim_public_2026.pem | grep -v "^-" | tr -d ''MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA... # Step 3: Publish DNS record with new selector sel202601._domainkey.example.com. IN TXT "v=DKIM1; k=rsa; p=MIIBIjAN..." # Step 4: Verify DNS propagation $ dig +short TXT sel202601._domainkey.example.com"v=DKIM1; k=rsa; p=MIIBIjAN..." # Step 5: Update mail server to use new selector# (Configuration varies by MTA - example for Postfix with OpenDKIM) # /etc/opendkim/KeyTable:sel202601._domainkey.example.com example.com:sel202601:/etc/opendkim/keys/example.com/sel202601.private # Step 6: After transition, revoke old key sel202001._domainkey.example.com. IN TXT "v=DKIM1; p="DKIM verification can fail for various reasons. Understanding failure modes is essential for troubleshooting deliverability issues.
| Result | Meaning | Common Causes | Resolution |
|---|---|---|---|
| None | No DKIM signature present | Sender doesn't sign, signature stripped | Configure DKIM signing on sender side |
| Neutral | Signature present but not evaluated | Syntax issues, unsupported algorithm | Check signature format compliance |
| Fail (body hash) | Body was modified | Mailing list modification, AV rewrites | Investigate transit path modifications |
| Fail (signature) | Cryptographic verification failed | Wrong key, header modification, corruption | Verify DNS key matches signing key |
| PermError | Permanent error in evaluation | DNS key not found, invalid key format | Check DNS record exists and is valid |
| TempError | Temporary error | DNS timeout, rate limiting | Usually resolves; check DNS availability |
1. Mailing List Modifications
Mailing lists often add footers, modify subject lines ([LIST] prefix), or wrap messages. These changes cause body hash failure. Solutions:
2. DNS Propagation Delays New DKIM DNS records take time to propagate. During transition, some receivers see the old (or no) key while others see the new key.
3. Header Modification
Anti-spam gateways sometimes add or modify headers. If those headers are in the h= list, DKIM fails.
4. Line Length Issues
Some MTAs rewrap long lines differently, breaking body hash. Using c=relaxed/relaxed helps but doesn't solve all cases.
5. Key/Selector Mismatch Using a selector that points to a different key than what signed the message. Usually a configuration error.
12345678910111213141516171819202122232425262728
# Authentication-Results header showing DKIM failure Authentication-Results: mx.receiver.com; dkim=fail (body hash did not verify) header.d=example.com header.s=sel202501 header.b=dzdVyOf; spf=pass smtp.mailfrom=example.com # Interpretation: Body was modified after signing# Common with mailing lists, security gateways adding footers/banners # Troubleshooting steps: # 1. Verify DNS record exists$ dig +short TXT sel202501._domainkey.example.com"v=DKIM1; k=rsa; p=MIIBIjAN..." # 2. Extract public key and verify format$ echo "MIIBIjAN..." | base64 -d | openssl rsa -pubin -inform DER -text # 3. Check for header modifications in message path# Look at Received: headers for email gateways # 4. Check body for added content# Look for footers, disclaimers, tracking pixels added after signing # 5. Test DKIM setup with external tools$ wget -qO- https://www.mail-tester.com/# Or send test email to check-auth@verifier.port25.comServices like mail-tester.com, mxtoolbox.com, and check-auth@verifier.port25.com provide instant DKIM verification. Send a test email to receive detailed diagnostic reports showing exactly where authentication succeeds or fails.
Most organizations use third-party services for email delivery (marketing platforms, transactional email, CRM systems). Configuring DKIM for these services requires understanding delegation models.
Model 1: Provider Signs with Their Domain
The simplest approach—provider uses their own d= domain. However, this doesn't provide DMARC alignment for your domain.
Model 2: CNAME Delegation
You create CNAME records in your DNS pointing to the provider's key infrastructure. The provider signs with your domain (d=yourdomain.com).
Model 3: Key Upload You generate the key pair and upload the private key to the provider. More control, but private key leaves your infrastructure.
Model 4: Subdomain Delegation
Provider signs with a subdomain (d=mail.yourdomain.com). Requires DMARC relaxed alignment to match your organizational domain.
12345678910111213141516171819202122232425262728
# Example: Setting up DKIM for SendGrid using CNAME delegation # SendGrid provides you with a selector and CNAME target# You add these DNS records: s1._domainkey.example.com. CNAME s1.domainkey.u12345678.wl.sendgrid.net.s2._domainkey.example.com. CNAME s2.domainkey.u12345678.wl.sendgrid.net. # When SendGrid signs email from you:# 1. Signs with d=example.com, s=s1# 2. Receiver queries s1._domainkey.example.com# 3. CNAME redirects to SendGrid's key infrastructure# 4. SendGrid's public key is returned# 5. Signature verifies ✓# 6. d=example.com aligns with your From: domain for DMARC # Example: Google Workspace DKIM setup # Google provides a selector (e.g., google or a custom name)# Add TXT record with the public key Google provides: google._domainkey.example.com. TXT "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA..." # Multiple services, multiple selectors:google._domainkey.example.com → Google Workspace (primary email)s1._domainkey.example.com → SendGrid (transactional)s2._domainkey.example.com → SendGrid (transactional, rotation)mte1._domainkey.example.com → Mailchimp (marketing)d=yourdomain.com) for strict DMARC alignment. Some providers only sign with their own domain.DKIM provides the cryptographic layer of email authentication, ensuring message integrity and domain-level authentication that survives mail forwarding. Let's consolidate the key concepts:
What's Next:
SPF validates the sending IP. DKIM validates the message content. But neither directly addresses the visible From header that users see and trust. The next page covers DMARC (Domain-based Message Authentication, Reporting, and Conformance), which:
DMARC ties SPF and DKIM together into a coherent policy framework, enabling domain owners to protect their brand and users from spoofing attacks.
You now understand DKIM's cryptographic foundations, signing and verification processes, key management best practices, and failure modes. You can configure DKIM for mail servers, interpret DKIM-Signature headers, troubleshoot verification failures, and integrate DKIM with third-party email services.