SPF, DKIM and DMARC for Your Own Mail Server: Stay Out of Spam
If mail from your server lands in spam, one of five things is almost always missing: a reverse DNS (PTR) record that matches the server's hostname, an SPF record that authorises its IP, DKIM signing, a DMARC record, and open outbound port 25. Gmail, Yahoo and Outlook now check all of them and reject or junk messages that fail. This guide gives you example DNS records, the commands to verify them and the mistakes we see most often.
The examples use the domain example.com, the mail server mail.example.com with IPv4 203.0.113.10 and IPv6 2001:db8::10. Swap in your own.
Before the records: server basics
Outbound port 25
Many cloud providers block outbound port 25 on new VPSs to curb spam. Without it, your server receives mail but can't deliver any. Check with:
nc -vz -w 5 gmail-smtp-in.l.google.com 25
If it times out, ask your provider to lift the block or send through an SMTP relay (smarthost) such as Amazon SES, Brevo or Mailgun. In that case your SPF record must include the relay, not just your server.
Hostname and A record
The name your server announces in HELO/EHLO must resolve to its address:
mail.example.com. 3600 IN A 203.0.113.10
mail.example.com. 3600 IN AAAA 2001:db8::10
PTR (reverse DNS)
A PTR record maps an IP address back to a name. It must return mail.example.com, and that name must resolve back to the same IP (known as forward-confirmed reverse DNS). You set the PTR in your server provider's control panel, not in your domain's DNS, because the reverse zone belongs to whoever owns the IP block.
dig +short -x 203.0.113.10
# expected: mail.example.com.
dig +short mail.example.com A
# expected: 203.0.113.10
If the server has IPv6, you need a PTR for the IPv6 address too: Gmail often rejects mail arriving from an IPv6 address with no reverse DNS. If you can't set one, send over IPv4 only (in Postfix: smtp_address_preference = ipv4 or inet_protocols = ipv4).
MX
example.com. 3600 IN MX 10 mail.example.com.
The MX must point to a hostname with A/AAAA records, never to an IP address and never to a CNAME.
SPF: who may send for your domain
SPF is a TXT record on the domain listing the servers allowed to send with it in the envelope sender (Return-Path).
example.com. 3600 IN TXT "v=spf1 mx a ip4:203.0.113.10 ip6:2001:db8::10 ~all"
mxandaauthorise the hosts behind the domain's MX and A records;ip4:andip6:authorise specific addresses;include:pulls in a third-party service's senders (for exampleinclude:amazonses.comfor Amazon SES);~all(softfail) marks everything else as suspicious;-all(fail) rejects it.
With DMARC in place, ~all is enough and more forgiving while you change infrastructure; move to -all once you're sure you've listed every sender (newsletter tool, CRM, invoicing app, the website's contact form).
Rules to remember: one SPF record per domain (two v=spf1 records break validation); no more than 10 DNS lookups across include, a, mx, redirect and exists (RFC 7208); subdomains don't inherit the parent's SPF.
DKIM: signing your messages
DKIM signs each message with a private key that stays on your server; the public key sits in DNS under a selector. Receivers check the message wasn't altered and really came from your domain.
The record looks like this (key shortened):
selector._domainkey.example.com. 3600 IN TXT ( "v=DKIM1; k=rsa; "
"p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx..."
"...IDAQAB" )
- Use 2048-bit RSA keys: Google accepts 1024 and up but recommends 2048.
- A TXT value longer than 255 characters must be split into several quoted strings within the same record; some DNS dashboards do this for you, some don't.
- Selectors let you run several keys (one for your server, one for your newsletter service) and rotate them without downtime.
If you're wiring it up by hand with OpenDKIM, generate the key pair like this (opendkim-tools is in the Ubuntu 24.04 repositories):
sudo apt install opendkim opendkim-tools
opendkim-genkey -b 2048 -d example.com -s mail
# creates mail.private (private key) and mail.txt (the record to publish)
DMARC: policy and reports
DMARC tells receivers what to do when a message fails, and sends you reports on who's sending as your domain. Crucially, it adds alignment: the domain in the visible From: header must match the domain verified by SPF or DKIM.
_dmarc.example.com. 3600 IN TXT "v=DMARC1; p=none; rua=mailto:dmarc@example.com; adkim=r; aspf=r"
p=none: monitor only, no effect on delivery;p=quarantine: failing messages go to spam;p=reject: failing messages are refused;rua=: where aggregate reports go (daily XML files from the big mailbox providers);adkimandaspf: alignment mode,r(relaxed, subdomains allowed) ors(strict).
The sensible path: start at p=none, read the reports for a few weeks, fix any failing senders, then step up to quarantine and finally reject. If reports go to a mailbox on a different domain, that domain must authorise it with an example.com._report._dmarc.otherdomain.com record.
MTA-STS and TLS-RPT, briefly
STARTTLS between mail servers is opportunistic, so an attacker in the middle can strip it. MTA-STS (RFC 8461) lets you declare that your domain only accepts mail over TLS with a valid certificate. You need:
- a TXT record at
_mta-sts.example.comwithv=STSv1; id=20260926; - a policy file served over HTTPS at
https://mta-sts.example.com/.well-known/mta-sts.txt:
version: STSv1
mode: testing
mx: mail.example.com
max_age: 604800
TLS-RPT (RFC 8460) adds reports on TLS failures: _smtp._tls.example.com TXT "v=TLSRPTv1; rua=mailto:tls@example.com". Start in mode: testing and switch to enforce only once your mail server's certificate renews reliably. MTA-STS protects inbound mail; Gmail and Yahoo don't require it for delivery.
Gmail, Yahoo and Outlook requirements
Since February 2024 Google has required all senders to Gmail to have SPF or DKIM, valid forward and reverse DNS (PTR), TLS, a reported spam rate below 0.3% and RFC 5322-compliant messages. Anyone sending more than 5,000 messages a day to Gmail needs SPF and DKIM, a DMARC record (p=none is fine), From: alignment and one-click unsubscribe for marketing mail (Google's sender guidelines). Since November 2025 Google has been enforcing this with temporary and permanent rejections for non-compliant traffic (Google's FAQ).
Yahoo asks for the same: SPF or DKIM for everyone; SPF and DKIM plus a valid DMARC record for bulk senders; spam under 0.3%; valid reverse DNS; and unsubscribes honoured within two days (Yahoo Sender Hub). Since May 2025 Outlook.com has enforced SPF, DKIM and DMARC for senders of more than 5,000 messages a day (Microsoft announcement).
Bottom line: even if you send very little, publish all three records. Then the thresholds stop mattering.
How to check everything works
With dig
dig +short MX example.com
dig +short TXT example.com | grep spf1
dig +short TXT selector._domainkey.example.com
dig +short TXT _dmarc.example.com
dig +short -x 203.0.113.10
Query a specific public resolver too (dig @1.1.1.1 ... or dig @8.8.8.8 ...) to see what the rest of the internet sees after a change: the TTL can delay updates.
The mail server's TLS certificate
openssl s_client -starttls smtp -connect mail.example.com:25 -servername mail.example.com </dev/null 2>/dev/null | openssl x509 -noout -subject -dates
A real message
The most reliable test is to email a Gmail or Outlook address you own and open the raw message (in Gmail: ⋮ › Show original). You want SPF: PASS, DKIM: PASS and DMARC: PASS, with your domain in all three. There are also web services that give you an address to write to and return a score; they're handy for a quick check, but the verdict that counts is the recipient provider's. If you send in volume, register your domain with Google Postmaster Tools to track reputation and spam rate.
Common mistakes
- Two SPF records on the same domain, often a leftover from a previous host: merge them into one.
- Too many
includes: past 10 DNS lookups SPF returnspermerror. - Generic or missing PTR (like
vps-203-0-113-10.provider.net), especially on IPv6. - Broken DKIM record: missing quotes, spaces inside the key, or a selector that doesn't match the one used when signing.
- Misaligned
From:: the website sends asinfo@example.comthrough a service that signs with its own domain. - Forwarding to external addresses without sender rewriting (SRS): the original sender's SPF fails at the destination.
- Jumping straight to
p=rejectwithout reading reports: you risk blocking legitimate newsletters and business apps. - A blocklisted IP (Spamhaus, Barracuda, SpamCop), sometimes inherited from the provider's previous customer.
How Koapanel handles it
If you run Koapanel, the optional mail service (Postfix, Dovecot, Rspamd) does most of this for you. Before enabling it, the panel checks outbound port 25, the PTR, the A record of the mail hostname and blocklists, and tells you what to fix. In Server › Mail › Outgoing mail you choose direct delivery or a relay (Brevo, Mailgun, Amazon SES, SMTP2GO, Postmark, SendGrid or another); Run diagnostics tests port 25 to Gmail and Outlook and checks the PTR including IPv6, and Send over IPv4 only avoids rejections when the IPv6 address has no PTR. On Vultr and Hetzner Cloud you can set the PTR straight from the panel with the provider's API key.
When you enable mail on a domain, the panel creates a 2048-bit DKIM key and the Mail DNS tab lists the records to publish, checking what public DNS sees: MX, SPF (v=spf1 mx a ip4:… ~all, with the relay's include if you use one), DKIM under the panel._domainkey selector, DMARC starting at p=none, and optional autoconfig and autodiscover. Full details are in the mail docs.
If your DNS is on a connected Cloudflare account, Set up mail DNS previews the changes and then publishes them, leaving any existing DMARC policy untouched. If the server is the DNS for your domains (this server's DNS, PowerDNS with DNSSEC), MX, SPF, DKIM and DMARC are written into the zone automatically. MTA-STS and TLS-RPT aren't covered in the manual, so you'd publish those by hand.
FAQ
Do I really need all three: SPF, DKIM and DMARC?
Yes. Low-volume senders only strictly need SPF or DKIM for Gmail, but without DMARC and alignment your domain's reputation stays fragile. All three plus a proper PTR is the right starting point.
Should SPF end in ~all or -all?
With DMARC in place ~all is enough and safer while things change. Use -all once you're certain every service that sends for the domain is listed.
Where do I set the PTR record?
In the control panel of the provider that assigned your IP address (Vultr, Hetzner, OVHcloud and so on), not in your domain's DNS.
How long until the records take effect?
It depends on the TTL: from a few minutes to a few hours. Check with dig @8.8.8.8 and dig @1.1.1.1 before running send tests.
I send through an SMTP relay. What changes?
SPF must include the relay (the include: your provider gives you), and the service usually asks you to authenticate the domain with its own DKIM record. Your own server's PTR matters less, because mail leaves from the relay's servers.
Try Koapanel
Want a mail server with DKIM, SPF and DMARC ready to go and every check explained? Install Koapanel for free on a fresh Ubuntu 24.04 server, or look around the public demo. Moving mailboxes from another server? See our guide to migrating email accounts over IMAP.