Email Security

DKIM Setup Guide: Signing Your Emails for Authentication

Step-by-step guide to generating DKIM keys, publishing DNS TXT records, configuring your mail server, and rotating selectors safely in production.

March 9, 20266 min readShipSafer Team

DKIM Setup Guide: Signing Your Emails for Authentication

DKIM (DomainKeys Identified Mail) lets you prove that an email genuinely came from your infrastructure and was not tampered with in transit. Without it, any server on the internet can send mail claiming to be you, and receiving servers have no cryptographic way to distinguish the real message from a forgery. This guide walks through every step of DKIM implementation: key generation, DNS publication, mail server configuration, and safe selector rotation.

How DKIM Signing Works

When your mail server sends a message, it computes a cryptographic hash of selected headers and the message body, then signs that hash using your private key. The signature travels in the DKIM-Signature header. When a receiving server gets the message, it looks up your public key in DNS, verifies the signature, and confirms two things: the message came from a server holding your private key, and the signed portions have not been modified since signing.

The DNS lookup path is: {selector}._domainkey.{domain}

The selector is a label you choose that allows you to have multiple DKIM keys active simultaneously — one per mail service, or old and new keys during rotation.

Step 1: Generate Your DKIM Key Pair

Use OpenSSL to generate a 2048-bit RSA key pair. 1024-bit keys are considered weak; use at minimum 2048-bit, preferably 4096-bit for new deployments.

# Generate private key
openssl genrsa -out dkim-private.pem 2048

# Extract public key
openssl rsa -in dkim-private.pem -pubout -out dkim-public.pem

# View public key in format suitable for DNS
openssl rsa -in dkim-private.pem -pubout -outform DER | openssl base64 -A

Keep dkim-private.pem secure on your mail server. Never commit it to version control. The base64-encoded output of the last command goes into your DNS TXT record.

Key storage best practices

  • Store private keys with file permissions 600 (owner read/write only)
  • On Linux: chmod 600 /etc/mail/dkim/dkim-private.pem
  • For high-volume senders, consider storing keys in HashiCorp Vault or AWS KMS
  • Back up private keys securely — losing a key means reconfiguring all signing before the old record expires

Step 2: Publish the DNS TXT Record

Choose a selector name. Common conventions are the year (2026), a service name (sendgrid), or a combination (mail2026). Descriptive selectors make rotation easier to track.

The DNS record format:

{selector}._domainkey.{yourdomain.com}  TXT  "v=DKIM1; k=rsa; p={base64-public-key}"

Example record

mail2026._domainkey.yourcompany.com  IN  TXT  "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2a7..."

If your public key is longer than 255 characters (common with 2048-bit keys), split it across multiple quoted strings in the same TXT record. Most DNS providers handle this automatically, but if you are editing zone files directly:

mail2026._domainkey.yourcompany.com  IN  TXT  ( "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2a7..."
                                                  "continued-base64-here==" )

Verify DNS propagation

# Check your record is live
dig TXT mail2026._domainkey.yourcompany.com +short

# Or use nslookup
nslookup -type=TXT mail2026._domainkey.yourcompany.com

Allow up to 48 hours for global propagation, though most resolvers pick up changes within 15 minutes.

Step 3: Configure Your Mail Server

Postfix with OpenDKIM

Install OpenDKIM:

apt-get install opendkim opendkim-tools

Configure /etc/opendkim.conf:

Mode                    sv
LogWhy                  Yes
Syslog                  Yes
SyslogSuccess           Yes
Canonicalization        relaxed/relaxed
Domain                  yourcompany.com
Selector                mail2026
KeyFile                 /etc/opendkim/keys/mail2026.private
Socket                  inet:8891@localhost
UMask                   022
UserID                  opendkim
OversignHeaders         From

Wire Postfix to OpenDKIM in /etc/postfix/main.cf:

milter_protocol = 6
milter_default_action = accept
smtpd_milters = inet:localhost:8891
non_smtpd_milters = inet:localhost:8891

Restart both services:

systemctl restart opendkim postfix

Google Workspace

  1. In the Google Admin Console, go to Apps > Google Workspace > Gmail > Authenticate email
  2. Select your domain and click "Generate new record"
  3. Google shows you the DNS TXT record to publish
  4. After propagation, click "Start authentication"

Microsoft 365

  1. Go to the Microsoft 365 Defender portal > Email & collaboration > Policies & rules > Threat policies > Email authentication settings
  2. Select DKIM and click the domain
  3. Microsoft generates two CNAME records (they manage key rotation automatically)
  4. Publish the CNAME records in your DNS
  5. Toggle DKIM signing to Enabled

SendGrid

  1. In SendGrid, go to Settings > Sender Authentication > Domain Authentication
  2. Enter your domain and SendGrid provides DNS records to publish
  3. After publishing, click "Verify"

Step 4: Verify DKIM is Signing Correctly

Send a test email to a Gmail or Yahoo address, open the message, and view the original headers. Look for:

Authentication-Results: mx.google.com;
  dkim=pass header.i=@yourcompany.com header.s=mail2026 header.b=AbCdEfGh

dkim=pass confirms your setup is working. If you see dkim=fail, check:

  • The private key path in your mail server configuration is correct
  • The selector in configuration matches the DNS record name
  • The DNS record is fully propagated
  • File permissions on the private key allow the mail daemon to read it

You can also use mail-tester.com or mxtoolbox.com/EmailHeaders to analyze authentication results without inspecting raw headers manually.

Step 5: DKIM Selector Rotation

Rotating DKIM keys periodically limits the damage if a private key is compromised. The process must be done carefully to avoid breaking delivery during the transition.

Rotation procedure

  1. Generate a new key pair using the same OpenSSL commands as Step 1, with a new selector name (e.g., mail2026b or mail2027)

  2. Publish the new DNS TXT record alongside the existing one — both selectors are valid simultaneously

  3. Wait for propagation — confirm the new DNS record resolves globally before proceeding

  4. Update your mail server configuration to sign with the new selector

  5. Restart your mail server — new messages now sign with the new key

  6. Wait 48–72 hours before removing the old DNS record. In-flight messages signed with the old key may still be in delivery queues. Removing the record too early causes those messages to fail DKIM verification.

  7. Remove the old DNS record and securely delete the old private key

Rotation schedule recommendations

  • At minimum: rotate annually
  • Best practice: rotate every 6 months
  • If a private key is ever exposed: rotate immediately, do not wait

Troubleshooting Common Issues

dkim=fail (body hash did not verify) — The message body was modified after signing. This often happens when mailing list software appends footers or when content scanning proxies alter messages. Use c=relaxed/relaxed canonicalization (which normalizes whitespace) rather than c=simple/simple.

dkim=neutral (no key for signature) — Your DNS record is not resolving. Check the selector name matches exactly and the record has propagated.

dkim=permerror (bad signature data) — The key in DNS does not match the private key used for signing. This happens after a key rotation where the wrong selector is active in the mail server config.

Signature missing entirely — The signing daemon is not running or the milter socket is not connected. Check systemctl status opendkim and review mail server logs.

Check Your Security Score — Free

See exactly how your domain scores on DMARC, TLS, HTTP headers, and 25+ other automated security checks in under 60 seconds.