How to Set Up Postfix DKIM in 2026 (OpenDKIM & Rspamd)

by

Last Updated:
13 min read
How to Set Up Postfix DKIM in 2026 (OpenDKIM & Rspamd)

Key Takeaways

  • Postfix has no built-in DKIM signer, so you attach a milter (OpenDKIM or Rspamd) that signs every outgoing message before it leaves the server.
  • OpenDKIM still works for signing, but upstream activity has been sparse in recent years. Choose it for simple single-domain setups where you can verify current distro support, and prefer Rspamd for multi-domain or production mail.
  • Use 2048-bit RSA keys at minimum; 1024-bit keys are deprecated by RFC 8301. Prefer Ed25519 if both your MTA/milter and DNS provider support it.
  • Most “no signature” failures trace to a socket or permission mismatch. If your Postfix runs smtpd in a chroot (common in some Debian/Ubuntu packages), place the OpenDKIM socket inside the Postfix spool directory and ensure the postfix user can access it (e.g., by adding postfix to the opendkim group).
  • DKIM passing isn’t enough. DMARC needs alignment, so your signing domain must match the From: header, and keys should rotate at least once a year.

DKIM in Postfix is the cryptographic signature you attach to outgoing mail so receiving servers can confirm the message really came from your domain and wasn’t altered in transit. 

Postfix doesn’t do this on its own. You attach a “milter” (a mail filter) that signs every message as it leaves your server.

This guide walks through Postfix DKIM setup end-to-end in 2026: from choosing your milter and generating modern keys to wiring it into Postfix and rotating keys before they become a liability.

OpenDKIM vs. Rspamd: Which Should You Use in 2026?

Before you can sign a single message, you must choose the milter that does the signing. OpenDKIM and Rspamd are the two most common choices for DKIM with Postfix in 2026.

Both will authenticate your outbound mail correctly. However, they differ in how much they ask of you to run, and how confidently you can rely on them going forward.

CriteriaOpenDKIMRspamd
Maintenance statusUpstream activity sparse; last stable release 2.10.3 (May 2015); 2.11.0 branch in beta. Debian testing has flagged it for autoremoval (June 2026) due to a libmemcached dependency bug.Actively developed, frequent releases
What it doesDKIM signing/verification onlyDKIM signing plus full spam filtering
Setup complexitySimple, single purposeMore moving parts up front
Postfix integrationMilter (socket)Milter (proxy socket)
Web UINoneBuilt-in dashboard

OpenDKIM signs the mail correctly, and millions of servers depend on it right now. However, it carries a maintenance risk worth weighing before you build on it. 

The last stable upstream release was 2.10.3 on May 12, 2015. The 2.11.0 branch, which added Ed25519 support, never left beta. OpenDKIM still signs mail reliably and remains packaged by major distributions, but Debian testing has flagged version 2.11.0~beta2 for autoremoval (currently scheduled June 2026) due to a transitive dependency issue with libmemcached, not upstream abandonment per se. Check your distro’s current package status before committing to OpenDKIM for long-term production use.

You can run it today, but you’re building on software whose upstream hasn’t shipped a stable release in a decade, and that’s the long-term risk to weigh. 

Rspamd is the actively maintained alternative. It signs DKIM and filters spam from a single milter, so you run one service instead of two if you also want inbound protection. Postfix is the most common MTA paired with Rspamd, and stacks like Mailcow rely on it for DKIM signing rather than OpenDKIM. 

Here’s how to choose:

  • Choose OpenDKIM if you run a single domain and want the simplest possible setup with DKIM signing and nothing else.
  • Choose Rspamd if you manage multiple domains, send production mail, or build on a stack like Mailcow or iRedMail.

Either way, both paths are covered below. Skip ahead to the one you’ve chosen.

Suggested Read: What is DKIM?

Prerequisites Before You Begin

Before you generate a key or edit a config file, make sure these four things are already in place 

  • A working Postfix installation that already sends mail: DKIM signs the mail your server sends, so the server needs to be sending cleanly first. If Postfix isn’t set up yet, handle that before you continue.
  • DNS access for your domain: Your A and MX records should already be published, and you’ll need to be able to add a TXT record, since that’s where your public key will live.
  • Root or sudo access on the mail server: You’ll be editing system configuration files and restarting services.
  • A DNS provider that accepts long TXT records: A 2048-bit key runs longer than the 255-character limit for a single TXT string, so some providers ask you to split it across two quoted strings. Confirm yours can handle this before you generate the key.

First, pick your key size: 2048-bit RSA, or Ed25519 if both your MTA/milter and DNS provider support it, but never 1024-bit. RFC 8301 prohibits SHA-1 (rsa-sha1 MUST NOT be used) and recommends 2048-bit RSA as a SHOULD-level minimum, while 1024-bit remains the protocol floor (MUST use at least 1024 bits). Weak keys give receivers a reason to distrust your mail.

How to Set Up Postfix DKIM with OpenDKIM

OpenDKIM is the most direct way to add DKIM signing to a single-domain Postfix server, with one daemon, one key, no extra moving parts. These five steps take you from a server sending unsigned mail to one that signs every outbound message with a key that receivers can verify. Each step builds on the last, so follow them in order 

Step 1: Install OpenDKIM

Install two packages: opendkim (the signing daemon itself) and opendkim-tools (the utilities you’ll use to generate keys).

Ubuntu 24.04 / Debian 12:

bash

sudo apt update

sudo apt install opendkim opendkim-tools

RHEL / Rocky 9 (OpenDKIM ships in the EPEL repository):

bash

sudo dnf install epel-release

sudo dnf install opendkim opendkim-tools

Enable the service so it starts on boot:

bash

sudo systemctl enable opendkim

Note: On some distributions, the service name or user/group may differ (e.g., opendkim vs. opendkim-daemon, opendkim:opendkim vs. opendkim:postfix). Check your package docs or systemd unit if commands don’t match.

Step 2: Generate Your DKIM Key Pair

Create a directory to hold the domain’s keys, then generate a 2048-bit pair:

bash

sudo mkdir -p /etc/opendkim/keys/example.com

sudo opendkim-genkey -b 2048 -d example.com -s selector2026 \

  -D /etc/opendkim/keys/example.com/

What each flag does:

FlagMeaning
-b 2048Key size in bits - 2048-bit RSA
-d example.comThe domain you're signing for
-s selector2026The selector name (see note below)
-D /etc/opendkim/keys/example.com/Where to write the output files

On the selector: the -s value is the label that ends up in your DNS record. Use a year-based name like selector2026. It costs nothing now and makes rotation painless later, next year you generate selector2027 and the old record stays live during the changeover.

The command produces two files:

FileWhat it isRule
selector2026.privateYour private signing keyNever share it; keep it readable only by OpenDKIM
selector2026.txtThe public key, formatted for DNSThis is what you publish in Step 5

Now fix ownership. Wrong permissions here are the single most common reason OpenDKIM fails to sign, so don’t skip this:

bash

sudo chown -R opendkim:opendkim /etc/opendkim/keys

sudo chmod 600 /etc/opendkim/keys/example.com/selector2026.private

Adjust user/group if your distro uses different names (e.g., opendkim:postfix). Check your package docs or systemd unit to confirm.

Step 3: Configure OpenDKIM

OpenDKIM reads its main settings from /etc/opendkim.conf, then uses three small lookup files to decide what to sign and with which key. Set the core directives first:

Syslogyes
UMask2
Modes
Canonicalizationrelaxed/relaxed
Socketlocal:/var/spool/postfix/opendkim/opendkim.sock
PidFile/run/opendkim/opendkim.pid
OversignHeadersFrom
KeyTable/etc/opendkim/key.table
SigningTablerefile:/etc/opendkim/signing.table
ExternalIgnoreList/etc/opendkim/trusted.hosts
InternalHosts/etc/opendkim/trusted.hosts

What the important directives do:

DirectiveWhat it controls
Mode sSign only. Use sv if you also want OpenDKIM to verify inbound mail.
Canonicalization relaxed/relaxedTolerates minor whitespace changes in transit, which keeps signatures valid. Note: canonicalization does not control DMARC alignment. DMARC alignment depends on whether the d= domain in the DKIM signature matches the From: header domain, not on the canonicalization setting.
SocketWhere OpenDKIM listens for Postfix. This path must match what you set in Postfix later.
OversignHeaders FromSigns the From header so an attacker can't add a second one, a small but real anti-spoofing measure.
KeyTable / SigningTableThe two lookup files that connect domains to selectors to keys (below).

Then create the three lookup files. Each has one job:

FileJobExample line
signing.tableMaps a sender to a selector*@example.com selector2026._domainkey.example.com
key.tableMaps that selector to its private key on diskselector2026._domainkey.example.com example.com:selector2026:/etc/opendkim/keys/example.com/selector2026.private
trusted.hostsLists hosts whose outbound mail should be signed127.0.0.1 / localhost / ::1 / example.com

Step 4: Connect OpenDKIM to Postfix

This is where most setups break, and the cause is almost always the socket. OpenDKIM creates a socket file to talk to Postfix. If your Postfix runs smtpd in a chroot, which is the default in Debian/Ubuntu packages, but not the upstream Postfix default or RHEL/Rocky,  it is locked inside /var/spool/postfix and cannot see a socket outside that directory. The two never connect, and your mail goes out unsigned.

The fix is to place the socket inside Postfix’s spool directory and give the postfix user permission to reach it. Follow these in order:

1. Create the socket directory inside Postfix’s spool:

bash

sudo mkdir -p /var/spool/postfix/opendkim

sudo chown opendkim:postfix /var/spool/postfix/opendkim

Adjust the group if your distro uses opendkim:opendkim instead.

2. Add the postfix user to the opendkim group so it can read the socket:

bash

sudo gpasswd -a postfix opendkim

3. Confirm the runtime socket path matches opendkim.conf. On Ubuntu/Debian, set it in /etc/default/opendkim (or the systemd override):

  SOCKET=”local:/var/spool/postfix/opendkim/opendkim.sock”

4. Point Postfix at the milter in /etc/postfix/main.cf:

milter_default_action = accept

   milter_protocol = 6

   smtpd_milters = local:opendkim/opendkim.sock

   non_smtpd_milters = $smtpd_milters

What those four Postfix directives mean:

DirectivePurpose
milter_default_action = acceptIf the milter is down, mail still flows, a dead signer never silently blackholes your queue.
milter_protocol = 6The milter protocol version current OpenDKIM uses.
smtpd_miltersApplies the milter to mail received over SMTP (your outbound submissions).
non_smtpd_miltersApplies it to mail not received over SMTP, e.g. generated locally.

The socket path in main.cf is relative, local:opendkim/opendkim.sock, not the full filesystem path, because Postfix is reading it from inside its chroot.

Restart both services to apply everything:

bash

sudo systemctl restart opendkim

sudo systemctl restart postfix

Step 5: Publish the DKIM DNS TXT Record

Open the public-key file you generated in Step 2:

bash

sudo cat /etc/opendkim/keys/example.com/selector2026.txt

Publish its contents at your DNS provider as a new record:

FieldValue
Record nameselector2026._domainkey.example.com
TypeTXT
ValueEverything inside the parentheses (the v=DKIM1; k=rsa; p=... string)

Since this is a 2048-bit key, the value runs longer than the 255-character limit for a single TXT string. Most DNS providers split it automatically. If yours rejects it, break the public key across two quoted strings inside the same record that the .txt file already shows you where the split falls.

Set the TTL to 300 seconds during setup so any mistake is cheap to correct. Once you’ve confirmed signing works, raise it to 3600.

Step 6: Verify before you send

DNS takes time to propagate, and a 2048-bit key split incorrectly will look fine in your zone editor but fail the moment a receiver reads it. 

Rspamd is the stronger choice once you’re past a single domain or running production mail. It signs DKIM and filters spam from one milter, so you maintain one service instead of two.

Also, since it looks up keys by domain automatically, adding your next domain becomes a one-line change rather than a new setup. Here’s the full path on Postfix, in five steps.

Step 1: Install Rspamd

The version in your distro’s base repos is usually outdated, so install from Rspamd’s official stable repository.

bash

sudo apt install -y lsb-release wget gpg

sudo mkdir -p /etc/apt/keyrings

wget -O- https://rspamd.com/apt-stable/gpg.key | \

  gpg –dearmor | sudo tee /etc/apt/keyrings/rspamd.gpg > /dev/null

echo “deb [signed-by=/etc/apt/keyrings/rspamd.gpg] \

  http://rspamd.com/apt-stable/ $(lsb_release -cs) main” | \

  sudo tee /etc/apt/sources.list.d/rspamd.list

sudo apt update && sudo apt install rspamd

Enable it to start on boot:

bash

sudo systemctl enable rspamd

Always check rspamd.com for the latest installation instructions, as the repository URL and GPG key steps change occasionally.

Step 2: Generate Your DKIM Key

Rspamd ships its own key generator, rspamadm dkim_keygen with no separate tools package needed. It writes the private key to a file and prints the public key (your DNS record) to the screen, which you capture into a .pub file.

bash

sudo mkdir -p /var/lib/rspamd/dkim

sudo rspamadm dkim_keygen -s selector2026 -b 2048 -d example.com \

  -k /var/lib/rspamd/dkim/example.com.selector2026.key | \

  sudo tee /var/lib/rspamd/dkim/example.com.selector2026.pub

sudo chown -R _rspamd:_rspamd /var/lib/rspamd/dkim

Adjust user/group if your distro uses rspamd:rspamd instead of _rspamd:_rspamd. Check your package’s systemd unit to confirm.
The flags mirror OpenDKIM’s: -s selector, -b 2048 key size, -d domain, -k the private-key output file. You end up with two files:

FileWhat it is
example.com.selector2026.keyThe private signing key Rspamd uses. Keep it owned by the _rspamd user
example.com.selector2026.pubThe public key, formatted for DNS, you publish this in Step 5

Step 3: Enable DKIM Signing

Rspamd handles DKIM through its dkim_signing module. Turn it on and tell it where your keys live in /etc/rspamd/local.d/dkim_signing.conf

selector = “selector2026”;

path = “/var/lib/rspamd/dkim/$domain.$selector.key”;

allow_username_mismatch = true;

use_domain = “header”;

What each setting does:

SettingWhat it controls
selectorThe selector name, must match your key filename and DNS record
pathWhere Rspamd finds the private key; $domain and $selector are filled in automatically
allow_username_mismatchSigns even when the authenticated username doesn't match the From domain
use_domain = "header"Picks the signing domain from the message's From header

That path line is what makes Rspamd strong for multiple domains. Since it resolves $domain and $selector by filename, adding another domain means dropping its key in the same folder with no new config block, no second daemon.

Step 4: Connect Rspamd to Postfix

Point Postfix at Rspamd’s milter in /etc/postfix/main.cf. The directives are identical to the OpenDKIM setup, only the socket changes:

milter_default_action = accept

milter_protocol = 6

smtpd_milters = inet:localhost:11332

non_smtpd_milters = $smtpd_milters

Rspamd listens on its proxy worker at TCP port 11332 by default. Since it’s a network socket, you skip the chroot socket-permission problem that trips up OpenDKIM. The only line that differs between the two milters:

MilterSocket line in main.cf
OpenDKIMsmtpd_milters = local:opendkim/opendkim.sock
Rspamdsmtpd_milters = inet:localhost:11332

Step 5: Publish the DNS Record

Open the public key and publish it exactly as in the OpenDKIM Step 5 with the same record name format, TXT type, and 255-character split rule for the 2048-bit key:

bash

sudo cat /var/lib/rspamd/dkim/example.com.selector2026.pub

Optionally, enable the web dashboard by setting a password in /etc/rspamd/local.d/worker-controller.inc 

It gives you a live view of signing and spam activity. Then restart both services:

bash

sudo systemctl restart rspamd postfix

Verify the published record with a DKIM checker before you rely on it, the same way you would after the OpenDKIM setup.

Rspamd replaces both OpenDKIM and SpamAssassin. If you were running a separate spam filter, you can retire it here so you have fewer services, a smaller config surface, and one place to manage both signing and filtering.

Configuring Postfix DKIM for Multiple Domains

Running several domains off one Postfix server is normal, but DKIM doesn’t cut corners for it. Every domain you send from needs its own key pair and its own DNS record, because each one is authenticated independently, so there’s no shared key that covers them all. How you scale depends on the milter you chose.

With OpenDKIM, you extend the tables you already built: Generate a key for each new domain, then add one line for it in each lookup file.

In signing.table:

*@example.com    selector2026._domainkey.example.com

*@example.net    selector2026._domainkey.example.net

In key.table:

selector2026._domainkey.example.com    example.com:selector2026:/etc/opendkim/keys/example.com/selector2026.private

selector2026._domainkey.example.net    example.net:selector2026:/etc/opendkim/keys/example.net/selector2026.private

Each new domain is one more key and two more lines, manual, but predictable.

With Rspamd, the work is already done for you: Since the path setting uses the $domain variable, Rspamd finds each domain’s key by filename automatically. Drop example.net.selector2026.key into the same directory and it signs that domain too without any config change required. If you want tighter control, you can still add per-domain blocks in dkim_signing.conf.

Two habits keep multi-domain signing manageable:

  1. Use the same selector across every domain, selector2026 everywhere, so rotation stays one process instead of several. 
  2. Publish a separate DNS record for each domain: miss it on one, and that domain’s mail signs locally but fails verification at the receiver.

How to Test and Verify Your Postfix DKIM Configuration

Signing mail and confirming it’s signed correctly are two different things. From the sending side everything can look fine while a receiver quietly rejects your signature, and you wouldn’t know until deliverability slips. 

These five checks confirm DKIM is actually working, moving from your own logs outward to a real receiver. Follow the below order:

Check 1: Check the mail log first

Mail log is the fastest confirmation, and it’s local. Tail the log, send a test message, and watch for a signing entry:

bash

  sudo tail -f /var/log/mail.log

On RHEL/Rocky the file is /var/log/maillog. You’re looking for a line showing the message was signed with your selector. If it’s there, your milter is doing its job.

Check 2: Validate the key against DNS (OpenDKIM)

Validation confirms the private key on disk matches the public key you published:

bash

  opendkim-testkey -d example.com -s selector2026 -vvv

key OK means the two halves match. Anything else points to a DNS typo or a key mismatch, which needs to be fixed before going further.

Check 3: Send a real test

This is the only check that proves a receiver accepts your signature. Email a Gmail account, open the message, and choose “Show original.” Look for DKIM: ‘PASS’ with your domain, which means the receiving server is confirming that your signature is verified.

Check 4: Run external checkers

A DKIM checker fetches and parses your published record the way a receiving server would, confirming the key is valid and complete

Try PowerDMARC’s free DKIM Checker, then send a message to mail-tester.com for a broader deliverability score that weighs DKIM alongside SPF, DMARC, and spam signals. 

Check 5: Watch for the DKIM-passes-but-DMARC-fails trap

Your signature can verify perfectly and DMARC can still fail, because DMARC needs alignment: the domain in your DKIM d= tag has to match the domain in the visible From: header. 

Sign as mail.example.com while sending From example.com and relaxed alignment will save you, but strict won’t. If DMARC fails despite a passing DKIM, check that your signing table maps to the right domain.

Check 6: Audit all three in one pass

A passing DKIM check confirms whether a part of authentication works, but your deliverability and spoofing protection depend on DKIM, SPF, and DMARC pulling together. 

PowerDMARC’s free Domain Analyzer scans all three at once and returns an A–F score, so in a single pass you learn whether your domain is actually protected end to end or just partly covered. 

When you see issues like the DKIM-passes-but-DMARC-fails trap, the free Email Header Analyzer puts the DKIM verdict and the alignment result side by side, so you pinpoint the exact mismatch in seconds instead of squinting at raw headers. 

Postfix DKIM Key Rotation

A private key that sits on a server untouched for years is a key with a growing chance of exposure. If it ever leaks, an attacker can sign mail as your domain until you catch it.

Rotating on a schedule, at least once a year, keeps that window small. The year-based selector makes the swap clean.

The rotation process:

  1. Generate a new key with a new selector – selector2027.
  2. Publish the new public key as a new DNS TXT record, and leave the old record in place.
  3. Update your config to sign with the new selector.
  4. Reload the milter and wait for the DNS TTL to propagate.
  5. Keep the old record live for at least the previous TTL plus 24–48 hours (commonly 48–72 hours total), depending on your TTL and volume of in-flight mail. Mail already in flight, signed with the old key, still needs to verify.
  6. Retire the old selector and remove its DNS record.

The overlap in steps 5 and 6 is the part you can’t rush. Pull the old record too early and any message still being checked against it fails verification, exactly the kind of silent authentication failure DKIM is supposed to prevent.

Neither OpenDKIM nor Rspamd automate the key generation, the DNS publishing, or the overlap timing. For a single domain, that’s a once-a-year calendar reminder. Across five or more, it becomes a recurring task that’s easy to let slip, and a rotation that quietly never happens is a compliance gap you won’t notice until someone asks you to prove it.

Common Postfix DKIM Errors and How to Fix Them

DKIM problems on Postfix often cluster around a few predictable causes, mostly socket permissions, key paths, and domain alignment. The table below pairs the symptom you’re seeing with its most likely cause and the fix, so you can jump straight to yours. 

ErrorLikely CauseFix
No DKIM signature in headersMilter not connected or socket mismatchConfirm the socket path matches in opendkim.conf and main.cf; check the postfix user is in the opendkim group
connect to Milter service... Connection refusedOpenDKIM daemon not runningsystemctl start opendkim; confirm the socket file actually exists in the spool dir
opendkim: key retrieval failedWrong path in key table or bad permissionsVerify the .private path in key.table; run chown opendkim:opendkim on the key
DKIM passes but DMARC failsAlignment mismatchThe signing domain (d=) must match the From: header domain; use relaxed alignment
2048-bit key rejected by DNSProvider's 255-char TXT limitSplit the public key across two quoted strings in the same TXT record

When to Move Beyond Manual Postfix DKIM

For a single domain, self-managed DKIM on Postfix is a perfect choice. You configure it once, and it does its job, but as your sending grows, the manual work behind it turns into a source of risk rather than control. 

A few signs you’ve reached that point:

  • You’re signing for three or more domains.
  • Mail leaves from multiple sources, an ESP, transactional mail, your app, each needing its own keys.
  • You have a compliance deadline and can’t afford a missed rotation.
  • One person holds all the DKIM knowledge, and their departure would take it with them.

If you are facing these challenges, hosted DKIM management closes those gaps by removing the manual steps entirely. Here’s how manual DKIM management differs from hosted DKIM management:

TaskManual (OpenDKIM / Rspamd)Hosted DKIM
Key rotationBy hand each cycle: generate, publish, overlap, retireAutomatic, no DNS edit per cycle
Multiple domainsSeparate key, record, and config per domainManaged centrally
Key size2048-bit (or Ed25519)Up to 4096-bit
Selector managementTracked manuallyAuto-detected for major ESPs
DNS maintenanceEdited on every rotationA single CNAME, published once

If you’re managing DKIM across several domains or need compliance-grade rotation you can count on, PowerDMARC’s Hosted DKIM removes the manual overhead, and the risk that comes with it. 

Start your 15-day free trial

Frequently Asked Questions

What is Postfix DKIM?

Postfix DKIM is the cryptographic signing of outbound mail on a Postfix server, so receivers can confirm it came from your domain unaltered. Postfix has no built-in signer, so it hands each message to a milter, OpenDKIM or Rspamd, that adds the signature.

What is OpenDKIM?

OpenDKIM is a standalone milter that signs and verifies DKIM for Postfix and other MTAs, and nothing else. It’s simple and widely deployed, but has had no stable release since 2021, so weigh that maintenance risk for long-term setups.

What is Rspamd?

Rspamd is an actively maintained spam-filtering system whose DKIM signing module can sign Postfix mail. Since it handles filtering and signing in one milter, it replaces both OpenDKIM and SpamAssassin, the stronger 2026 choice for multi-domain or production servers.

What is Postfix?

Postfix is a widely used open-source mail transfer agent (MTA) that routes and delivers email on Unix-like servers. It sends and receives mail but does not sign DKIM on its own, that requires a separate milter like OpenDKIM or Rspamd.

Should I use OpenDKIM or Rspamd with Postfix in 2026?

For single-domain, simple setups, OpenDKIM still works fine. For multi-domain or production servers, Rspamd is the better choice. It’s actively maintained and combines DKIM signing with spam filtering in one milter.

How do I verify DKIM is signing my outbound mail?

Check /var/log/mail.log for signing entries, run opendkim-testkey, send a test email to Gmail and inspect the raw headers for DKIM: PASS, or run your domain through a free DKIM checker.

CTA