If you’re running a self-hosted mail server, getting your emails delivered reliably means implementing three authentication standards: SPF, DKIM, and DMARC. Without them, your legitimate email will land in spam — or be rejected entirely. This guide explains each standard and shows you exactly how to set them up.
Why Email Authentication Matters
Email was designed without authentication, which made spoofing trivial. These three DNS-based standards fix that:
| Standard | What It Does |
|---|---|
| SPF | Declares which servers are allowed to send email for your domain |
| DKIM | Cryptographically signs outgoing emails to prove they weren’t tampered with |
| DMARC | Ties SPF and DKIM together; tells receivers what to do when checks fail |
All three are DNS TXT records — no software to install for SPF and DMARC. DKIM requires a small daemon (opendkim).
Part 1: SPF (Sender Policy Framework)
SPF is a DNS TXT record on your domain that lists all IP addresses authorized to send mail for it.
Create the record:
For a server at 203.0.113.10 sending email for example.com:
example.com. IN TXT "v=spf1 ip4:203.0.113.10 ~all"
Breakdown:
v=spf1— SPF versionip4:203.0.113.10— authorize this IPv4 address~all— softfail for anything else (use-allfor hardfail once you’re confident)
If you use a relay service (like Amazon SES or SendGrid), include their SPF record:
"v=spf1 ip4:203.0.113.10 include:amazonses.com ~all"
Verify:
dig TXT example.com +short
# Should show your SPF record
Or use:
nslookup -type=TXT example.com
Part 2: DKIM (DomainKeys Identified Mail)
DKIM adds a cryptographic signature to outgoing emails. The public key is published in DNS; the private key is used by your mail server to sign messages.
Install OpenDKIM
sudo apt update
sudo apt install opendkim opendkim-tools -y
Generate a Key Pair
sudo mkdir -p /etc/opendkim/keys/example.com
sudo opendkim-genkey -b 2048 -d example.com -s mail -D /etc/opendkim/keys/example.com/
sudo chown -R opendkim:opendkim /etc/opendkim/keys/
This creates:
/etc/opendkim/keys/example.com/mail.private— private key (never share)/etc/opendkim/keys/example.com/mail.txt— DNS record to publish
Publish the DNS Record
View the generated record:
cat /etc/opendkim/keys/example.com/mail.txt
It looks like:
mail._domainkey IN TXT ( "v=DKIM1; k=rsa; "
"p=MIIBIjANBgkq..." )
Create a DNS TXT record:
- Name:
mail._domainkey.example.com - Value: paste the full
p=...value (without the parentheses)
Configure OpenDKIM
Edit /etc/opendkim.conf:
Mode sv
Canonicalization relaxed/simple
Domain example.com
Selector mail
KeyFile /etc/opendkim/keys/example.com/mail.private
Socket inet:8891@localhost
Create /etc/opendkim/TrustedHosts:
127.0.0.1
localhost
example.com
Integrate with Postfix
In /etc/postfix/main.cf, add:
milter_protocol = 2
milter_default_action = accept
smtpd_milters = inet:localhost:8891
non_smtpd_milters = inet:localhost:8891
Restart both:
sudo systemctl restart opendkim
sudo systemctl reload postfix
Verify DKIM
Send a test email to check-auth@verifier.port25.com — you’ll get an automated reply with DKIM pass/fail.
Or use MXToolbox DKIM Lookup for mail._domainkey.example.com.
Part 3: DMARC
DMARC ties SPF and DKIM together and gives mailbox providers instructions on what to do when checks fail.
Create the record (_dmarc.example.com):
_dmarc.example.com. IN TXT "v=DMARC1; p=none; rua=mailto:dmarc@example.com"
Policy options (p=):
none— monitor only, take no action (start here)quarantine— send failing messages to spamreject— reject failing messages outright
Start with p=none and review the aggregate reports (rua) for 2–4 weeks before moving to quarantine or reject.
Example strict policy (after validation):
"v=DMARC1; p=reject; pct=100; rua=mailto:dmarc@example.com; aspf=s; adkim=s"
pct=100— apply policy to 100% of failing messagesaspf=s— strict SPF alignmentadkim=s— strict DKIM alignment
Verify Everything
Use the following to check all three from the command line:
# SPF check via nslookup
nslookup -type=TXT example.com
# DKIM check
nslookup -type=TXT mail._domainkey.example.com
# DMARC check
nslookup -type=TXT _dmarc.example.com
Or use an online tool like MXToolbox Email Health for a comprehensive report.
BIMI (Bonus)
Once DMARC is at p=quarantine or p=reject, you can add BIMI (Brand Indicators for Message Identification) — a logo that appears in Gmail and other clients:
default._bimi.example.com. IN TXT "v=BIMI1; l=https://example.com/logo.svg"
Summary
| Step | Record | Where |
|---|---|---|
| SPF | example.com TXT "v=spf1 ..." | Your domain DNS |
| DKIM | mail._domainkey.example.com TXT "v=DKIM1; ..." | Your domain DNS |
| DMARC | _dmarc.example.com TXT "v=DMARC1; p=none; ..." | Your domain DNS |
With all three in place, you’ll pass email authentication checks at Gmail, Outlook, Yahoo, and every major inbox provider.