How to set up SPF, DKIM and DMARC with copy-paste examples
Every large mailbox provider now checks SPF, DKIM and DMARC before deciding whether your message reaches the inbox, the spam folder, or gets dropped silently. This guide explains what each record actually proves, gives copy-paste examples for a domain that sends from its own server plus a newsletter service, and shows how to tighten DMARC policy without breaking your own mail. It is written for anyone who manages DNS for a domain that sends email.
What each record actually proves
SPF is a TXT record on your domain that lists the IP addresses allowed to use the domain in the SMTP envelope sender (Return-Path). A pass proves only that the sending server was on your list. It says nothing about the From address the user sees, and it breaks when mail is forwarded.
DKIM is a cryptographic signature your mail server adds to each message. The public key sits in DNS under a selector, for example s1._domainkey.example.com. A pass proves the message body and key headers were not modified since someone holding your private key signed them. It survives forwarding.
DMARC ties both checks to the visible From domain (this is called alignment) and publishes a policy telling receivers what to do when both fail: do nothing, quarantine, or reject. It also asks receivers to send you reports. Without DMARC, SPF and DKIM results are only advisory signals.
Copy-paste records for a typical setup
Assume example.com sends transactional mail from its own server at 192.0.2.10 and newsletters through a third-party service. Adjust names and IPs to your own values.
SPF, one TXT record at the domain apex:
example.com. TXT "v=spf1 ip4:192.0.2.10 include:servers.mcsv.net -all"
The include comes from your newsletter provider's documentation, the one above is Mailchimp's. Add mx or a mechanisms only if those hosts really send mail.
DKIM: generate a 2048-bit key pair on the server:
openssl genrsa -out dkim-private.pem 2048 openssl rsa -in dkim-private.pem -pubout -outform der | openssl base64 -A
Publish the base64 output as a TXT record:
s1._domainkey.example.com. TXT "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQ...AQAB"
Then point your MTA (OpenDKIM, rspamd, Exim, whatever you run) at the private key with selector s1. The newsletter service signs with its own keys: it will give you two or three CNAME records to add so its signatures align with your domain. Add them, otherwise the newsletters will fail DMARC later.
DMARC, start in monitoring mode:
_dmarc.example.com. TXT "v=DMARC1; p=none; rua=mailto:dmarc-reports@example.com"
Verify everything from any machine:
dig +short TXT example.com dig +short TXT s1._domainkey.example.com dig +short TXT _dmarc.example.com
Then send a test message to a Gmail address and use Show original: you want spf=pass, dkim=pass and dmarc=pass on one screen.
SPF mistakes that actually hurt
- Two SPF records. The standard allows exactly one. If a control panel or a SaaS wizard adds a second one, receivers return permerror and treat it as a fail. Merge all mechanisms into a single record.
- +all. This authorizes the entire internet to send as your domain. Spam filters know that, and some score it as a spam signal by itself. End with
-all, or~allwhile you are still migrating senders. - Too many DNS lookups. SPF allows at most 10 mechanisms that query DNS (
include,a,mx,redirect). Nested includes from a few SaaS tools burn through the limit fast, and the result is again permerror. Count your lookups with any SPF checker, remove services you no longer use, and replacea/mxwith literalip4entries where addresses are stable.
DKIM key rotation basics
A leaked DKIM key lets an attacker sign mail that passes DMARC, and you will not notice from the outside. Rotating once or twice a year keeps the damage window small. Selectors make rotation painless:
- Generate a new key pair and publish it under a new selector, for example
s2._domainkey. - Wait out the DNS TTL, then switch your MTA to sign with
s2. - Leave the old
s1record in DNS for about a week so queued and in-transit mail still verifies, then delete it.
Stay at 2048 bits. Some DNS panels require long p= values split into quoted 255-character chunks; that is fine, resolvers join them back together.
DMARC: from none to reject without breaking anything
- Run
p=nonewithruareporting for at least two to four weeks. Nothing is blocked yet, you are only collecting data. - Fix every legitimate source that fails alignment. The usual suspects: the website contact form, an invoicing tool, a CRM someone connected two years ago.
- Move to
p=quarantine; pct=25, then raisepctto 100 as reports stay clean. Failing mail now goes to spam instead of the inbox. - Finish with
p=reject. Forwarders and mailing lists break SPF regularly, so only go here once DKIM signs everything you send: aligned DKIM survives forwarding and keeps DMARC passing.
Subdomains inherit the policy unless you set sp= separately. If a subdomain never sends mail, an explicit v=spf1 -all plus a reject policy for it closes a common spoofing hole.
Reading DMARC reports without drowning
Aggregate (rua) reports arrive as zipped XML, one per receiver per day. Nobody reads those raw for long. Feed them into a parser: self-hosted parsedmarc works well, and several web dashboards have free tiers. Then check weekly for exactly two things:
- Legitimate sources that fail: fix their SPF include or DKIM signing before you tighten the policy.
- Unknown IPs sending volume as your domain: that is spoofing, and it is exactly what your reject policy will cut off.
Ignore forensic (ruf) reports, most large receivers no longer send them. All three records are plain DNS, so nothing here depends on where the mailbox lives: if your domain runs through our domain registration, you edit these TXT records in the same DNS panel, and on our web hosting plans SPF and DKIM records for the included mail service can be generated from the control panel. Set p=none today, read the first reports next week, and you are already ahead of most senders.