Skip to main content

SPF, DKIM, and DMARC: Complete Email Protection Setup

Domains · 19.04.2026 · 6 min read
Illustration for “SPF, DKIM, and DMARC: Complete Email Protection Setup”

On a VPS running your own Postfix, the entire responsibility for outbound mail reputation falls on you: there's no pre-warmed, pre-configured provider infrastructure behind it. DKIM, SPF, and DMARC on a self-managed mail server aren't optional hardening — they're the minimum without which mail starts landing in spam or getting rejected from day one.

Installing OpenDKIM

apt install opendkim opendkim-tools -y

# Generate keys
mkdir -p /etc/opendkim/keys/yourdomain.com
cd /etc/opendkim/keys/yourdomain.com
opendkim-genkey -t -s mail -d yourdomain.com
chown opendkim:opendkim mail.private

Getting the public key for DNS

cat /etc/opendkim/keys/yourdomain.com/mail.txt
# Add this record to DNS as TXT for:
# mail._domainkey.yourdomain.com

Full set of DNS records

RecordTypeNameValue
MXMX@mail.yourdomain.com (priority 10)
SPFTXT@v=spf1 mx ~all
DKIMTXTmail._domainkeyv=DKIM1; k=rsa; p=PUBLICKEY
DMARCTXT_dmarcv=DMARC1; p=none; rua=mailto:dmarc@yourdomain.com

Unlike managed mail services, where the provider hands you MX, SPF, and DKIM as an already-consistent set, on a VPS all four records are assembled by hand and must reference each other without contradiction: the domain in MX, the domain in SPF, and the selector in the DKIM record's name all have to match what's actually configured in Postfix and OpenDKIM.

Verifying the DKIM signature

# Test the signature
opendkim-testkey -d yourdomain.com -s mail -vvv

# Check after sending
# The email header should contain:
# DKIM-Signature: v=1; a=rsa-sha256; d=yourdomain.com; s=mail...
💡 Start with p=none in DMARC — this is monitoring mode. After a week of reviewing reports, move to p=quarantine, then p=reject.

Common OpenDKIM Errors

MessageCauseFix
opendkim: mail.private: No such file or directoryThe KeyFile path in /etc/opendkim.conf doesn't match where the key actually livesCompare the path in the config against the output of ls /etc/opendkim/keys/yourdomain.com/
body hash did not verify (DKIM-Signature)The message changed after signing — for example, an intermediate server added a mailing-list footerExclude such routes from the relay, or sign the message after all body modifications
key not found in DNS (opendkim-testkey)The TXT record hasn't propagated yet, or the selector in DNS doesn't match the name in the configCheck dig TXT mail._domainkey.yourdomain.com and wait out the TTL
Postfix: reject: 550 5.7.1 SPF check failedThe outbound server's IP isn't included in the sending domain's SPF record (a third-party relay)Ask the sending domain's owner to add the server's IP to their SPF via an ip4: mechanism

For any of these errors, the first step is checking /var/log/mail.log (Debian/Ubuntu) or /var/log/maillog (RHEL family): it shows exactly at what stage Postfix and the OpenDKIM milter processed the message and with what rejection code, rather than guessing based on symptoms seen at the recipient's end.

From p=none to p=reject: a DMARC Rollout Plan

Stagep valueDurationWhat happens
Monitoringp=none1–2 weeksrua reports are collected, no message is blocked
Partial quarantinep=quarantine; pct=251 weekA quarter of failing messages get sent to recipients' spam folders
Full quarantinep=quarantine; pct=1001–2 weeksAll failing messages go to spam
Rejectionp=rejectongoingMessages without valid DKIM/SPF are rejected on receipt

On a self-hosted VPS, rua reports arrive as an ordinary email to the address you specified, containing XML inside a gzip archive — there's no ready-made dashboard for reading them the way large mail providers offer. In practice they're either parsed with a homegrown script, or forwarded to a free third-party service like dmarcian, which turns them into a readable table of sending sources for you.

Verifying SPF and DMARC Records

# Check the published SPF record
dig TXT yourdomain.com +short

# Check the DMARC record and its current policy
dig TXT _dmarc.yourdomain.com +short

# Quick online check by sending a message
# mail-tester.com — returns an SPF/DKIM/DMARC breakdown within seconds

When DKIM/SPF/DMARC on a VPS Doesn't Fit

  • Mail is sent through several external mailing services at once — you need a single SPF record with an include for each service, not separate TXT records: a zone only allows one SPF-type record
  • The server's IP is in a PBL or a dynamic provider range — DKIM won't save you from a block based on the IP's own reputation; a dedicated static address is needed
  • You need zero-downtime key rotation — you'll need to run two selectors in parallel, for example mail and mail2, and switch between them
  • Mail is already hosted on Google Workspace or another SaaS — DKIM is configured on the provider's side, see Google Workspace: MX and DNS, not through OpenDKIM on a VPS

Frequently asked questions

Is it safe to jump straight to p=reject in DMARC without a monitoring period?

Jumping straight to p=reject is risky: if DKIM or SPF is misconfigured, legitimate mail starts getting rejected by recipients before you even notice. The monitoring phase with p=none exists precisely so you can see the real sending sources through rua reports and confirm your own mail passes authentication before tightening the policy.

What happens if mail goes out through several external sending services at once?

A DNS zone only allows one record of the SPF type, so you can't add a separate SPF record per sending service — every sending source has to be listed through an include mechanism inside the domain's single SPF record. Add multiple separate SPF records instead, and verification becomes unpredictable, with some mail getting rejected regardless of DKIM.

How do I read DMARC (rua) reports without a ready-made dashboard like the big mail providers offer?

On a self-hosted VPS these reports arrive as an ordinary email containing a compressed archive with markup inside — reading them by eye is impractical. In practice they're either parsed with a small homegrown script or forwarded to a free third-party service such as dmarcian, which builds a table of sending sources and highlights what passes authentication and what doesn't.

Do I need to change DKIM settings when moving mail to Google Workspace or another SaaS?

Yes, the OpenDKIM configuration on the VPS becomes unnecessary in that case: the provider generates the key and signature on its own side, and all you need to do is add its records to the domain's DNS. The old OpenDKIM setup and the SaaS provider shouldn't both sign the same mail at once — that creates confusing, conflicting authentication results.

Was this article helpful?
← Back to Knowledge Base Ask Support