Email security for servers: SPF, DKIM, DMARC and MTA-STS

Updated November 2026

Anyone can send mail that claims to come from your domain. SPF, DKIM and DMARC let receivers check that claim and reject fakes. MTA-STS makes other servers use verified TLS when they deliver to you. Gmail and Yahoo now require these basics, so without them your own mail lands in spam or bounces.

Why spoofing and blocklisting happen

SMTP, the protocol that moves mail between servers, has no built-in check on the sender. A spammer can put From: billing@example.com on a message from any server. Receivers therefore look at DNS records that you publish:

SPF (RFC 7208)
A list of servers allowed to send mail for your domain. It checks the hidden envelope sender (the “MAIL FROM” or bounce address), not the visible From.
DKIM (RFC 6376)
Your server signs each message with a private key. Receivers fetch the public key from DNS and check the signature. It survives forwarding as long as the message is not changed.
DMARC (RFC 9989)
Ties SPF and DKIM to the visible From domain (“alignment”), tells receivers what to do with failures, and asks them to send you reports.
MTA-STS (RFC 8461) and TLS-RPT (RFC 8460)
Protect mail coming to you from downgrade and interception, and report TLS problems.

Blocklisting is a separate problem with overlapping causes. Your IP or domain gets listed when spam leaves it: a hacked mailbox password, a vulnerable web form or script, a compromised server, or an open relay. Missing reverse DNS and missing authentication make listings and spam-folder placement more likely. If you are already listed, see IP blacklisted.

What Gmail and Yahoo require

Sender requirements published by Google and Yahoo, checked November 2026
RequirementAll sendersBulk senders
SPF and DKIMSPF or DKIMBoth
DMARC record—Yes; p=none is enough
From domain aligned with SPF or DKIM—Yes
Valid forward and reverse DNS for sending IPsYesYes
Spam complaint rateBelow 0.3%Below 0.3% (Google advises under 0.1%)
One-click unsubscribe—Yes, for marketing mail

Google counts more than 5,000 messages a day to Gmail accounts as bulk, also requires TLS for all senders, and asks for DKIM keys of at least 1024 bits (2048 recommended). Reverse DNS means the PTR record of your sending IP names a host whose A or AAAA record points back to that IP. Set the PTR at your hosting provider.

SPF: list your senders

; server at 203.0.113.10 plus a mailing service
example.com.  IN TXT "v=spf1 mx ip4:203.0.113.10 include:_spf.mail-provider.example -all"

; a domain that never sends or receives mail
parked.example.  IN TXT "v=spf1 -all"
parked.example.  IN MX  0 .

DKIM with OpenDKIM and Postfix

Install the packages: sudo apt install opendkim opendkim-tools on Debian and Ubuntu, or sudo dnf install opendkim opendkim-tools from EPEL on RHEL, Rocky and AlmaLinux. Then make a 2048-bit key. Use a dated selector so you can rotate later:

sudo mkdir -p /etc/opendkim/keys/example.com
sudo opendkim-genkey -b 2048 -d example.com -s s2026 -D /etc/opendkim/keys/example.com
sudo chown -R opendkim:opendkim /etc/opendkim/keys
sudo chmod 600 /etc/opendkim/keys/example.com/s2026.private
sudo cat /etc/opendkim/keys/example.com/s2026.txt     # the DNS record to publish

Publish the contents of s2026.txt as a TXT record at s2026._domainkey.example.com. A 2048-bit key is longer than one 255-character DNS string, so the file splits it into several quoted strings; keep them that way. Set these lines in /etc/opendkim.conf (one domain, one key):

Mode              sv
Domain            example.com
Selector          s2026
KeyFile           /etc/opendkim/keys/example.com/s2026.private
Canonicalization  relaxed/simple
OversignHeaders   From
Socket            inet:8891@localhost
UserID            opendkim

OpenDKIM signs mail from the hosts in InternalHosts (default 127.0.0.1) and verifies the rest. A TCP socket avoids path problems when Postfix runs chrooted. For several domains, use KeyTable and SigningTable instead of the three single-key lines. Connect Postfix in /etc/postfix/main.cf:

smtpd_milters     = inet:localhost:8891
non_smtpd_milters = $smtpd_milters
milter_default_action = tempfail

Note that Postfix writes inet:host:port while OpenDKIM writes inet:port@host. With tempfail (the default), mail waits if OpenDKIM is down; accept sends it unsigned instead. Apply and test. This restarts OpenDKIM and reloads Postfix:

sudo systemctl restart opendkim
sudo postfix check && sudo systemctl reload postfix
sudo opendkim-testkey -d example.com -s s2026 -k /etc/opendkim/keys/example.com/s2026.private -v

Or sign with rspamd

If you already run rspamd for spam filtering, let it sign and don’t add OpenDKIM too. Its default key path is /var/lib/rspamd/dkim/$domain.$selector.key:

sudo rspamadm dkim_keygen -s s2026 -b 2048 -d example.com -k /var/lib/rspamd/dkim/example.com.s2026.key
# prints the DNS record; then in /etc/rspamd/local.d/dkim_signing.conf:
#   selector = "s2026";
#   path = "/var/lib/rspamd/dkim/$domain.$selector.key";
# Postfix main.cf:  smtpd_milters = inet:localhost:11332

Make the key readable only by the user rspamd runs as (check with ps -o user= -C rspamd), then restart rspamd. By default rspamd signs mail from authenticated users and local networks.

DMARC: monitor, then enforce

DMARC passes when SPF or DKIM passes and its domain matches the From domain. By default the match is relaxed, so mail.example.com aligns with example.com. The current standard, RFC 9989 (May 2026), replaced RFC 7489. Records still start with v=DMARC1. It removed the pct tag and added t=y (test mode) and np (policy for subdomains that don’t exist).

; step 1: monitor only
_dmarc.example.com.  IN TXT "v=DMARC1; p=none; rua=mailto:dmarc-reports@example.com"

; final: reject failures, including made-up subdomains
_dmarc.example.com.  IN TXT "v=DMARC1; p=reject; np=reject; rua=mailto:dmarc-reports@example.com"
p=none read reports Fix senders SPF + DKIM aligned p=quarantine failures to spam p=reject failures refused Weeks to months: move on only when reports show no legitimate mail failing
A safe DMARC rollout. Go back a step if reports show real mail failing.
  1. p=none with rua. Receivers send aggregate reports: XML files listing which IPs sent mail as your domain and whether SPF and DKIM passed. Use a report parser or service; they are hard to read by hand.
  2. Fix every legitimate source the reports show: web apps, the CRM, the invoicing system, the newsletter tool. Each needs aligned DKIM, or aligned SPF at least.
  3. p=quarantine. You can add t=y first; receivers then apply one level lower (none instead of quarantine) while you watch.
  4. p=reject. The RFC says a domain with p=reject must sign with DKIM and not rely on SPF alone, because forwarding breaks SPF. It also warns that p=reject on domains whose users post to mailing lists causes trouble for those lists.

If reports go to another domain, that domain must agree: publish example.com._report._dmarc.reports.example.net as a TXT record containing v=DMARC1. Failure reports (ruf) can contain parts of real messages, so think about privacy before you ask for them.

MTA-STS and TLS-RPT

Servers deliver mail to your MX using STARTTLS, but by default a sender falls back to plain text if TLS fails, and does not check your certificate. An attacker on the path can strip TLS. MTA-STS publishes a policy saying “my MX hosts are these, and they have valid certificates; don’t deliver otherwise.”

_mta-sts.example.com.  IN TXT "v=STSv1; id=20261103T1200;"
_smtp._tls.example.com. IN TXT "v=TLSRPTv1; rua=mailto:tls-reports@example.com"

Serve the policy over HTTPS at https://mta-sts.example.com/.well-known/mta-sts.txt as text/plain, with a valid certificate:

version: STSv1
mode: testing
mx: mail.example.com
max_age: 604800

This protects mail to you. Postfix does not check other domains’ MTA-STS policies on its own; the add-on daemon postfix-mta-sts-resolver supplies them through smtp_tls_policy_maps.

Check your setup

dig +short TXT example.com | grep spf1
dig +short TXT s2026._domainkey.example.com
dig +short TXT _dmarc.example.com
dig +short TXT _mta-sts.example.com
dig +short -x 203.0.113.10          # PTR of the sending IP
curl -s https://mta-sts.example.com/.well-known/mta-sts.txt

Then send a message to a Gmail or other outside mailbox and read the Authentication-Results header: you want spf=pass, dkim=pass and dmarc=pass. Keep the mail software itself patched too: see Exim and Postfix. Watch the queue (postqueue -p) for sudden growth, which is often the first sign of a hacked account sending spam.

Sources