DKIM Configuration for Email Authentication: Complete Guide
Introduction
DomainKeys Identified Mail (DKIM) is a critical email authentication method that helps prove your emails are legitimately sent from your domain and haven't been tampered with during transit. In an era where email spoofing and phishing attacks are rampant, DKIM provides cryptographic verification that an email genuinely originated from the claimed sender's domain.
DKIM works by adding a digital signature to email headers using public-key cryptography. When your mail server sends an email, it signs it with a private key. Receiving mail servers can then verify this signature using the public key published in your DNS records. If the signature is valid and the message hasn't been altered, the email passes DKIM verification, significantly improving deliverability and reducing the likelihood of your emails being marked as spam.
Major email providers like Gmail, Yahoo, Microsoft Outlook, and others heavily rely on DKIM authentication when determining email legitimacy. Without DKIM, your emails are more likely to be rejected, marked as spam, or flagged with security warnings. Implementing DKIM is no longer optional for serious email operations—it's essential.
This comprehensive guide walks you through installing and configuring DKIM for your mail server using OpenDKIM with Postfix. You'll learn how to generate cryptographic keys, configure OpenDKIM, integrate it with Postfix, publish DNS records, and verify everything is working correctly.
Prerequisites
Before configuring DKIM, ensure you have:
System Requirements
- A working mail server with Postfix installed and configured
- Root or sudo access to the server
- Ubuntu 20.04/22.04, Debian 10/11, CentOS 8/Rocky Linux 8, or similar
- At least 512MB RAM available
- Basic Postfix configuration already in place
Domain Requirements
- A registered domain name (e.g., example.com)
- Access to your domain's DNS management panel
- DNS propagation time available (up to 48 hours, usually much faster)
- Understanding of DNS TXT records
Email Server Requirements
- Postfix properly sending and receiving email
- Valid hostname configured (mail.example.com)
- SPF records recommended (but not required)
- Working knowledge of your current mail setup
Knowledge Prerequisites
- Linux command-line proficiency
- Basic understanding of public-key cryptography
- Familiarity with DNS record management
- Experience editing configuration files
Understanding DKIM
How DKIM Works
- Key Generation: You generate a pair of cryptographic keys (private and public)
- Private Key Storage: The private key stays securely on your mail server
- Public Key Publication: The public key is published in your DNS as a TXT record
- Email Signing: When sending email, your server signs the message with the private key
- Signature Verification: Receiving servers retrieve your public key from DNS and verify the signature
- Authentication Result: If verification succeeds, the email is authenticated
DKIM Header Example
A DKIM signature in an email header looks like this:
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=example.com;
s=default; t=1642080000;
bh=4KJds9FH3jk2lksjdflk3jF=;
h=From:To:Subject:Date;
b=AbCdEf123...very long signature string...
Key components:
- v=1: DKIM version
- a=rsa-sha256: Algorithm used
- d=example.com: Signing domain
- s=default: Selector (identifies which key to use)
- h=: Headers included in signature
- b=: The actual signature
Benefits of DKIM
- Improved Deliverability: Emails pass authentication checks
- Reduced Spam Flagging: Legitimate emails less likely marked as spam
- Brand Protection: Prevents domain spoofing and phishing
- Trust Building: Recipients can verify email authenticity
- Compliance: Required by many organizations and email providers
- Better Reputation: Contributes to positive sender reputation
Step 1: Install OpenDKIM
OpenDKIM is the most widely used open-source DKIM implementation for Linux mail servers.
Ubuntu/Debian Installation
# Update package lists
sudo apt update
# Install OpenDKIM and tools
sudo apt install opendkim opendkim-tools -y
CentOS/Rocky Linux Installation
# Install EPEL repository (if not already installed)
sudo dnf install epel-release -y
# Install OpenDKIM
sudo dnf install opendkim -y
Verify Installation
# Check OpenDKIM version
opendkim -V
# Check if service exists
systemctl list-unit-files | grep opendkim
Step 2: Generate DKIM Keys
Create a directory structure for DKIM keys:
# Create directory for keys
sudo mkdir -p /etc/opendkim/keys/example.com
# Set ownership
sudo chown -R opendkim:opendkim /etc/opendkim
# Set permissions
sudo chmod 750 /etc/opendkim
sudo chmod 750 /etc/opendkim/keys
Generate the DKIM key pair:
# Navigate to domain key directory
cd /etc/opendkim/keys/example.com
# Generate keys (2048-bit RSA recommended)
sudo opendkim-genkey -b 2048 -d example.com -D /etc/opendkim/keys/example.com -s default -v
# Set proper ownership
sudo chown opendkim:opendkim /etc/opendkim/keys/example.com/*
# Set restrictive permissions on private key
sudo chmod 600 /etc/opendkim/keys/example.com/default.private
sudo chmod 644 /etc/opendkim/keys/example.com/default.txt
This creates two files:
- default.private: Private key (kept secret on server)
- default.txt: Public key (to be published in DNS)
View the Generated Keys
# View private key
sudo cat /etc/opendkim/keys/example.com/default.private
# View public key (DNS record)
sudo cat /etc/opendkim/keys/example.com/default.txt
The default.txt file contains something like:
default._domainkey.example.com. IN TXT ( "v=DKIM1; h=sha256; k=rsa; "
"p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA..." )
Key Size Considerations
- 1024-bit: Minimum, less secure, smaller DNS record
- 2048-bit: Recommended standard, good security, reasonable size
- 4096-bit: Maximum security, may cause DNS issues, larger record
Recommendation: Use 2048-bit for best balance of security and compatibility.
Step 3: Configure OpenDKIM Main Settings
Edit the main OpenDKIM configuration file:
sudo nano /etc/opendkim.conf
Add or modify these settings:
# Logging
Syslog yes
SyslogSuccess yes
LogWhy yes
# Basic settings
Canonicalization relaxed/simple
Mode sv
SubDomains no
# Security
AutoRestart yes
AutoRestartRate 10/1M
Background yes
DNSTimeout 5
SignatureAlgorithm rsa-sha256
# Keys and domains
KeyTable refile:/etc/opendkim/key.table
SigningTable refile:/etc/opendkim/signing.table
ExternalIgnoreList refile:/etc/opendkim/trusted.hosts
InternalHosts refile:/etc/opendkim/trusted.hosts
# Socket configuration
Socket local:/var/spool/postfix/opendkim/opendkim.sock
PidFile /var/run/opendkim/opendkim.pid
UMask 002
UserID opendkim:postfix
# Header settings
OversignHeaders From
Configuration Explained
- Canonicalization: How to treat whitespace and headers (relaxed/simple is standard)
- Mode: sv = sign and verify
- SubDomains: Whether to sign mail from subdomains
- SignatureAlgorithm: rsa-sha256 is current standard
- KeyTable: Maps key names to key files
- SigningTable: Maps email addresses/domains to keys
- InternalHosts: Hosts/networks trusted for signing
- Socket: UNIX socket for Postfix communication
- OversignHeaders: Headers to sign multiple times (prevents addition)
Step 4: Create OpenDKIM Configuration Files
Create Key Table
sudo nano /etc/opendkim/key.table
Add:
default._domainkey.example.com example.com:default:/etc/opendkim/keys/example.com/default.private
Format: selector._domainkey.domain domain:selector:keyfile
Create Signing Table
sudo nano /etc/opendkim/signing.table
Add:
*@example.com default._domainkey.example.com
This tells OpenDKIM to sign all emails from @example.com with the specified key.
For multiple domains:
*@example.com default._domainkey.example.com
*@example.net default._domainkey.example.net
*@example.org default._domainkey.example.org
Create Trusted Hosts
sudo nano /etc/opendkim/trusted.hosts
Add:
127.0.0.1
localhost
::1
203.0.113.10
*.example.com
example.com
mail.example.com
Include:
- Localhost addresses
- Your server's IP
- Your domain and subdomains
- Any other servers that should be trusted
Set Permissions
sudo chown opendkim:opendkim /etc/opendkim/key.table
sudo chown opendkim:opendkim /etc/opendkim/signing.table
sudo chown opendkim:opendkim /etc/opendkim/trusted.hosts
sudo chmod 644 /etc/opendkim/key.table
sudo chmod 644 /etc/opendkim/signing.table
sudo chmod 644 /etc/opendkim/trusted.hosts
Step 5: Create OpenDKIM Socket Directory
Create the socket directory for Postfix communication:
# Create socket directory
sudo mkdir -p /var/spool/postfix/opendkim
# Set ownership
sudo chown opendkim:postfix /var/spool/postfix/opendkim
# Set permissions
sudo chmod 750 /var/spool/postfix/opendkim
Alternative: Use TCP Socket
If UNIX sockets cause issues, use TCP instead:
In /etc/opendkim.conf:
Socket inet:8891@localhost
In Postfix configuration (later):
smtpd_milters = inet:localhost:8891
non_smtpd_milters = inet:localhost:8891
Step 6: Configure Postfix Integration
Edit Postfix main configuration:
sudo nano /etc/postfix/main.cf
Add these lines at the end:
# OpenDKIM milter configuration
milter_default_action = accept
milter_protocol = 6
smtpd_milters = local:/opendkim/opendkim.sock
non_smtpd_milters = $smtpd_milters
Postfix Milter Settings Explained
- milter_default_action: What to do if milter fails (accept/reject/tempfail)
- milter_protocol: Milter protocol version (6 is current)
- smtpd_milters: Milters for mail received via SMTP
- non_smtpd_milters: Milters for mail submitted locally
The socket path is relative to Postfix chroot (/var/spool/postfix/), so:
- Full path:
/var/spool/postfix/opendkim/opendkim.sock - Postfix path:
local:/opendkim/opendkim.sock
Step 7: Configure OpenDKIM Service
On some systems, you need to configure the OpenDKIM service startup:
Ubuntu/Debian
Edit the service configuration:
sudo nano /etc/default/opendkim
Ensure it contains:
RUNDIR=/var/run/opendkim
SOCKET=local:/var/spool/postfix/opendkim/opendkim.sock
USER=opendkim
GROUP=opendkim
PIDFILE=$RUNDIR/opendkim.pid
EXTRAAFTER=
SystemD Service Configuration
For systems using systemd, create an override:
sudo systemctl edit opendkim
Add:
[Service]
Group=postfix
Save and exit.
Step 8: Start and Enable Services
Start OpenDKIM and reload Postfix:
# Enable OpenDKIM to start on boot
sudo systemctl enable opendkim
# Start OpenDKIM
sudo systemctl start opendkim
# Check OpenDKIM status
sudo systemctl status opendkim
# Reload Postfix configuration
sudo systemctl reload postfix
# Check Postfix status
sudo systemctl status postfix
Verify the socket was created:
# Check socket exists
ls -la /var/spool/postfix/opendkim/
# You should see opendkim.sock
Step 9: Publish DKIM DNS Record
View your public key:
sudo cat /etc/opendkim/keys/example.com/default.txt
Output will look like:
default._domainkey.example.com. IN TXT ( "v=DKIM1; h=sha256; k=rsa; "
"p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1234567890abcdef..."
"...more key data..."
"...end of key" )
Extract the Public Key
The key is split across multiple lines with quotes. You need to combine them:
# Extract just the key value
sudo cat /etc/opendkim/keys/example.com/default.txt | grep -oP '(?<=p=).*' | tr -d '"\n\t '
Create DNS TXT Record
In your DNS management panel, create a TXT record:
Name/Host: default._domainkey
or
Name/Host: default._domainkey.example.com.
Type: TXT
Value: v=DKIM1; h=sha256; k=rsa; p=YOUR_PUBLIC_KEY_HERE
Example:
Name: default._domainkey
Type: TXT
Value: v=DKIM1; h=sha256; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef
Important Notes:
- Remove all line breaks and quotes from the key value
- Include only:
v=DKIM1; h=sha256; k=rsa; p=YOURKEY - Some DNS providers automatically add the domain, so use just
default._domainkey - Others require the full name:
default._domainkey.example.com - TTL: 3600 (1 hour) is typical
Common DNS Provider Formats
Cloudflare:
Name: default._domainkey
Type: TXT
Content: v=DKIM1; h=sha256; k=rsa; p=YOUR_KEY
GoDaddy:
Host: default._domainkey
TXT Value: v=DKIM1; h=sha256; k=rsa; p=YOUR_KEY
Namecheap:
Host: default._domainkey
Value: v=DKIM1; h=sha256; k=rsa; p=YOUR_KEY
Step 10: Verify DNS Propagation
Wait for DNS propagation (usually 5-30 minutes, can take up to 48 hours).
Check DNS Record
# Query DNS for DKIM record
dig default._domainkey.example.com TXT +short
# Alternative with host command
host -t TXT default._domainkey.example.com
# Alternative with nslookup
nslookup -type=TXT default._domainkey.example.com
Expected output:
"v=DKIM1; h=sha256; k=rsa; p=MIIBIjANBgkqhkiG..."
Test DKIM Record
# Test DKIM record validity
opendkim-testkey -d example.com -s default -vvv
Successful output:
opendkim-testkey: using default configfile /etc/opendkim.conf
opendkim-testkey: key OK
If you see errors:
key not secure: Warning only, key works but DNSSEC not configuredkey not found: DNS not propagated yet or wrong recordkey syntax error: Problem with DNS TXT record format
Step 11: Test DKIM Signing
Send a test email and verify DKIM signature:
Send Test Email
# Send test email
echo "This is a DKIM test email" | mail -s "DKIM Test" [email protected]
Check Mail Logs
sudo tail -f /var/log/mail.log
Look for:
opendkim[12345]: DKIM-Signature field added
Verify Email Headers
- Send email to Gmail, Yahoo, or another provider
- Open the email
- View full headers (usually "Show original" or similar)
- Look for DKIM signature and results
Headers to look for:
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=example.com;
s=default; t=1642080000;
And authentication results:
Authentication-Results: mx.google.com;
dkim=pass [email protected] header.s=default header.b=AbCdEf...
Status meanings:
dkim=pass: DKIM verification successfuldkim=fail: Signature verification faileddkim=neutral: No DKIM signature found or couldn't verifydkim=temperror: Temporary error during verification
Step 12: Test with Online Tools
Use online verification tools for comprehensive testing:
Mail-Tester.com
- Visit https://www.mail-tester.com/
- Get the unique email address
- Send email from your server:
echo "DKIM Test via mail-tester" | mail -s "Test" [email protected]
- View results on the website
- Check DKIM section for pass/fail status
DKIMValidator.com
- Visit https://dkimvalidator.com/
- Get the unique test address
- Send test email to that address
- View detailed DKIM validation results
MXToolbox DKIM Lookup
https://mxtoolbox.com/dkim.aspx
Enter your domain and selector (default) to verify DNS record.
Troubleshooting Common Issues
Issue 1: DKIM Signature Not Added
Symptoms: No DKIM-Signature header in sent emails
Diagnosis:
# Check OpenDKIM is running
sudo systemctl status opendkim
# Check socket exists
ls -la /var/spool/postfix/opendkim/
# Check mail logs
sudo grep opendkim /var/log/mail.log
# Test OpenDKIM manually
sudo opendkim-testkey -d example.com -s default -vvv
Solutions:
- Restart OpenDKIM:
sudo systemctl restart opendkim - Verify socket permissions
- Check signing.table includes your domain
- Verify trusted.hosts includes your server
Issue 2: DKIM Verification Fails (dkim=fail)
Symptoms: Emails signed but receiving servers report dkim=fail
Diagnosis:
# Verify DNS record matches key
sudo cat /etc/opendkim/keys/example.com/default.txt
dig default._domainkey.example.com TXT +short
# Check for key mismatch
opendkim-testkey -d example.com -s default -vvv
Solutions:
- Ensure DNS record exactly matches public key
- Remove line breaks and quotes from DNS record
- Verify no extra spaces in DNS record
- Wait for full DNS propagation (up to 48 hours)
- Check clock sync:
timedatectl status
Issue 3: OpenDKIM Won't Start
Symptoms: Service fails to start
Diagnosis:
# Check detailed status
sudo systemctl status opendkim -l
# Check configuration syntax
sudo opendkim -n
# Check journal for errors
sudo journalctl -u opendkim -n 50
Common errors and fixes:
"Can't open key file"
# Fix permissions
sudo chown opendkim:opendkim /etc/opendkim/keys/example.com/default.private
sudo chmod 600 /etc/opendkim/keys/example.com/default.private
"Can't bind to socket"
# Remove old socket
sudo rm /var/spool/postfix/opendkim/opendkim.sock
sudo systemctl restart opendkim
"Can't create PID file"
# Create PID directory
sudo mkdir -p /var/run/opendkim
sudo chown opendkim:opendkim /var/run/opendkim
Issue 4: DNS Record Not Found
Symptoms: opendkim-testkey reports "key not found"
Diagnosis:
# Query DNS directly
dig default._domainkey.example.com TXT +short
# Check from different DNS servers
dig @8.8.8.8 default._domainkey.example.com TXT +short
dig @1.1.1.1 default._domainkey.example.com TXT +short
Solutions:
- Verify correct DNS record name (default._domainkey)
- Check if your DNS provider adds domain automatically
- Wait longer for DNS propagation
- Clear DNS cache:
sudo systemd-resolve --flush-caches - Try full FQDN:
default._domainkey.example.com.(with trailing dot)
Issue 5: Permission Denied Errors
Symptoms: Errors about file access in logs
Fix all permissions:
# Fix OpenDKIM directory
sudo chown -R opendkim:opendkim /etc/opendkim
sudo chmod 750 /etc/opendkim
sudo chmod 750 /etc/opendkim/keys
sudo chmod 750 /etc/opendkim/keys/example.com
# Fix configuration files
sudo chmod 644 /etc/opendkim/key.table
sudo chmod 644 /etc/opendkim/signing.table
sudo chmod 644 /etc/opendkim/trusted.hosts
# Fix keys
sudo chmod 600 /etc/opendkim/keys/example.com/default.private
sudo chmod 644 /etc/opendkim/keys/example.com/default.txt
# Fix socket directory
sudo chown opendkim:postfix /var/spool/postfix/opendkim
sudo chmod 750 /var/spool/postfix/opendkim
# Restart service
sudo systemctl restart opendkim
Advanced Configuration
Multiple Domains
For multiple domains, generate separate keys:
# For each domain:
sudo mkdir -p /etc/opendkim/keys/domain2.com
sudo opendkim-genkey -b 2048 -d domain2.com -D /etc/opendkim/keys/domain2.com -s default
sudo chown -R opendkim:opendkim /etc/opendkim/keys/domain2.com
sudo chmod 600 /etc/opendkim/keys/domain2.com/default.private
Update key.table:
default._domainkey.example.com example.com:default:/etc/opendkim/keys/example.com/default.private
default._domainkey.domain2.com domain2.com:default:/etc/opendkim/keys/domain2.com/default.private
Update signing.table:
*@example.com default._domainkey.example.com
*@domain2.com default._domainkey.domain2.com
Publish separate DNS records for each domain.
Key Rotation
Rotate DKIM keys periodically for security:
- Generate new key with different selector:
sudo opendkim-genkey -b 2048 -d example.com -D /etc/opendkim/keys/example.com -s 202601
- Add to key.table:
202601._domainkey.example.com example.com:202601:/etc/opendkim/keys/example.com/202601.private
- Publish new DNS record
- Wait for propagation
- Update signing.table to use new selector
- Keep old key active for 30 days (for emails in transit)
- Delete old key and DNS record
Subdomains
To sign mail from subdomains:
Set SubDomains in opendkim.conf:
SubDomains yes
This allows signing mail from subdomain.example.com with example.com key.
Best Practices
1. Use Strong Keys
- Minimum 2048-bit RSA keys
- Consider 4096-bit for high-security requirements
- Rotate keys annually
2. Proper Permissions
- Private keys: 600 (readable only by opendkim)
- Configuration files: 644 (readable by all, writable by root)
- Directories: 750 (accessible by opendkim group)
3. Monitor DKIM
# Check DKIM statistics
sudo grep "DKIM-Signature" /var/log/mail.log | wc -l
# Check for failures
sudo grep "dkim.*fail" /var/log/mail.log
4. Combine with SPF and DMARC
DKIM alone is not enough. Implement all three:
- SPF: Validates sending server IP
- DKIM: Validates message integrity and authenticity
- DMARC: Policy for handling failures
5. Test Regularly
- Send test emails monthly
- Monitor authentication results
- Check DNS records haven't changed
- Verify keys haven't expired or been corrupted
6. Logging
Enable comprehensive logging during setup:
LogWhy yes
SyslogSuccess yes
After verification, reduce logging:
LogWhy no
SyslogSuccess no
Monitoring and Maintenance
Create Monitoring Script
sudo nano /usr/local/bin/check-dkim.sh
Add:
#!/bin/bash
echo "=== DKIM Status Check ==="
echo ""
echo "OpenDKIM Service:"
systemctl is-active opendkim
echo ""
echo "DNS Record Status:"
opendkim-testkey -d example.com -s default -vvv 2>&1 | grep "key"
echo ""
echo "Recent DKIM Signatures:"
grep "DKIM-Signature field added" /var/log/mail.log | tail -5
echo ""
echo "DKIM Failures (last 24h):"
grep "dkim.*fail" /var/log/mail.log | wc -l
Make executable:
sudo chmod +x /usr/local/bin/check-dkim.sh
Schedule Regular Checks
sudo crontab -e
Add:
0 9 * * * /usr/local/bin/check-dkim.sh | mail -s "Daily DKIM Report" [email protected]
Conclusion
You now have DKIM fully configured and operational on your mail server. Your outgoing emails are cryptographically signed, improving deliverability and protecting your domain reputation.
Key Accomplishments
- OpenDKIM Installed: Service running and integrated with Postfix
- Keys Generated: Secure 2048-bit RSA key pair created
- DNS Published: Public key available for verification
- Signing Active: All outgoing mail is DKIM-signed
- Verification Tested: DKIM signatures passing validation
Next Steps
To complete your email authentication:
- Configure SPF records for IP authorization
- Implement DMARC for policy enforcement
- Monitor authentication results regularly
- Set up automated testing for ongoing verification
- Plan key rotation schedule for security
- Combine with spam filtering (SpamAssassin)
Important Reminders
- Keep private keys secure: Never expose or share private keys
- Monitor DNS records: Ensure they don't change unexpectedly
- Test after changes: Any configuration change should be tested
- Rotate keys periodically: Annual rotation recommended
- Check logs regularly: Monitor for signing failures
With DKIM properly configured, your emails have significantly better deliverability and your domain is protected against spoofing. Combined with SPF and DMARC, you'll have industry-standard email authentication that maximizes trust and reliability.


