Skip to content

DKIM: How to Set Up Email Signing

What Is DKIM?

DKIM (DomainKeys Identified Mail) is an email authentication protocol defined in RFC 6376. It allows a sending mail server to cryptographically sign outgoing messages, and the receiving server to verify that the message was not altered in transit.

The process works with public-key cryptography:

  1. The sending server holds a private key and uses it to generate a digital signature over the message headers and body.
  2. The signature is added as a DKIM-Signature header in the email.
  3. The receiving server extracts the selector and domain from the signature, looks up the public key in DNS, and verifies the signature.

Unlike SPF, which validates the sending server's IP address, DKIM validates the message content itself. This means DKIM signatures survive email forwarding — the signature travels with the message regardless of which server relays it.

DKIM is essential for DMARC alignment. When SPF fails (common with forwarding), DKIM provides the fallback authentication path that allows DMARC to pass.

DKIM Record Anatomy

A DKIM public key is published as a DNS TXT record at {selector}._domainkey.{domain}. For example, if your selector is s1 and your domain is example.com:

s1._domainkey.example.com TXT "v=DKIM1; k=rsa; p=MIIBIjANBgkqhki..."

Record Tags

TagRequiredDescriptionValues
vRecommendedVersionDKIM1
kNoKey typersa (default), ed25519
pYesPublic key (base64)The key data
tNoFlagsy (testing), s (strict domain match)
hNoAcceptable hash algorithmssha256 (default)

The DKIM-Signature Header

When a message is signed, the sending server adds a header like this:

DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
  d=example.com; s=s1; t=1714600000;
  h=from:to:subject:date:message-id;
  bh=base64_body_hash;
  b=base64_signature

Key fields: d= is the signing domain (used for DMARC alignment), s= is the selector (used to find the DNS key), h= lists the signed headers, bh= is the body hash, and b= is the signature.

Generating DKIM Keys

Key Size

Use 2048-bit RSA keys. 1024-bit keys are considered weak and some receivers may flag them. Keys larger than 2048 bits may not fit in a single DNS TXT record (255-byte string limit per chunk).

Ed25519 keys are smaller and faster but not yet universally supported. If you use Ed25519, also publish an RSA key as a fallback and dual-sign messages.

Generating with OpenSSL

Generate a 2048-bit RSA private key:

openssl genrsa -out dkim_private.pem 2048

Extract the public key:

openssl rsa -in dkim_private.pem -pubout -outform PEM -out dkim_public.pem

Format the public key for DNS (remove headers and newlines):

grep -v "^-" dkim_public.pem | tr -d '\n'

The output is the base64 string you put in the p= tag of your DNS record.

Choosing a Selector

The selector is an arbitrary string that identifies which key to use. Common patterns:

  • s1, s2 — simple sequential naming for rotation
  • google, sendgrid — named after the sending service
  • 202605 — date-based for tracking rotation

Each sending service can have its own selector, allowing multiple DKIM keys for the same domain.

Setting Up DKIM on Common Platforms

Postfix with OpenDKIM

Install OpenDKIM:

apt install opendkim opendkim-tools

Generate keys:

opendkim-genkey -s s1 -d example.com -b 2048

This creates s1.private (private key) and s1.txt (DNS record). Configure /etc/opendkim.conf:

Domain                  example.com
KeyFile                 /etc/opendkim/keys/s1.private
Selector                s1
Canonicalization        relaxed/relaxed
Mode                    sv

Connect Postfix to OpenDKIM via milter in /etc/postfix/main.cf:

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

Google Workspace

  1. Go to Admin Console → Apps → Google Workspace → Gmail → Authenticate email
  2. Select your domain and click "Generate new record"
  3. Choose 2048-bit key length
  4. Google provides the DNS TXT record — publish it at the selector shown (usually google._domainkey.example.com)
  5. Wait for DNS propagation, then click "Start authentication"

Microsoft 365

Microsoft 365 uses two CNAME records instead of TXT records:

selector1._domainkey.example.com CNAME selector1-example-com._domainkey.example.onmicrosoft.com
selector2._domainkey.example.com CNAME selector2-example-com._domainkey.example.onmicrosoft.com

Enable DKIM signing in the Microsoft 365 Defender portal under Email & collaboration → Policies → DKIM.

Amazon SES

SES uses Easy DKIM with three CNAME records. In the SES console:

  1. Go to Verified identities → your domain → Authentication → DKIM
  2. Click "Generate DKIM tokens"
  3. Publish the three CNAME records SES provides
  4. SES automatically starts signing once DNS propagates

DKIM Key Rotation

Rotate DKIM keys periodically to limit the impact of a compromised key. Recommended rotation interval: every 6–12 months.

Rotation Process

  1. Generate a new key pair with a new selector (e.g., s2 if current is s1)
  2. Publish the new public key in DNS at the new selector
  3. Wait for DNS propagation (at least the TTL of the old record)
  4. Switch signing to the new selector — update your mail server or provider configuration
  5. Dual-sign during transition — if possible, sign with both old and new keys for a few days
  6. Remove the old public key from DNS after the transition period (or set p= to empty to explicitly revoke it)

To revoke an old key, publish an empty p= tag:

old-selector._domainkey.example.com TXT "v=DKIM1; p="

Common DKIM Problems

1. Key Too Long for DNS TXT Record

A single DNS TXT string is limited to 255 bytes. A 2048-bit RSA public key in base64 is about 392 characters — it must be split into multiple strings within the same TXT record:

s1._domainkey.example.com TXT ("v=DKIM1; k=rsa; p=MIIBIjANBgkqhki..."
  "...remaining_key_data...")

Most DNS providers handle this splitting automatically. If you are editing zone files manually, ensure the strings are concatenated without spaces.

2. Selector Misconfiguration

The selector in the DKIM-Signature header must exactly match the DNS record name. If your signature says s=google but your DNS record is at default._domainkey, verification will fail. Check the selector your mail server is using and ensure the DNS record matches.

3. Body Hash Mismatch

The bh= tag in the DKIM signature is a hash of the message body. If anything modifies the body after signing (mailing list footers, antivirus disclaimers, content filters), the body hash will not match and DKIM fails. Use c=relaxed/relaxed canonicalization to tolerate minor whitespace changes, but content modifications will still break the signature.

4. Missing Headers in Signature

The h= tag lists which headers are signed. At minimum, sign: from, to, subject, date, message-id. The From header is required by RFC 6376. If important headers are not signed, an attacker could modify them without invalidating the signature.

5. Clock Skew

The t= (timestamp) and x= (expiration) tags in the signature are checked against the receiver's clock. If your server's clock is significantly wrong, signatures may appear expired or not yet valid. Use NTP to keep your server's clock synchronized.

Verify Your DKIM Setup

Send a test email to check if your DKIM signature is valid and passes authentication.

Run Delivery Test → Domain Scan →