How to Set Up SPF, DKIM & DMARC (2026)
SPF, DKIM and DMARC are three DNS records that let receiving servers verify mail genuinely came from your domain. SPF lists which servers may send, DKIM signs each message, and DMARC ties both to your visible From address, sets a failure policy, and sends you reports.
Key takeaways
- Since February 2024, Gmail and Yahoo require bulk senders to publish SPF, DKIM and a DMARC record — so all three are now effectively mandatory.
- DMARC acts on alignment, not just a pass — a message can pass SPF or DKIM and still fail DMARC if neither result aligns with the From domain.
- DMARCbis (RFC 9989, May 2026) removed the pct, rf and ri tags; use t=y for staged testing. Existing records stay valid.
- Roll out in stages — p=none to collect reports, then quarantine, then reject; under RFC 9989, quarantine is the appropriate end state for domains whose users post to mailing lists.
| Standard | What it proves | Published as | Role in DMARC |
|---|---|---|---|
| SPF | Which servers may send for your domain | TXT at the domain root | Can yield an aligned pass |
| DKIM | A cryptographic signature on each message | TXT at selector._domainkey | Aligned pass that survives forwarding |
| DMARC | What to do when neither aligns + where to send reports | TXT at _dmarc | Ties SPF/DKIM to the visible From and sets policy |
Do you need all three, and how do they fit together?
Email was designed with no way to prove who sent a message. SPF, DKIM, and DMARC are the three DNS records that bolt that proof on after the fact — and as of 2026 they are no longer optional for anyone sending at volume. SPF declares which servers may send mail for your domain. DKIM attaches a cryptographic signature to each message so a receiver can verify it was not altered and came from an authorized key. DMARC is the policy layer: it ties the SPF and DKIM results to the address your recipient actually sees — the From header — and tells receiving servers what to do when that linkage fails, plus where to send you reports.
The table above summarizes the division of labor. The single most important idea — the one that trips up nearly every team — is that DMARC does not care whether SPF or DKIM merely "passed." It cares about alignment: the authenticated domain has to match your From domain. We will come back to that in detail, because it is where most real-world failures live.
One 2026 note that shapes everything below: DMARC was re-standardized in May 2026. RFC 9989 ("DMARCbis") obsoletes both the original RFC 7489 and the PSD extension RFC 9091, and promotes DMARC to the IETF Standards Track for the first time. The record you publish is backward-compatible — v=DMARC1 is unchanged — but a few tags changed, and we use the current RFC 9989 behavior throughout. Where Google's and Microsoft's help pages still describe the older RFC 7489 model, we flag it.
See where you stand first: before you change anything, run a free, no-sign-in SPF, DMARC and MX check on your domain to capture your current state.
How do you build an SPF record without breaking it?
SPF is a single DNS TXT record at your domain root that begins with v=spf1 and lists the hosts allowed to send your mail, ending with an all mechanism that says what to do with everyone else. A minimal record looks like v=spf1 include:_spf.google.com ~all.
Three rules cause most SPF breakage:
One record only. Publishing two v=spf1 records on the same name is not additive — it is a hard error. Per RFC 7208 §4.5, if the lookup returns more than one SPF record, the result is permerror and SPF effectively stops working. When you onboard a new sender, merge its include: into your existing record; never add a second one.
The ten-lookup limit. This is the classic professional foot-gun. RFC 7208 §4.6.4 requires implementations to limit SPF evaluation to 10 DNS-querying terms and to return permerror if that is exceeded. The terms that count are include, a, mx, ptr, exists, and the redirect modifier; ip4, ip6, and all cost nothing. The count is recursive — an include: that points at a record containing three more includes adds four lookups, not one. mx deserves special care: it counts as a single term toward the ten, but evaluating it then triggers an address lookup for every MX host it returns — bounded by a separate sub-limit of ten — so a domain with many MX hosts loads DNS far more heavily than the one term suggests. Stack Google, Microsoft 365, a marketing platform, a CRM, and a helpdesk and you can blow the limit silently; SPF then PermErrors and DMARC degrades with it. The same section also sets a SHOULD limit of two void lookups (queries that return no records), so stale include: entries for decommissioned vendors are worth pruning.
Qualifiers, and the ~all vs -all question. The prefix on a mechanism sets its result (RFC 7208 §4.6.2): + pass, - fail, ~ softfail, ? neutral.
Qualifier on all |
SPF result | Typical receiver behavior | When to use it |
|---|---|---|---|
-all |
Fail (hardfail) | May reject unlisted senders | Final state once all senders are known; non-sending domains |
~all |
SoftFail | Accept but mark/junk | While you are still discovering legitimate senders |
?all |
Neutral | No assertion | Testing only |
+all |
Pass | Authorizes the entire internet | Never — this disables SPF |
There is a real vendor disagreement here: Microsoft recommends -all so DMARC has a clean signal to act on, while Google recommends ~all. The defensible professional path is to run ~all while you confirm every sender in your DMARC reports, then tighten to -all as your enforced end state.
When you genuinely cannot fit your senders under ten lookups, flattening — replacing include: with the literal ip4:/ip6: ranges it resolves to — is a last resort, not a default. Microsoft is explicit that you should not flatten providers with dynamic IPs (its own spf.protection.outlook.com among them), because the moment the provider rotates IPs your flattened record silently drops legitimate mail. If you flatten, document it and re-check quarterly.
Hitting the limit? A free check shows your records; signing in runs the deep scan, which resolves your includes recursively and reports your live SPF lookup count so you can see exactly which sender pushed you over ten.
How do you set up DKIM — keys, selectors, and rotation?
DKIM publishes a public key in DNS and signs outbound mail with the matching private key. The public key lives at <selector>._domainkey.<domain>; per RFC 6376 §3.6.2.1, all DKIM keys are stored under the _domainkey subdomain, and the message's s= (selector) and d= (domain) tags tell the verifier exactly which record to fetch. The selector (RFC 6376 §3.1) exists precisely so a domain can publish several keys at once — which is what makes zero-downtime rotation possible. Providers pick their own: Google uses the selector google; Microsoft 365 publishes selector1 and selector2 as CNAMEs so it can rotate keys on its side.
On key strength: RFC 6376 §3.3.3 set the original floor at "at least 1024 bits," and RFC 8301 — the cryptographic-update RFC that amends RFC 6376 — raised it: signers MUST use at least 1024-bit RSA keys and SHOULD use at least 2048-bit. So the 2048-bit default is an RFC-level recommendation, reinforced by NIST and industry practice — treat 1024-bit as legacy. A practical wrinkle: a 2048-bit RSA public key is longer than a single 255-character DNS string, so some providers require it split into adjacent quoted strings. Ed25519 keys (RFC 8463 §3) sidestep that entirely — at 256 bits the base64 key is only 44 octets and fits in a single TXT string — though RSA remains the most broadly verified.
| RSA-2048 | Ed25519 (RFC 8463) | |
|---|---|---|
| Key strength | Industry/NIST default | Comparable security, modern |
| DNS record | Often must be split past 255 chars | Fits one 255-char string |
| Verifier support | Universal | Growing; verify your receivers |
Rotation without downtime follows one ordering: publish the new key under a new selector while the old one is still live, switch signing to the new selector, wait long enough for in-flight mail signed with the old key to be delivered and verified, then revoke the old key by emptying its p= value — an empty p= means the key is revoked (RFC 6376 §3.6.1). Industry guidance (M3AAWG) recommends rotating periodically rather than never; the exact cadence is a policy choice, but doing it on a schedule keeps the runbook fresh for the day you need an emergency rotation. Finally, sign with relaxed/relaxed canonicalization (RFC 6376 §3.4) so that benign whitespace normalization by intermediate servers does not invalidate your signature. Most DKIM "failed after I changed something" tickets are a selector mismatch (the s= in the header has no matching DNS record yet) or the old selector retired too early.
When you are choosing or moving an email platform, your provider determines your DKIM and SPF setup — Google Workspace, Microsoft 365, and the larger ESPs each publish their own selectors and includes.
Why does DMARC fail when SPF and DKIM pass?
This is the question that separates a working deployment from a broken one. DMARC does not act on a raw SPF or DKIM "pass" — it acts on identifier alignment: the domain that SPF or DKIM authenticated must match the domain in the visible From header. DMARC passes if either SPF or DKIM produces an aligned pass; it fails only when neither does.
Alignment comes in two modes, both defaulting to relaxed:
| Mode | aspf / adkim value |
What must match |
|---|---|---|
| Relaxed (default) | r |
The organizational domain (subdomains allowed) |
| Strict | s |
The exact domain, label for label |
The everyday trap: you send through a marketing platform, the message passes SPF — but SPF authenticated the platform's own bounce domain, not yours, so it is not aligned with your From, and DMARC fails despite the green SPF check. The fix is to get an aligned identifier: have the platform sign with DKIM using your domain (d=yourdomain.com), or set a custom Return-Path on your subdomain. DKIM alignment is also the more forwarding-robust of the two, because a DKIM signature travels inside the message and survives a forward, whereas SPF breaks the moment a forwarder becomes the new sending server (more on that below).
How do you write the DMARC record and roll out safely?
DMARC is a TXT record at _dmarc.<domain>. A monitoring record is as simple as v=DMARC1; p=none; rua=mailto:dmarc@yourdomain.com. The tags you will actually use are defined in RFC 9989 §4.7: p (policy), sp (subdomain policy), np (non-existent-subdomain policy), adkim/aspf (alignment), rua (aggregate reports), ruf (failure reports), and t (test mode).
The DMARCbis changes to bake in now. RFC 9989 removed the pct, rf, and ri tags — pct's removal is called out in RFC 9989 Appendix A.6, and none of the three are registered in the §4.7 tag list. Records that still carry them remain valid and receivers continue to honor them through the deprecation tail, so you do not need to rush-edit existing records — but for staged rollout, use t=y (test mode) instead of pct. RFC 9989 also replaces the old Public Suffix List with a DNS Tree Walk for finding your organizational domain (RFC 9989 §4.10), capped so that domains with more than eight labels never trigger more than eight queries. Note that Google's and Microsoft's current help pages still teach the RFC 7489 model, pct included; their record examples and rollout advice are still operationally fine, only the spec framing is dated.
The policy itself moves in stages:
| Policy | What receivers do | Use it when |
|---|---|---|
p=none |
Take no DMARC action; just report | You are gathering data on who sends as you |
p=quarantine |
Treat failing mail as suspicious (Junk) | Most legitimate senders align; you are de-risking |
p=reject |
Reject failing mail at SMTP time | Every legitimate sender aligns and no users post to mailing lists |
The disciplined path is none → quarantine → reject. Start at none, read your aggregate reports until every legitimate source produces an aligned pass, move to quarantine, confirm nothing legitimate is being quarantined, then go to reject. The exit criterion is data, not a calendar: do not advance until your reports show your real senders aligned. p=none gives you visibility but zero anti-spoofing protection, so it is a stage, not a destination — and the standard agrees. RFC 9989 §8, "Conformance Requirements for Full DMARC Participation," makes the domain-owner obligations normative: a fully participating Domain Owner MUST publish a DMARC policy record, MUST send mail that yields an aligned SPF or DKIM identifier, and MUST set up a mailbox to receive and analyze aggregate reports.
One 2026 nuance on where that path ends. RFC 9989 deliberately softened the old assumption that every domain should march to p=reject. The reason is the indirect-mail-flow problem the working group never fully solved: when your users post to a mailing list, the list resends their message with your From header intact, which breaks SPF — the list is now the sending server — and often breaks DKIM too, because the list rewrites the subject or appends a footer. Under p=reject, that legitimate list mail is rejected and subscribers can be silently dropped. So the current guidance splits by how your domain is actually used: reject remains the right end state for domains that never have humans sending from them — transactional streams like bank notifications, receipts, and dedicated marketing subdomains — while a domain whose users participate in mailing lists may be better served by quarantine as its enforced end state. The staged rollout is unchanged; what changed is that the destination is quarantine or reject depending on your domain, not reject for everyone.
The change from old to new, at a glance:
| Topic | RFC 7489 (legacy) | RFC 9989 (current) |
|---|---|---|
| Gradual rollout | pct= percentage |
pct removed → use t=y test mode |
| Removed tags | — | pct, rf, ri removed (still honored for now) |
| Org-domain discovery | Public Suffix List | DNS Tree Walk (≤ 8 lookups) |
| Non-existent subdomains | covered by sp |
dedicated np= tag |
| Status | Informational | Standards Track; obsoletes 7489 + 9091 |
How do you protect subdomains and parked domains?
By default a subdomain inherits your organizational p. You can override that for existing subdomains with sp=, and — new in RFC 9989 — you can set a separate policy for non-existent subdomains with np=, which shuts down a favorite spoofing trick of inventing lookalike subdomains. Precedence runs np → sp → p.
Do not forget the domains that send no mail at all — parked domains and bare brand domains are prime spoofing targets. Lock each one down with an empty SPF (v=spf1 -all), a DMARC record at p=reject, an empty DKIM key, and a null MX. A domain that should never send email should advertise exactly that.
How do you read DMARC reports and act on them?
Two report types, and you should treat them very differently. Aggregate (rua) reports are periodic XML summaries — per-source-IP counts, the SPF and DKIM results, the alignment outcome, and the disposition the receiver applied (RFC 9990 §3.1). They contain no message content, so the privacy risk is low; this is the workhorse, and you should always enable it. Failure (ruf) reports are per-message and include message headers and possibly body (RFC 9991 §2); because they can expose PII and non-public information (RFC 9991 §7), most large receivers do not send them at all. Plan around rua; treat ruf as a bonus.
Aggregate (rua) |
Failure (ruf) |
|
|---|---|---|
| Cadence | Periodic (usually daily) | Per failure, near real time |
| Contains | Counts + auth/alignment results | Message headers, possibly body |
| Privacy | Low (no content) | High (PII/NPI) |
| Reality | Always enable | Rarely sent by major receivers |
One mandatory detail people miss: if you send reports to an address at a different domain, that domain must publish an authorization record or the receiver will not deliver the reports. RFC 9990 §4 makes this verification mandatory — the receiving side publishes a TXT record at <your-domain>._report._dmarc.<reporter-domain> containing v=DMARC1. Skip it and your reports silently never arrive. Because raw aggregate XML is impractical to read by hand at any scale, send it to a dedicated mailbox or a parser, never a personal inbox.
DMARC reject broke our forwarded mail — how do you fix it?
Enforcement and forwarding collide in two predictable ways. A plain forwarder becomes the new sending server, which breaks SPF alignment; a mailing list rewrites the subject or body, which breaks the DKIM signature. With p=quarantine or p=reject, that legitimate-but-modified mail then gets caught. The fixes belong at the intermediary, not on your originating domain: forwarders should implement SRS to keep SPF intact, and intermediaries should add ARC (RFC 8617), which preserves the original authentication results so a downstream receiver can see the message passed before it was modified. Gmail and Microsoft both evaluate ARC. You cannot solve this from the sender side alone — which is one more reason to lean on DKIM alignment, the identifier most likely to survive the trip.
How do you verify and troubleshoot your records?
Everything here is visible from the command line. Check each record with dig (or nslookup):
- SPF:
dig TXT yourdomain.com— look for thev=spf1string. - DKIM:
dig TXT selector._domainkey.yourdomain.com— substitute your real selector. - DMARC:
dig TXT _dmarc.yourdomain.com.
The errors you will meet: PermError usually means too many DNS lookups or more than one SPF record (RFC 7208 §4.6.4 and §4.5); TempError is a transient DNS failure, so re-test rather than re-architect; a DKIM result of none means no signature or no published key at that selector, while fail means the signature did not verify (often a forwarder or a too-early key retirement). Remember DNS TTLs — lower yours before a change so you are not waiting on stale caches.
Skip the dig commands: check SPF, DMARC and MX on any domain instantly and free — no sign-in required.
What can a DNS checker actually verify — and what can't it?
This is worth stating plainly, because it is where a lot of tools quietly overpromise. A DNS-level check confirms that your records exist and parse correctly. It cannot, by itself, confirm that the mail you actually send will align — that requires reading your aggregate (rua) reports over time. Be skeptical of any checker that implies a green DNS result means your live mail is DMARC-aligned.
Here is exactly what NameProf's checker does and does not claim, split by tier:
| Free quick check (no sign-in) | Deep scan (sign in) | |
|---|---|---|
| SPF presence + qualifier | ✓ | ✓ |
| DMARC policy | ✓ | ✓ |
| MX / provider | ✓ | ✓ |
| Recursive SPF lookup count | — | ✓ |
| DKIM selector probe | — | ✓ |
| MTA-STS / DANE / TLS-RPT / BIMI | — | ✓ |
Two honest caveats we hold to. DKIM has no directory, so the deep scan probes a fixed list of common selectors; when it finds nothing it reports "no DKIM found on the probed selectors" — never "DKIM is not configured," because a custom or token-based selector simply may not be on the list. And our transport-security results are read from your published DNS records — a declared posture, not a live TLS handshake. A checker is a fast way to find missing or malformed records; your reports are how you confirm real-world alignment.
What do Gmail, Yahoo, and Microsoft require now?
Compliance, not theory, is what makes this urgent. Since February 2024, Google requires bulk senders (roughly 5,000+ messages/day to Gmail) to authenticate with both SPF and DKIM, publish a DMARC record at minimum p=none, pass DMARC alignment, offer one-click unsubscribe (RFC 8058), and keep spam complaints below 0.3%. Yahoo's sender requirements match. Microsoft followed: per its Outlook high-volume sender requirements, from May 5, 2025 non-compliant high-volume mail to Outlook.com/Hotmail/Live is rejected with 550 5.7.515. The through-line is consistent: SPF, DKIM, and an aligned DMARC record are now table stakes for reaching the inbox at scale.
Adoption still lags the mandate, which is the opportunity. Valimail's 2026 report found only about 42% of domains with DMARC reach an enforcement policy, and EasyDMARC's 2026 adoption report found roughly 56% of DMARC-enabled domains are still stuck at p=none. (These are separate vendor studies with different datasets — treat each on its own terms rather than combining them.)
Finally, where the adjacent standards fit: SPF, DKIM, and DMARC authenticate the message; a second family secures the transport. MTA-STS (RFC 8461) and DANE (RFC 7672, which needs DNSSEC) force authenticated TLS to your mail servers, and TLS-RPT (RFC 8460) reports when that fails. BIMI — still an IETF draft, not an RFC — is the visible reward: reach DMARC enforcement and you can display a verified logo, with a Verified Mark Certificate. Get SPF, DKIM, and DMARC right first; these build on top.
NameProf tool
Run the Email Authentication checker
SPF, DKIM, and DMARC explained — set them up, read the records, and fix failures.
Open the toolFrequently asked questions
- Do I really need all three?
- Yes. They do distinct jobs — SPF authorizes servers, DKIM signs messages, DMARC ties both to your visible From and tells receivers what to do on failure. Gmail, Yahoo and Microsoft now require all three from bulk senders.
- Should I use ~all or -all on my SPF record?
- It is a genuine vendor split — Microsoft recommends -all, Google recommends ~all. Use ~all while you are still discovering every legitimate sender, then move to -all once DMARC reports confirm all sources are covered.
- How long should I stay at p=none?
- Until every legitimate sender produces an aligned SPF or DKIM pass in your reports — often a few weeks to a few months for complex senders. p=none gives visibility but no spoofing protection, so treat it as a stage, not a destination.
- Does NameProf's free check include DKIM?
- No. The free, no-sign-in check covers SPF, DMARC and MX. DKIM selector probing, the recursive SPF lookup count, and MTA-STS/DANE are part of the deep scan, which requires signing in.
- Why does my mail pass SPF but still fail DMARC?
- Alignment. DMARC requires that the SPF- or DKIM-authenticated domain matches your visible From domain. A third-party sender often authenticates its own domain, which passes SPF in isolation but is not aligned with your From.
- Is the pct tag still valid?
- DMARCbis (RFC 9989) removed pct, rf and ri. Existing records that still contain them remain syntactically valid and receivers honor them through the deprecation tail, but new deployments should use t=y for staged testing instead.