Networking

SPF, DKIM and DMARC: how to protect your domain’s email

Anyone can type your domain into the “From” field of an email, the sending protocol alone proves nothing. SPF, DKIM and DMARC are three DNS records that together answer three different questions: who may send, did the message arrive intact, and is the sender the user sees really who it claims to be. The piece almost every tutorial forgets is the third one. SPF authenticates the envelope address (the MAIL FROM, from RFC 5321); DKIM authenticates the signing domain; but it is DMARC that requires one of those two to align with the “From” shown on screen (the From, from RFC 5322). That is why an email can pass SPF and still be rejected by DMARC, and grasping that misalignment is what separates people who set up real authentication from people who just copy records off the internet. Paste your domain into the [SPF, DKIM and DMARC checker](tool:email-security-checker) as you read: it queries all three records in the browser and flags the mistakes before you tighten the policy.

J-Kit18 min readIntermediate
  • SPF
  • DKIM
  • DMARC
  • Email
  • Authentication

Key takeaways

  • SPF authorizes servers by the envelope address, DKIM signs the content, and DMARC requires one of the two to align with the visible “From” domain.
  • An email can pass SPF and fail DMARC: SPF validates the MAIL FROM (envelope), DMARC validates the From (header). If they do not match, there is no alignment.
  • SPF breaks on forwarding because the relaying server is not on the original sender’s list; SRS and ARC are the attempts to work around it.
  • Roll out in order: publish SPF and DKIM, put DMARC at p=none with rua, read the reports, and only then tighten to quarantine and reject.

Three layers to prove the email is yours

SMTP was born on an internet of mutual trust and never built in authentication: the server delivering a message simply asserts the sender, and the destination, historically, believed it. Today’s three mechanisms were bolted on top of the protocol to fix that without breaking it. They solve distinct problems and do not replace each other, a receiving provider tends to trust a message that passes all three and to reject or spam-folder one that fails.

The three layers, what each one proves and where it lives in DNS.
RecordWhat it provesIdentity it validatesWhere it lives in DNS
SPFThat the sending server is authorizedMAIL FROM (envelope, RFC 5321)TXT on the domain
DKIMThat the message was not tampered withSigning domain (d=)selector._domainkey.domain
DMARCThat SPF or DKIM aligns with the visible “From”From (header, RFC 5322)_dmarc.domain

Look at the middle column: each mechanism authenticates a different identity. That is where the confusion in nine out of ten setups lives. SPF looks at an address the user never sees; DMARC looks at the address they do see. When those two addresses belong to different domains, which happens constantly with sending platforms, SPF can say “pass” while DMARC says “fail”. The rest of this guide is about reconciling those identities.

Envelope / MAIL FROM (RFC 5321)
The address declared in the SMTP conversation, where bounces return (Return-Path). It does not appear in the mail client. It is what SPF checks.
Header From (RFC 5322)
The “From” field the recipient reads on screen. It is what phishing forges and what DMARC protects.
Alignment
The DMARC rule: the domain authenticated by SPF or DKIM must match the From domain. Without a match there is no DMARC pass, even with valid SPF and DKIM.

SPF: who may send for the domain

SPF (Sender Policy Framework, RFC 7208) is a single TXT record that lists, through mechanisms, the servers authorized to use your domain in MAIL FROM. The recipient takes the connecting IP and compares it against that list. If it matches, SPF returns pass; if not, the outcome depends on the qualifier that closes the record.

example.com.   IN TXT   "v=spf1 include:_spf.google.com ip4:198.51.100.25 -all"

  v=spf1                  → versão do registro (obrigatória, sempre primeiro)
  include:_spf.google.com → autoriza os IPs do Google Workspace  (1 consulta de DNS)
  ip4:198.51.100.25       → autoriza este IP literal              (0 consultas)
  -all                    → hardfail: rejeita qualquer outro servidor
A real SPF record, field by field. Order matters: mechanisms are evaluated left to right and the first match wins.
SPF mechanisms. Only those in the last column consume the budget of 10 DNS lookups (RFC 7208, §4.6.4).
MechanismWhat it authorizesCounts toward the 10?
allMatches everything; closes the record with a qualifierNo
ip4 / ip6A literal IP or CIDR rangeNo
aThe IPs of the domain’s A/AAAA recordYes (1)
mxThe IPs of the domain’s MX serversYes (1)
includeImports another domain’s SPF (the provider)Yes (1 + those inside)
existsTests whether a name resolves (uses macros)Yes (1)
ptrReverse DNS, discouraged by RFC 7208Yes (1)
redirect=Modifier: replaces the record with another domain’sYes (1)

Each mechanism can take a qualifier that decides the verdict when it matches. In practice, the only qualifier that matters is the one on the trailing “all”, because it defines what happens to everyone who is not on the list.

SPF qualifiers. The default, when omitted, is “+”.
QualifierResultPractical effect on trailing …all
+Pass (default)+all authorizes ANY server, never use it
-Fail (hardfail)-all rejects anyone not on the list (recommended)
~SoftFail~all accepts but flags as suspicious (transition)
?Neutral?all expresses no opinion, almost no protection

There is a structural trap in SPF that silently knocks out whole domains: the 10-DNS-lookup limit. RFC 7208 (§4.6.4) requires the evaluation to make no more than 10 lookups triggered by include, a, mx, ptr, exists and redirect, counting the nested lookups inside each include. Blowing that ceiling is neither softfail nor neutral: it is permerror, and SPF is treated as if it did not exist. Since every provider you add (Google, a marketing platform, a CRM, an invoicing tool) brings its own include, the budget runs out faster than it looks. It is worth walking the count.

# Exemplo ilustrativo: um SPF com includes aninhados que ESTOURA o limite

example.com:      v=spf1 include:_spf.google.com include:spf.plataforma.net \
                        include:_spf.crm.com -all

_spf.google.com:  v=spf1 include:_netblocks.google.com include:_netblocks2.google.com \
                        include:_netblocks3.google.com ~all
  _netblocks*.google.com:  só ip4/ip6  (0 consultas cada)

spf.plataforma.net: v=spf1 a mx include:relay.plataforma.net ~all
  relay.plataforma.net:    só ip4      (0 consultas)

_spf.crm.com:     v=spf1 include:eu._spf.crm.com include:us._spf.crm.com ~all
  eu/us._spf.crm.com:      só ip4      (0 consultas cada)
Example built for the count: the names are fictional, but the pattern (a provider that includes another include) is exactly the real-world one.
Worked example 1, counting the 10 lookups. ip4, ip6, all and the qualifiers do NOT count.
#Term that triggers the lookupRunning total
1include:_spf.google.com1
2↳ include:_netblocks.google.com2
3↳ include:_netblocks2.google.com3
4↳ include:_netblocks3.google.com4
5include:spf.plataforma.net5
6↳ a6
7↳ mx7
8↳ include:relay.plataforma.net8
9include:_spf.crm.com9
10↳ include:eu._spf.crm.com10
11↳ include:us._spf.crm.com → over the limit11 → PermError

Eleven lookups, one over the cap: the whole record returns permerror and SPF is discarded. Notice how innocent the three providers look, three includes at the top, yet Google alone spends four because of its own internal includes. The way out is to flatten (replace includes with ip4/ip6 ranges when the provider publishes stable IPs), remove sending sources you no longer use, or delegate sending to a dedicated subdomain. The SPF, DKIM and DMARC checker shows the “lookups: n/10” counter and raises a warning from 8 onward. To inspect what each include resolves to, the DNS lookup returns the raw TXT of each name.

DKIM: the signature that proves integrity

DKIM (DomainKeys Identified Mail, RFC 6376, now an Internet Standard, STD 76) solves a problem SPF never touches: integrity. The sending server computes a hash of the body and of a chosen set of headers, and signs that set with a private key. The signature travels inside a DKIM-Signature header; the matching public key is published in DNS. If the subject or the body changes a single byte along the way, the signature stops matching. It is the same family of ideas as the guide on hashing, encryption and encoding: here we use a hash to detect tampering and an asymmetric key to prove authorship.

DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=example.com;
    s=selector1; h=from:to:subject:date;
    bh=2jUSOH9NhtVGCQWNr9BrIAPreKQjO6Sn7XIkfJVOzv8=;
    b=AbCdE...assinatura codificada em base64...==

  a=  → algoritmo (rsa-sha256; ed25519-sha256 também é padrão)
  c=  → canonicalização cabeçalho/corpo (relaxed/relaxed)
  d=  → DOMÍNIO que assina, é ele que o DMARC alinha contra o From
  s=  → SELETOR: aponta para s=selector1 → selector1._domainkey.example.com
  h=  → lista de cabeçalhos cobertos pela assinatura
  bh= → hash do CORPO (body hash)
  b=  → a assinatura sobre os cabeçalhos de h= mais o bh=
The DKIM-Signature header that travels in the message. The pair d= (domain) and s= (selector) tells the recipient which public key to fetch.
selector1._domainkey.example.com.   IN TXT   "v=DKIM1; k=rsa; p=MIIBIjANBgkq…IDAQAB"

  v=DKIM1 → versão do registro
  k=rsa   → tipo de chave (rsa; ed25519 também é possível)
  p=…     → a chave PÚBLICA em base64; p= vazio significa seletor REVOGADO
The TXT record with the public key, at the name built from the selector. The recipient verifies b= with this key.
Selector (s=)
A label you choose that points to a specific key. It lets you keep several active keys and rotate them without downtime: publish a new selector and migrate.
Canonicalization (c=)
How the header and body are normalized before hashing. “simple” is strict (any change breaks it); “relaxed” tolerates the whitespace and line-wrapping differences servers introduce in transit. That is why relaxed/relaxed is the most used.
Body hash (bh=) and signature (b=)
bh= is the hash of the body alone; b= is the cryptographic signature over the headers listed in h= plus the bh= itself. Verifying both separates “the body changed” from “a header changed”.

DKIM’s great virtue is surviving hops that break SPF. Because the proof travels inside the message rather than being tied to the connection IP, a forward that rewrites the envelope does not destroy the signature, as long as nobody alters the body or the signed headers. That is why, in practice, aligned DKIM tends to be the most reliable path to a DMARC pass.

DMARC: alignment, policy and reports

DMARC is the layer that gives the other two meaning. On their own, SPF and DKIM authenticate domains the user never sees. DMARC (originally RFC 7489, now re-standardized by RFC 9989) does three things: it requires SPF or DKIM to align with the visible From domain, it defines a policy for failures, and it asks for reports back. Alignment is the heart, without it, everything falls apart.

It is worth building the example that confuses everyone: an email that passes SPF and still fails DMARC. It is the typical scenario of anyone sending a newsletter through a marketing platform.

Return-Path: <[email protected]>   ← envelope (o SPF olha aqui)
DKIM-Signature: ... d=plataforma-envio.com; s=k1    ← assinatura da plataforma
From: Promoções <[email protected]>                 ← cabeçalho (o usuário vê isto)

SPF   : pass  para  plataforma-envio.com   (o IP está no SPF DA PLATAFORMA)
DKIM  : pass  para  plataforma-envio.com   (a assinatura d= confere)

Alinhamento DMARC, comparado com o From = loja.com.br:
  SPF  alinhado?  plataforma-envio.com  ≟  loja.com.br  →  NÃO
  DKIM alinhado?  plataforma-envio.com  ≟  loja.com.br  →  NÃO
  Resultado DMARC: FAIL  → com p=reject em loja.com.br, a mensagem é RECUSADA
Worked example 2, SPF and DKIM pass, DMARC fails. The two domains side by side: authentication went to plataforma-envio.com, but the From is loja.com.br. No alignment, no DMARC pass.

The fix is not to touch the policy but to reconcile the identities. Two ways out: ask the platform to sign DKIM with d=loja.com.br (a delegated key), which aligns DKIM; or set the Return-Path to a subdomain of yours, like bounce.loja.com.br, which aligns SPF. Only one of the two needs to align for DMARC to pass. It is exactly the rule Google and Yahoo have required of large senders since 2024: SPF and DKIM in place, and at least one of them aligned to the From.

How strict alignment is comes from two tags: aspf (for SPF) and adkim (for DKIM). Each takes “r” (relaxed, the default) or “s” (strict). In relaxed mode, matching the organizational domain is enough, news.loja.com.br aligns with loja.com.br. In strict mode, the domain must be identical, news.loja.com.br does not align with loja.com.br. Always start relaxed.

_dmarc.example.com.   IN TXT   "v=DMARC1; p=quarantine; rua=mailto:[email protected]; \
                                adkim=s; aspf=r; pct=100"

  v=DMARC1  → versão (obrigatória, sempre primeiro)
  p=        → política do domínio: none | quarantine | reject
  rua=      → destino dos relatórios AGREGADOS (diários, em XML)
  ruf=      → destino dos relatórios de FALHA por mensagem (opcional; cuidado com privacidade)
  adkim=s   → alinhamento DKIM estrito (domínio idêntico)
  aspf=r    → alinhamento SPF relaxado (mesmo domínio organizacional)
  pct=100   → aplica a política a 100% das mensagens
A DMARC record field by field. In mature production it sits at p=reject; here it is at quarantine only to illustrate the alignment tags.
The three DMARC policies and what the recipient does with a message that does not align.
Policy (p=)What the recipient doesWhen to use it
noneOnly observes and reports; nothing is blockedStart: gather reports at no risk
quarantineSends non-aligning mail to spamMiddle: once legitimate mail passes
rejectRefuses delivery at the SMTP connectionEnd: maximum protection against spoofing

Aggregate reports (rua) are what make DMARC operable: they arrive by email, in XML, and list which IPs sent on your domain’s behalf, how many messages, and how each one fared on SPF, DKIM and alignment. In the 2026 revision (the so-called DMARCbis), the standard was split into three documents, RFC 9989 (the protocol), RFC 9990 (aggregate reports) and RFC 9991 (failure reports), and, crucially, DMARC stopped being merely Informational and entered the IETF Standards Track as a Proposed Standard. For operators, the day-to-day does not change: publish, read the reports, tighten.

Why SPF breaks on forwarding, and what ARC and SRS do

SPF’s Achilles’ heel is forwarding. You send an email to someone who redirects their mailbox to another provider; the relaying server uses YOUR domain in MAIL FROM, but its IP is not in your SPF, because how would it be? You never authorized a third party’s server. SPF then fails, even though the message is legitimate. Two distinct solutions attack the problem at different points in the chain, and both are worth knowing before you move to p=reject.

  1. 2006SPF, experimental (RFC 4408)

    The first attempt to authorize servers by IP is published as an experimental standard.

  2. 2007DKIM (RFC 4871)

    The cryptographic signature merges DomainKeys (Yahoo) and Identified Internet Mail (Cisco).

  3. 2011DKIM becomes an Internet Standard (RFC 6376, STD 76)

    The consolidated DKIM reaches the top of the IETF maturity ladder.

  4. 2014SPF re-standardized (RFC 7208)

    SPF sheds its experimental status and becomes a Proposed Standard, with the 10-DNS-lookup limit.

  5. 2015DMARC (RFC 7489)

    Binds SPF and DKIM to the visible From, creates alignment and reports, published as Informational.

  6. 2019ARC (RFC 8617)

    Experimental standard that preserves the authentication result across mailing lists and forwarders.

  7. 2024Google and Yahoo require authentication

    From February 1, senders of more than 5,000 messages/day to Gmail need aligned SPF, DKIM and DMARC.

  8. 2026DMARCbis (RFC 9989/9990/9991)

    Three RFCs obsolete 7489 and move DMARC onto the Standards Track as a Proposed Standard.

Why SPF breaks on forwarding, precisely

SPF checks the connection IP against the MAIL FROM domain. In a simple forward (an automatic mailbox “forward”), the intermediate server resends keeping your domain in the envelope, but the connection now comes from its IP. Since that IP was never in your list, SPF fails. The message is the same, the content legitimate, only the path changed. This is why nobody should rely on SPF alone for the verdict, and why DMARC accepts alignment via SPF OR via DKIM.

SRS, rewriting the envelope so SPF passes again

SRS (Sender Rewriting Scheme) acts at the forwarder: instead of keeping your domain in MAIL FROM, it rewrites the envelope to an address in its own domain, reversibly stashing the original so bounces return to the right place. SPF then checks the domain of whoever actually resends, and passes again. SRS has no formal RFC, it is a 2004 technical specification (Shevek, from Meng Weng Wong’s idea) adopted de facto by servers and providers as a convention. It fixes SPF, but not alignment with the From: so, on its own, it does not save DMARC.

ARC, carrying the authentication verdict across hops

ARC (Authenticated Received Chain, RFC 8617, experimental) tackles it from the other end. Each trusted intermediary, a mailing list, say, that rewrites the subject and breaks DKIM, records, signed, the authentication result IT saw before touching the message. The final destination, if it trusts that chain, can accept an email that would fail “raw” DMARC, because the ARC chain proves it was legitimate before the path’s edits. It is a bridge of trust between servers, not a replacement for SPF or DKIM.

What DMARC does NOT solve: look-alike (cousin) domains

DMARC protects your exact domain. It does nothing against an attacker who registers loja-pagamentos.com or l0ja.com.br and sends perfectly authenticated email from there, after all, it is THEIR domain, with their own SPF and DKIM. To the human eye it looks like you; to DMARC it is a different domain, and it passes. Defenses against this live outside the trio: monitoring for look-alike registrations, reputation- and content-based anti-phishing filters, and programs like BIMI, which shows your verified logo next to messages (requiring DMARC at quarantine with pct=100 or reject) to give the user a visual authenticity cue. A WHOIS of the suspicious domain helps you see when it was registered and by whom.

How to roll it out without blocking legitimate mail

  1. Inventory and publish SPF and DKIMList EVERY sending source (Google/Microsoft, marketing, CRM, invoicing, forms) and cover each in SPF without blowing the 10 lookups; ask each provider for DKIM with d= aligned to your domain.
  2. Put DMARC at p=none with ruaPublish _dmarc with p=none and rua pointing to a mailbox of yours. Nothing is blocked; you are only turning on the report stream.
  3. Read the reports for weeksIn the aggregate XML, look for legitimate sources failing alignment and fix each one (delegated DKIM or a Return-Path on a subdomain of yours).
  4. Tighten to p=quarantineOnce legitimate mail passes, move to quarantine (optionally with a lower pct at first) and watch whether anything lands in spam unfairly.
  5. Close at p=rejectWith everything stable, go to reject: from then on, any message that does not align with your From is refused at the door.
Run your domain (and your provider’s DKIM selector) here: the checker shows all three records, the SPF lookup counter and the DMARC policy, all in the browser.Open the tool full page

It helps to know that authenticating the sender is one piece of a larger ecosystem. MTA-STS (RFC 8461) and TLS-RPT (RFC 8460) are about forcing and reporting TLS on server-to-server delivery; BIMI handles the verified logo. None of these replace the trio, they all assume DMARC is working. To read the authentication verdict of a message that already arrived (the Authentication-Results header, with that email’s SPF, DKIM and DMARC results), use the email header analyzer; it rebuilds the route and shows where authentication passed or failed.

  • A single SPF record, ending in -all (or ~all during transition), within the 10 DNS lookups.
  • DKIM active with a key of at least 2048 bits and d= aligned to the From domain.
  • DMARC published at _dmarc, with rua to a mailbox someone actually reads.
  • At least one identity, SPF OR DKIM, aligned with the From on every sending source.
  • Progression none → quarantine → reject only after the reports confirm legitimate mail passes.

Frequently asked questions

Why does my email pass SPF but fail DMARC?
Because SPF authenticates the envelope domain (the MAIL FROM), while DMARC requires that domain, or the DKIM signing domain, to align with the From domain the user sees. When you send through a platform, the envelope is usually the platform’s domain, so SPF passes for the platform’s domain but does not align with your From. The fix is DKIM signed with your domain (aligned d=) or a Return-Path on a subdomain of yours.
Do I need all three or is SPF enough?
The three complement each other. SPF alone breaks on forwarding and does not protect the visible From; DKIM proves integrity but sets no policy; it is DMARC, backed by aligned SPF and DKIM, that closes the loop against spoofing and also gives you reports. Google and Yahoo, in fact, require all three of large senders since 2024.
What is the SPF 10-DNS-lookup limit?
RFC 7208 (§4.6.4) allows at most 10 DNS lookups triggered by include, a, mx, ptr, exists and redirect, counting the nested lookups inside each include. Going over produces permerror and SPF is ignored, even with the right server. ip4, ip6 and all do not count. Flattening includes into IP ranges or removing unused sources fixes it.
Why start with p=none?
To monitor without blocking. At p=none nothing is refused, but the aggregate reports (rua) reveal legitimate senders you forgot to cover. Only after aligning all of them is it safe to move to quarantine and then reject. Skipping this step usually drops invoices, HR notices and other automated mail.
DKIM or SPF: which survives forwarding?
DKIM. Because the signature travels inside the message, a forward that merely rewrites the envelope does not destroy it, as long as the body and signed headers stay the same. SPF, which depends on the connection IP, fails when a third party relays using your domain. That is why DMARC accepts alignment via SPF or via DKIM, one is enough.
Does DMARC protect against domains that look like mine?
No. DMARC protects your exact domain. Against an attacker who registers a look-alike (cousin) domain and authenticates correctly from it, the trio does nothing, it is their domain. The defense comes from monitoring look-alike registrations, reputation- and content-based anti-phishing filters, and visual cues like BIMI, which requires DMARC at quarantine (pct=100) or reject.
Has DMARC become an official standard?
Yes. The 2015 RFC 7489 was merely Informational. In 2026, the work known as DMARCbis was published as RFC 9989 (protocol), 9990 (aggregate reports) and 9991 (failure reports), obsoleting 7489 and moving DMARC onto the IETF Standards Track as a Proposed Standard. Operationally, publishing and tightening stays the same.

SPF authorizes servers by the envelope, DKIM signs the content, and DMARC ties both to the visible From by requiring alignment, that is why an email can pass SPF and still fail DMARC. Stay within SPF’s 10 lookups, make sure at least one identity aligns per sending source, understand forwarding (which SRS and ARC try to fix), and roll out in order: p=none with rua, read the reports, and only then quarantine and reject.

Sources & references

  1. RFC 7208, Sender Policy Framework (SPF)
  2. RFC 6376, DomainKeys Identified Mail (DKIM), STD 76
  3. RFC 7489, DMARC (original, Informational, now obsoleted)
  4. RFC 9989, DMARC (DMARCbis, obsoletes RFC 7489)
  5. RFC 8617, Authenticated Received Chain (ARC)
  6. RFC 8461, SMTP MTA Strict Transport Security (MTA-STS)
  7. Google, Email sender guidelines