Back to Learning CenterEmail Authentication

How do you set up DKIM on Postfix with OpenDKIM?

By Samuel ChenardAugust 5, 20268 min read
How do you set up DKIM on Postfix with OpenDKIM?

To sign mail with DKIM on Postfix you run OpenDKIM as a separate service and connect it to Postfix as a milter. OpenDKIM holds your private key, adds a DKIM-Signature header to every outgoing message, and Postfix hands mail to it over a socket. The setup is four steps: install OpenDKIM, generate a key pair and configure the signing tables, publish the public key as a DNS TXT record, and point Postfix's milter directives at the OpenDKIM socket. Once the DNS record propagates, receivers can verify your signature and your mail earns a dkim=pass.

At a glance

Quick takeaways

  • Postfix does not sign DKIM itself — OpenDKIM is a milter that plugs into it.
  • You generate a key pair: the private key stays on the server, the public key goes in DNS.
  • Three files drive OpenDKIM: the main config, a KeyTable (selector → key), and a SigningTable (domain → selector).
  • Postfix connects to OpenDKIM through smtpd_milters / non_smtpd_milters pointing at a shared socket.
  • The socket address in opendkim.conf must exactly match the one in Postfix's main.cf.
  • After DNS propagates, confirm signing by reading the Authentication-Results header on a test message.

What is OpenDKIM and why does Postfix need it?

Postfix is a mail transfer agent — it routes and delivers mail — but it has no built-in DKIM signer. DKIM signing is added by a milter (mail filter), a helper process Postfix streams each message through before delivery. OpenDKIM is the standard open-source milter for this job. When a message passes through, OpenDKIM hashes the headers and body, signs the hash with your private key, and inserts a DKIM-Signature header. The receiving server later fetches your public key from DNS and checks that signature.

Because OpenDKIM runs as its own daemon, the two processes talk over a socket — either a TCP port like inet:localhost:8891 or a Unix socket like local:/run/opendkim/opendkim.sock. Keeping the signer separate is what lets one OpenDKIM instance sign for several domains and selectors at once. If the milter concept is new, our explainer on what an MTA is sets the context for where signing sits in the mail flow.

How do you install and configure OpenDKIM?

Install OpenDKIM and its tools from your distribution's packages (opendkim and opendkim-tools on Debian/Ubuntu, opendkim on RHEL-family systems). The tools package provides the key-generation utility.

1. Generate a key pair. Pick a selector — a short label that names this key, for example mail or 2026a. Generate the key for your domain:

Technical exampletext
opendkim-genkey -b 2048 -d example.com -s mail -D /etc/dkimkeys/

This writes two files: mail.private (the private key, keep it readable only by the OpenDKIM user) and mail.txt (the public key, formatted as a DNS record). A 2048-bit key is the current baseline; 1024-bit keys are considered weak.

2. Configure /etc/opendkim.conf. Set the operating mode to sign and verify, and point OpenDKIM at its tables:

Technical exampletext
Mode                    sv
Socket                  inet:8891@localhost
Canonicalization        relaxed/relaxed
KeyTable                /etc/opendkim/KeyTable
SigningTable            refile:/etc/opendkim/SigningTable
InternalHosts           /etc/opendkim/TrustedHosts

Mode sv signs outbound mail and verifies inbound. relaxed/relaxed canonicalization tolerates the minor whitespace changes mail servers make in transit, which avoids needless dkim=fail (body hash did not verify) results.

3. Map the key with a KeyTable. The KeyTable ties a selector name to a domain and a private-key file. One line per key:

Technical exampletext
mail._domainkey.example.com example.com:mail:/etc/dkimkeys/mail.private

4. Choose what to sign with a SigningTable. The SigningTable maps sender addresses or domains to a KeyTable entry. To sign everything from your domain:

Technical exampletext
*@example.com mail._domainkey.example.com

5. List your trusted internal hosts. TrustedHosts names the hosts whose mail OpenDKIM should sign (rather than only verify). Include loopback and your server:

Technical exampletext
127.0.0.1
localhost
::1
example.com

Set ownership so the OpenDKIM user can read the keys and tables, then restart the service.

How do you publish the DKIM public key in DNS?

Open the generated mail.txt. It contains a TXT record for the host mail._domainkey.example.com with a value like v=DKIM1; k=rsa; p=MIIBIjANBg.... Publish it at your DNS provider:

  • Name / host: mail._domainkey (your provider appends the domain automatically — do not type the full domain twice).
  • Type: TXT.
  • Value: the entire p= string. Some providers need the quoted segments concatenated into one continuous value; the key is long enough that DNS splits it into chunks, and it must reassemble to the exact string OpenDKIM generated.
DKIM/record-setup on the mail server side is only half the job — receivers cannot verify until this record resolves. Give it time to propagate, then confirm the selector is live with a DKIM record lookup or the DKIM checker tool against mail._domainkey.example.com.

How do you connect OpenDKIM to Postfix?

With OpenDKIM running and listening on its socket, tell Postfix to route mail through it. Add these lines to /etc/postfix/main.cf:

Technical exampletext
milter_default_action = accept
milter_protocol = 6
smtpd_milters = inet:localhost:8891
non_smtpd_milters = inet:localhost:8891
  • smtpd_milters filters mail arriving over SMTP (from your submission clients).
  • non_smtpd_milters filters mail injected locally (from sendmail, cron, scripts) — set it too or that mail goes unsigned.
  • milter_default_action = accept means that if OpenDKIM is unreachable, Postfix still delivers the message rather than deferring it. That trades a missing signature for uptime; use tempfail instead if you would rather retry than send unsigned.
  • The socket in smtpd_milters must match the Socket line in opendkim.conf exactly.
Reload Postfix. Send a message to an external address you control and inspect the headers: you should see a DKIM-Signature header added by your server, and the receiver's Authentication-Results should read dkim=pass. Our guide to testing and verifying DKIM walks through reading that header in detail.

Common issues with DKIM on Postfix

Mail leaves the server with no DKIM-Signature header

Postfix is not handing mail to the milter, or OpenDKIM is not signing it. Check that both smtpd_milters and non_smtpd_milters point at the socket, that the OpenDKIM service is actually running, and that the sender's domain is covered by a SigningTable line. Mail from a host not listed in TrustedHosts is only verified, never signed — a very common cause of silent non-signing.

dkim=fail (body hash did not verify)

The body changed after signing, usually because a mailing list or a downstream filter altered it, or because canonicalization is too strict. Use relaxed/relaxed canonicalization so minor whitespace edits do not break the hash. Our deep dive on why a body hash fails to verify covers the other triggers.

Postfix logs "connect to Milter service … Connection refused"

Postfix cannot reach OpenDKIM on the socket. Confirm OpenDKIM is listening on the same address you put in main.cf — a mismatch between inet:localhost:8891 and inet:8891@localhost versus a Unix socket path is the usual culprit. If you use a Unix socket, make sure it lives somewhere Postfix's chroot can reach and that permissions allow the connection.

DKIM passes but DMARC still fails

A valid signature can still fail DMARC if it is not aligned — the signing domain (d= in the signature) must match the visible From: domain. If your SigningTable signs with the wrong domain, you get dkim=pass but dmarc=fail. Sign with the same domain your users send from, and see DKIM vs SPF and how alignment works for the underlying rule.

Where Palisade fits

Running OpenDKIM yourself means owning key rotation, alignment, and the DNS record for every domain and selector on the box — and quietly discovering months later that one of them stopped signing. Palisade watches DKIM, SPF, and DMARC across all your domains, flags a selector that drops to dkim=fail or falls out of alignment, and keeps enforcement on track whether you self-host with Postfix or send through a platform. Check your current signing and alignment with the Email Security Score.

Questions readers ask

Frequently asked questions

Manage DKIM records through Palisade

Start in Palisade.

Get started

Keep going with AI

Ask AI how this applies to you

Take this guide to your assistant — each question opens pre-filled, with a link back to this page so it can read the details.

  • How do you set up DKIM on Postfix with OpenDKIM?
  • How does this apply to my domain?
  • What should I do about it, step by step?

Share this article

Samuel Chenard

Written by

Samuel Chenard

CEO & Co-Founder, Palisade

Samuel Chenard is the CEO and co-founder of Palisade, AI-first DMARC software for IT teams and MSPs, from one domain to thousands.

More from Samuel

Related articles