inboxes.
← Blog Fundamentals July 2026 · 12 min read

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 provesThe sending IP is authorized by the domainThe message was signed by the domain and not alteredThe passing check matches the visible From domain
DNS locationTXT at example.comTXT at selector._domainkey.example.comTXT at _dmarc.example.com
What it checksReturn-Path domain vs connecting IPSignature in the message header vs published public keySPF/DKIM results plus From-domain alignment
Survives forwardingNoYes (if body unmodified)Via the DKIM path
StandardRFC 7208 (2014)RFC 6376 (2011)RFC 7489 (2015)
Without it in 2026Fails Gmail/Yahoo minimumsFails bulk-sender rulesBulk 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:

  1. 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.
  2. 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 with pct=25, applying the policy to a quarter of failing mail, then raise it.
  3. 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 besides v=.
  • sp=: policy for subdomains. If omitted, subdomains inherit p=. Spoofers actively probe for domains at p=reject with 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 that pct does not apply to p=none.
  • adkim= / aspf=: alignment strictness, r (relaxed, subdomain matches count) or s (strict, exact match). Relaxed is the right default; strict breaks the common pattern of signing at the root while sending from news.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=spf1 TXT record on the same name, usually left behind by an old provider's setup wizard, is an automatic permerror. RFC 7208 allows exactly one. Merge them into a single record; never publish two.
  • ~all vs -all. Tilde means softfail ("probably not us"), hyphen means fail ("definitely not us"). During rollout ~all is 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; +all should 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.com after 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.com instead of _dmarc.example.com, or DKIM missing the ._domainkey label, 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.