SPF, DKIM, DMARC: What Each Record Does and How to Set All Three Up
SPF, DKIM, and DMARC are three DNS records that together prove your email is really from you: SPF lists the servers allowed to send for your domain, DKIM adds a cryptographic signature to each message, and DMARC ties both checks to the visible From address and tells receivers what to do with failures. You need all three in 2026: Gmail and Yahoo have required them from bulk senders since February 2024, and Gmail now rejects unauthenticated bulk mail outright.
This guide puts the three records side by side with copy-adaptable examples for a fictional example.com, then covers the details that actually break in production: the 10-lookup SPF limit, DKIM key length, the DMARC policy progression, and the silent misconfigurations that leave senders "authenticated" on paper and failing in practice. For the conceptual view of why these exist and how alignment works, read email authentication explained first; this piece is the record-level manual.
SPF vs DKIM vs DMARC side by side
| SPF | DKIM | DMARC | |
|---|---|---|---|
| What it proves | The sending IP is authorized by the domain | The message was signed by the domain and not altered | The passing check matches the visible From domain |
| DNS location | TXT at example.com | TXT at selector._domainkey.example.com | TXT at _dmarc.example.com |
| What it checks | Return-Path domain vs connecting IP | Signature in the message header vs published public key | SPF/DKIM results plus From-domain alignment |
| Survives forwarding | No | Yes (if body unmodified) | Via the DKIM path |
| Standard | RFC 7208 (2014) | RFC 6376 (2011) | RFC 7489 (2015) |
| Without it in 2026 | Fails Gmail/Yahoo minimums | Fails bulk-sender rules | Bulk mail rejected; domain spoofable |
The SPF record: syntax and the 10-lookup limit
SPF is a single TXT record on the root of your sending domain. A realistic record for a company sending through Google Workspace, an ESP, and a billing tool:
example.com. IN TXT "v=spf1 include:_spf.google.com include:sendgrid.net include:mail.zendesk.com -all"
Reading it left to right: version tag, then mechanisms evaluated in order, then the catch-all. include: pulls in another domain's SPF record (your provider maintains it), ip4:/ip6: list addresses directly, and the final -all means "everything not listed fails".
The 10 DNS lookup limit
RFC 7208 caps SPF evaluation at 10 DNS lookups. Every include:, a, mx, ptr, exists, and redirect costs one, and includes count recursively: include:_spf.google.com alone consumes 3-4 lookups internally. Cross the limit and receivers return permerror, which most treat as no SPF at all. This is the most common silent SPF failure at growing companies: each new SaaS tool adds an include, nothing visibly breaks, and lookup number 11 quietly voids the record. Count your lookups with an SPF checker whenever you add a sending service; if you are near the cap, remove unused includes or list stable provider IPs directly with ip4:.
The DKIM record: selectors and key length
DKIM needs two pieces: your mail server signs outgoing messages with a private key, and the matching public key lives in DNS under a selector name. If your ESP assigns selector s1, the record looks like:
s1._domainkey.example.com. IN TXT "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC...IDAQAB"
The p= value is the base64 public key (truncated here). Selectors let you run several keys at once, one per sending service, and rotate keys without downtime: publish the new key at a new selector, switch signing, then retire the old record.
1024-bit vs 2048-bit keys
Use 2048-bit RSA keys wherever your provider offers them. 1024-bit is the floor receivers still accept (Gmail rejects anything shorter), but 1024-bit RSA has been considered weak for years and NIST guidance has long pointed past it. The practical trade-off: a 2048-bit public key is too long for some DNS interfaces' single-string limit, so it must be split into two quoted strings inside one TXT record, which resolvers concatenate:
s1._domainkey.example.com. IN TXT ( "v=DKIM1; k=rsa; p=MIIBIjANBgkq...first-part"
"second-part...IDAQAB" )
Most managed ESPs handle this via a CNAME to a record they host, which is fine, and you can confirm the published key resolves and parses with a DKIM checker.
The DMARC record: p=none to quarantine to reject
DMARC lives at the _dmarc subdomain. A sensible starting record:
_dmarc.example.com. IN TXT "v=DMARC1; p=none; rua=mailto:[email protected]; adkim=r; aspf=r"
And a mature one, reached over a couple of months:
_dmarc.example.com. IN TXT "v=DMARC1; p=reject; rua=mailto:[email protected]; pct=100"
The policy progression is the whole art of DMARC deployment:
p=none(weeks 1-4): observe. Nothing changes for delivery; you collect aggregate RUA reports showing every source sending as your domain and whether it aligns. Almost everyone discovers a forgotten sender here: the CRM, the survey tool, an office scanner.p=quarantine(weeks 4-8): failures go to spam. Move here once reports show 98%+ of your legitimate mail passing aligned. You can phase in withpct=25, applying the policy to a quarter of failing mail, then raise it.p=reject(from week 8 or so): failures are refused. The destination state. Spoofed mail bounces instead of reaching anyone, and receivers read a reject policy as a mark of a well-run domain.
The RUA reports are XML files, unreadable by hand at any volume; parsed DMARC monitoring turns them into per-source pass rates so you can see exactly when it is safe to tighten. Moving to reject without reading reports first is how companies discover their invoicing system the hard way.
The DMARC tags that matter
DMARC records support a dozen tags; in practice you will use six:
p=: policy for the domain itself (none,quarantine,reject). The only required tag besidesv=.sp=: policy for subdomains. If omitted, subdomains inheritp=. Spoofers actively probe for domains atp=rejectwith unprotected subdomains, so once you tighten, tighten both.rua=: where aggregate reports go. Set it from day one; the reports are the entire point of the observation phase.pct=: percentage of failing mail the policy applies to, useful for phasing quarantine in gradually. Note thatpctdoes not apply top=none.adkim=/aspf=: alignment strictness,r(relaxed, subdomain matches count) ors(strict, exact match). Relaxed is the right default; strict breaks the common pattern of signing at the root while sending fromnews.example.com.
Common silent breakers
These are the misconfigurations we see most, all invisible until you look at headers or reports:
- Two SPF records. A second
v=spf1TXT record on the same name, usually left behind by an old provider's setup wizard, is an automaticpermerror. RFC 7208 allows exactly one. Merge them into a single record; never publish two. ~allvs-all. Tilde means softfail ("probably not us"), hyphen means fail ("definitely not us"). During rollout~allis the safer choice, and under DMARC the difference matters less because DMARC treats softfail as a failure for alignment purposes. But an SPF record ending?all(neutral) or, worse,+all(everyone may send as us) silently authorizes the entire internet;+allshould never appear in a production record.- CNAME flattening surprises. Some DNS hosts flatten or restrict CNAMEs at the apex, and some providers' DKIM CNAMEs get "helpfully" converted to static TXT copies. The copy then goes stale the moment the provider rotates keys, and signing fails with no DNS error anywhere. If your DKIM is delegated by CNAME, verify the chain resolves live rather than trusting the zone file.
- Stale includes after leaving a provider. Keeping
include:oldprovider.comafter cancellation wastes lookups and, worse, still authorizes that provider's shared IPs to send as you. - DMARC with no aligned pass. SPF passes on the ESP's Return-Path and DKIM signs with the ESP's shared domain: both green, DMARC fails, because neither aligns with your From. The fix is enabling custom-domain DKIM at your ESP.
- Publishing on the wrong name. DMARC at
example.cominstead of_dmarc.example.com, or DKIM missing the._domainkeylabel, both simply do not exist as far as receivers are concerned.
Setup order and verification
Deploy in this order: SPF, then DKIM, then DMARC at p=none, then tighten to reject over 6-10 weeks as reports come clean. The order matters: DMARC evaluates the other two, so publishing it first just generates a month of failure reports, and jumping straight to p=reject before SPF and DKIM are verified is the one sequence that can take down your own legitimate mail. After each change, verify against reality, not just the zone file: send a real message through each sending service to a Gmail address, open Show original, and read the Authentication-Results header. You want spf=pass, dkim=pass with header.d=example.com, and dmarc=pass. A single-pass email health check covers the same ground across all three records plus blacklists in one run.
A boundary worth stating in a guide full of exact syntax: correct records make your mail verifiable, not welcome. Authentication is required table stakes; placement afterward still depends on reputation, complaint rates, and whether recipients want the mail. No DNS configuration guarantees the inbox, and seed-based placement testing, ours included, gives directional estimates rather than promises. Distrust absolute guarantees in this field generally.
Once all three records are live, prove the chain end to end: a placement test with Inboxes sends through your real setup, evaluates SPF, DKIM, DMARC, and alignment exactly as receivers do, and shows placement across Gmail, Outlook, Yahoo, iCloud, GMX, and Zoho with a fix list ranked by impact.