Email Security: Hands-on SPF, DKIM, and DMARC Against Spoofing
End-to-end SPF, DKIM, and DMARC setup: DNS records, opendkim key generation and Postfix integration, DMARC policy rollout and report monitoring. Includes verification commands and FAQ.
SPF, DKIM, and DMARC are three defenses against domain spoofing and phishing. This guide covers DNS records and Postfix integration from mechanism to production so operators can build a verifiable mail trust chain.
Scope
Self-hosted mail (Postfix/Exim) or cloud mail (Tencent Exmail, Alibaba Enterprise Mail, etc.) on a company domain. Recipients can verify sender authenticity, cutting spoofed phishing and spam-folder placement.
Prerequisites
- DNS admin rights for the domain (can add TXT records)
- Fixed or enumerable sending IPs / hostnames
- Self-hosted: root and opendkim installed
Mechanism
Each protocol has a job: SPF publishes allowed sender IPs in DNS; the receiver checks the connecting IP. DKIM signs mail with a private key; the receiver verifies with the public key in DNS so the body was not altered. DMARC combines both results, sets fail policy (none/quarantine/reject), and sends aggregate reports to a mailbox you name.
Procedure
1. Configure the SPF record
Add a TXT record for the domain in the DNS panel:
Record type: TXT
Hostname: @ (or blank)
Value: v=spf1 ip4:203.0.113.10 include:_spf.qq.com -all
Key params: ip4 declares your sending IP; include pulls a third-party ESP's SPF; trailing -all rejects anything not listed (use `~all` softfail during rollout).
2. Configure DKIM
# Generate key pair (selector recommended as year-month: 202608)
sudo apt install -y opendkim opendkim-tools
sudo mkdir -p /etc/opendkim/keys/example.com
sudo opendkim-genkey -b 2048 -s 202608 -d example.com -D /etc/opendkim/keys/example.com -v
# Write the p= value from public key 202608.txt into a DNS TXT record
Record type: TXT
Hostname: 202608._domainkey
Value: v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GN... (full public key)
# Configure opendkim and integrate with Postfix
sudo tee /etc/opendkim.conf <<'EOF'
Mode sv
Socket inet:8891@localhost
Selector 202608
Domain example.com
KeyFile /etc/opendkim/keys/example.com/202608.private
EOF
sudo systemctl restart opendkim
sudo postconf -e "milter_default_action = accept"
sudo postconf -e "smtpd_milters = inet:localhost:8891"
sudo postconf -e "non_smtpd_milters = inet:localhost:8891"
sudo systemctl restart postfix
3. Configure DMARC
Record type: TXT
Hostname: _dmarc
Value: v=DMARC1; p=quarantine; rua=mailto:dmarc@example.com; pct=100
Roll out in three steps: p=none and watch reports 1–2 weeks, then p=quarantine, then p=reject. rua receives aggregate reports; pct is the percent of mail the policy applies to.
Verification
# 1. Verify DNS records
dig TXT example.com +short
dig TXT 202608._domainkey.example.com +short
dig TXT _dmarc.example.com +short
# 2. After sending a test email, inspect headers
# Expect:
# spf=pass / dkim=pass / dmarc=pass
grep -i "authentication-results" /var/log/mail.log
Or send a test via mail-tester.com for a combined score and missing-item hints. Enterprise domains should watch delivery in Google Postmaster or the Tencent Cloud email console.
FAQ
Q1: SPF lookup limit exceeded (10 lookups)?
Each include/redirect counts as a DNS lookup; over 10 returns permerror. Shorten the include chain, drop unused third-party includes, and declare IP ranges with `ip4` instead of nested includes.
Q2: DKIM verify fails (dkim=neutral/fail)?
Confirm selector and public key match exactly (the TXT p= value must not wrap or truncate). Check opendkim is listening on 8891: `ss -lntp | grep 8891`, then verify locally with `opendkim-testmsg`. Confirm the From domain matches the signing domain.
Q3: Can I start with p=reject?
No. If a third-party system (e.g. a marketing blast platform) lacks SPF/DKIM, reject drops that mail. Start with p=none, watch rua reports 1–2 weeks, measure pass rate on legitimate mail, then tighten.
Summary
SPF, DKIM, and DMARC form sender authentication: SPF is who may send, DKIM is the body was not changed, DMARC is what to do on fail. The DNS records and Postfix config here can be applied as-is. After go-live, keep watching rua reports and tighten sending paths so the domain's mail trust score rises.