MX, SPF, DKIM and DMARC Explained: How They Fit Together
How MX, SPF, DKIM and DMARC work together, the mistakes that break them, and a safe way to roll out DMARC without losing legitimate email.
Published: · 7 min read
Four DNS record types decide how email for your domain is delivered and whether receivers believe it is really yours. They are usually explained one at a time, which hides the most important point: each one covers a gap the others leave open.
This guide walks through all four, the mistakes that show up most often in real zones, and a rollout order that does not put your legitimate mail at risk.
The short version
- MX says where mail to your domain should be delivered.
- SPF says which servers may send mail using your domain in the envelope sender.
- DKIM attaches a cryptographic signature that proves a message was authorised by a domain and not altered on the way.
- DMARC ties SPF and DKIM to the From address people actually see, tells receivers what to do when both fail, and sends you reports.
MX is about receiving. The other three are about sending.
MX: where mail goes
$ dig +short MX example.com
10 mx1.mail.example.net.
20 mx2.mail.example.net.
Senders try the lowest preference number first and fall back to higher numbers on failure. Equal numbers share load.
Rules that matter:
- The target must be a hostname with an A or AAAA record. It must not be an IP address and must not be a CNAME.
- If no MX record exists, senders fall back to the domain's own A/AAAA record. That is almost never what you want.
- A domain that should never receive mail can publish a null MX:
0 .(preference zero, target a single dot). Senders then fail at once instead of retrying for days.
SPF: which servers may send
SPF is a single TXT record on the domain:
example.com. TXT "v=spf1 include:_spf.mail.example.net ip4:192.0.2.10 -all"
The receiving server takes the domain from the envelope sender (the Return-Path, not the visible From header), fetches its SPF record and checks whether the connecting IP address matches. The all at the end decides what happens to everyone else: -all means fail, ~all means softfail, ?all means no opinion.
Two limitations are built in:
- SPF checks a domain the recipient never sees. On its own it does nothing to stop someone forging your visible From address.
- SPF breaks on forwarding. When a message is forwarded, the forwarder's IP connects to the final receiver, and that IP is not in your record.
DKIM: a signature that travels with the message
With DKIM the sending server signs selected headers and the body with a private key and adds a DKIM-Signature header. The public key lives in DNS:
s2026._domainkey.example.com. TXT "v=DKIM1; k=rsa; p=MIIBIjANBgkqh..."
s2026 is the selector. It is an arbitrary label chosen by the sending system, and it appears in the signature header as s=s2026 next to the signing domain d=example.com. A domain can have any number of selectors, one per sending service and one per key rotation.
This has a consequence people trip over: you cannot look up "the DKIM record" of a domain. DNS has no way to list the names under _domainkey. You need the selector, and the dependable way to get it is to open the headers of a message the domain really sent.
DKIM survives plain forwarding because the signature travels with the message. It breaks when an intermediary changes signed content, which is what many mailing lists do when they add a footer or a subject tag.
DMARC: alignment, policy and reports
DMARC is a TXT record at _dmarc:
_dmarc.example.com. TXT "v=DMARC1; p=none; rua=mailto:dmarc-reports@example.com"
It adds three things.
Alignment. A message passes DMARC if SPF passes and the envelope domain aligns with the From domain, or DKIM passes and the d= domain aligns with the From domain. One aligned pass is enough. By default alignment is relaxed, so mail.example.com aligns with example.com.
Policy. p=none asks receivers to take no action, p=quarantine asks them to treat failures as suspicious (usually the spam folder), and p=reject asks them to refuse the message. sp= sets a separate policy for subdomains.
Reporting. Receivers send daily aggregate XML reports to the rua address: which IPs sent mail claiming to be you, how many messages, and whether SPF and DKIM passed and aligned. These reports are how you find the senders you had forgotten about.
Alignment is the reason a message can "pass SPF" and still fail DMARC. A newsletter platform that uses its own bounce domain passes SPF for its domain, which does not align with yours. The fix is normally to set up a custom return-path or, better, DKIM signing with your own domain at that platform.
The mistakes we see most
Multiple SPF records
example.com. TXT "v=spf1 include:_spf.mail.example.net ~all"
example.com. TXT "v=spf1 include:spf.crm.example.org ~all"
Two records starting with v=spf1 is a permanent error (permerror). SPF fails for every message. This usually happens when someone follows a new vendor's setup guide literally. Merge them into one record with both includes.
The 10-lookup limit
A receiver may perform at most ten DNS lookups while evaluating SPF. include, a, mx, exists, redirect and ptr each count, and includes nest: one vendor include can cost three or four lookups by itself. ip4, ip6 and all cost nothing. Go over ten and the result is permerror again.
Fixes, in order of preference: remove services you no longer use; move bulk senders to a subdomain with its own SPF record; rely on aligned DKIM for services that support it and drop their include. Be cautious with "SPF flattening" that copies vendor IPs into your record. It goes stale without warning when the vendor changes its ranges.
+all
v=spf1 +all authorises every server on the internet. It is worse than having no record, because it actively asserts that forged mail is legitimate. ?all is not much better.
The ptr mechanism
Slow, unreliable and discouraged by the SPF specification itself. Remove it.
p=none forever
p=none is a monitoring mode. It gives you reports and no protection: anyone can still put your domain in the From line and receivers will deliver it as they would have anyway. Plenty of domains publish p=none to satisfy a bulk-sender checklist and never move. If the reports have been clean for weeks, there is no reason to stay.
Forgetting domains that do not send
Parked domains and domains used only for websites get spoofed precisely because nobody watches them. Lock them down:
example.org. TXT "v=spf1 -all"
_dmarc.example.org. TXT "v=DMARC1; p=reject"
example.org. MX 0 .
Rolling out DMARC safely
- Inventory your senders. Mailbox provider, website and application mail, CRM, newsletter tool, invoicing, helpdesk, monitoring alerts. The ones you forget are the ones that break.
- Fix SPF. One record, under ten lookups, ending in
~allor-all. - Turn on DKIM everywhere. For every service, enable signing with your domain in
d=. This matters most, because DKIM is what keeps DMARC passing through forwarding. - Publish
p=nonewith aruaaddress. Use a mailbox or a report-processing service; raw XML is unpleasant to read by hand. - Read reports for two to four weeks. Look for legitimate sources that fail alignment. Fix each one at the source.
- Move to
p=quarantine. Usepct=to go gradually if your volume is large, for example 10, then 50, then 100. Keep reading reports. - Move to
p=reject. Decide separately whether subdomains need their ownsp=policy. - Keep watching. New tools get adopted without anyone telling whoever owns DNS. Reports are how you find out.
Expect a small residue of failures you cannot fix, mostly from mailing lists and odd forwarders. Many receivers handle those with ARC or local heuristics. It is a reason to move carefully, not a reason to stay at p=none.
What records cannot do
Correct MX, SPF, DKIM and DMARC records mean receivers can verify that mail is authorised by your domain. They do not mean your mail lands in the inbox. Mailbox providers also weigh the reputation of your domain and sending IPs, complaint rates, list quality, content and how recipients interact with your mail. None of that lives in DNS.
Authentication is the entry ticket. Large providers now require it from bulk senders, and without it you are filtered before anything else is considered. With it, you are judged on how you actually send.
A DNS check also cannot prove that mail is flowing. It can show that your published policy is coherent, which is the part you control from the zone.
Check it with OrbitProbe
The OrbitProbe MX lookup reads a domain's MX, SPF and DMARC records and flags the problems described above: multiple SPF records, too many lookups, +all, a missing DMARC record or a policy stuck at p=none. For DKIM, find your selector in a sent message's headers and query selector._domainkey.yourdomain as a TXT record. If you want to know when these records change, a DNS change watch in the workspace keeps a history.