A payment-change request arrives in your finance team’s inbox. It comes from a supplier they have worked with for three years, at the exact address they always use. The formatting is right, the signature block is right, and the reference number matches a real open invoice. Nothing gets flagged, because nothing about it is technically wrong.
SMTP, the protocol that carried that message, was specified with no mechanism to verify who sent it, and it still has none. It is worse than that: every message carries two separate sender identities, and nothing requires them to agree. One is used by mail servers to route the message and return bounces. The other is the one your finance controller read. SPF, DKIM and DMARC are three controls, each published as a DNS record, added later to close that gap. You almost certainly publish all three. Whether that protects anyone comes down to a single value in one of those records.
What it actually is
Email authentication is three DNS-published controls that let a receiving server decide whether a message genuinely originated from the domain it claims. The server doing that deciding is a mail transfer agent, or MTA: the software that accepts a message and relays it onward. Every organization runs them at both ends, one sending and one receiving, and the checks below all happen inside the receiving one, in the seconds before a message is accepted. Each answers a different question, and each authenticates a different identity.
SPF publishes a TXT record listing the sources
authorised to send for a domain. The receiving MTA takes the IP address of the
server currently connecting, looks up the record belonging to the domain in the
SMTP envelope, and checks whether that IP is authorised.
DKIM attaches a DKIM-Signature header to each outgoing
message. The header names a signing domain in its d= tag and a key selector in
s=. The receiver fetches the matching public key from that domain’s DNS and
verifies the signature.
DMARC publishes a TXT record at
_dmarc.yourdomain.com. It authenticates nothing itself. It reads the SPF and
DKIM results, tests whether either belongs to the domain in the From: header,
and publishes an instruction for what receivers should do when neither does.
That third control is doing more work than its position in the acronym list suggests. SPF and DKIM both authenticate identities your users will never see. Only DMARC examines the line on the screen, and that distinction is the whole subject.
Why it lands on your desk
Your domain is a brand asset that, right now, anyone in the world may be able to
send mail as. A DMARC record published with p=none is not a neutral state. It
is an unrevoked licence to impersonate you, issued to everybody, and the people
it harms are your customers and your suppliers. They will not distinguish between
a message you sent and a message that merely carried your name.
The reason this stalls is never the DNS record, which takes minutes. It is that
nobody can enumerate your senders. The marketing platform, payroll, the ticketing
tool, the CRM, an invoicing box that predates two of your predecessors, and the
three business units that each bought something without asking. Every one of them
sends as you, and most of them sign with their own d= domain. Building that
list is an organizational problem with a technical output, which is exactly the
kind of work that has no natural owner and therefore does not happen.
Rushing it is worse than delaying it. Move to p=reject before that inventory is
complete and your own invoices stop arriving, publicly, in a way that gets rolled
back within the hour. This needs somebody senior enough to say “not yet” and mean
it, which is usually you.
And it is drifting from good practice into a condition of doing business. Major mailbox providers now require authentication and a published DMARC record from bulk senders, and national guidance such as the NCSC’s anti-spoofing collection treats enforcement as the expected end state rather than an advanced option. Enforcement is also the precondition for BIMI, the standard that puts a verified logo beside your mail in the inbox: it needs your policy at quarantine or reject before the logo shows at all, and at Gmail and Apple it also needs a paid certificate proving you own the mark. So the day marketing asks for the logo, they are asking for enforcement and a budget line, in that order. Deliverability is on the line alongside security, which tends to find you money that security alone would not.
This is a programme with an owner and a register, not a switch with a ticket.
How it works, to the depth you need
You will never write these records. You do need to follow one message through the checks, because every argument you will have about this topic is really an argument about step three.
ONE MESSAGE, THREE CHECKS
what the message carries
+----------------------------------------------+
| MAIL FROM: bounce@bulk.mailer.net | the envelope
| DKIM-Signature: d=mailer.net; s=k1 | rides inside
| From: billing@yourbank.com | all you see
+----------------------------------------------+
|
v
1 SPF is the connecting IP authorised by the
v=spf1 record at bulk.mailer.net ? PASS
|
v
2 DKIM does the signature verify against the
key at k1._domainkey.mailer.net ? PASS
|
v
3 ALIGN does either authenticated domain match
the From: domain the reader sees ?
mailer.net vs yourbank.com FAIL
|
v
4 ACT nothing aligned, so apply the policy at
_dmarc.yourbank.com
p=none deliver it anyway
p=quarantine send it to junk
p=reject refuse it at the door
Two genuine passes, and the message is still a forgery. Step three is where the decision actually happens.
The two addresses in every email
Every message carries two sender identities, and confusing them is the root of every misunderstanding in this area.
The first is the envelope sender, set by the MAIL FROM command during the
SMTP conversation and also called the return-path. Mail servers use it to route
bounces. It is the identity SPF evaluates, and no mail client displays it. SPF
can also check the name the sending server introduces itself with, which is the
only identity available on a bounce, where the envelope sender is empty.
The second is the From: header, which sits inside the message alongside the
subject line. It is the only sender identity a human ever sees, and it is free
text that the sending system writes.
The physical analogy holds up: the address on the envelope gets the letter delivered, the letterhead inside tells you who wrote it, and the post office has never once compared them. SPF inspects the envelope. Your people read the letterhead.
SPF: authorising the sending infrastructure
An SPF record is a TXT record beginning v=spf1, followed by mechanisms naming
authorised sources: ip4: for your own ranges, and include: to inherit another
provider’s list wholesale. It ends in an all qualifier that tells receivers how
to treat everything else, usually -all for a hard fail or ~all for a softfail
that asks receivers to accept but mark the message.
Two properties matter to you. First, the record consulted is the one belonging to
the envelope domain, so a pass proves that some domain authorised the connecting
server and proves nothing about the From: header.
Second, SPF evaluation is capped at 10 DNS lookups. Every include: consumes
part of that budget, and third-party providers nest their own includes inside
yours. Exceed the limit and evaluation returns permerror, which signals a
broken publisher rather than an absent one, and which some receivers judge more
harshly than no record at all. What matters to you is that permerror is not a
pass, so SPF can no longer contribute anything, and your authentication is
resting entirely on DKIM without anyone deciding that it should. Nothing tells
you this has happened unless somebody is reading the aggregate reports, where the
result appears by name.
SPF also breaks on forwarding by design. When a mailing list or a mailbox rule
relays your message, the forwarder becomes the connecting server, and it was
never in your record. Genuine mail returns fail. That is not a defect, it is
the direct consequence of authenticating a route rather than a message, and it is
why a second mechanism exists.
DKIM: signing the message itself
DKIM signs the message rather than the route. Your mail system hashes the body
and a chosen set of headers, always including From:, then signs that hash with
a private key and attaches the result as a DKIM-Signature header.
Two tags in that header carry the meaning. d= names the signing domain,
which takes responsibility for the message and which need not be your domain.
s= names a selector, which points at one specific published key: the
receiver fetches it from s._domainkey.d, so a signature naming d=mailer.net; s=k1 sends the receiver to k1._domainkey.mailer.net.
Selectors are why a domain can publish several keys at once, which in turn is what makes key rotation possible without a verification gap, and what lets a third-party provider sign on your behalf under its own selector.
A verifying signature proves exactly two things: the signed content was not
altered after signing, and the domain in d= took responsibility for it. Two
corrections follow. DKIM is a signature, not a seal: it does not encrypt
anything, and the message is readable at every hop. And because the proof travels
inside the message, DKIM survives the forward that breaks SPF, though a mailing
list that appends a footer changes the body and invalidates the hash.
DMARC: the alignment test
Here is the scenario the first two controls cannot handle.
An attacker registers secure-bank-alerts.net. They own it legitimately. They
publish a correct v=spf1 record for it, generate a signing key, publish the
public half under their own selector, and sign their outgoing mail with
d=secure-bank-alerts.net.
SPF passes. DKIM passes. Neither result is a forgery or a misconfiguration. Both
correctly certify that secure-bank-alerts.net authorised the connection and
signed the content. The attacker then writes your bank’s address into the From:
header, because that header is free text and neither check has ever examined it.
Alignment is the test that closes this. DMARC compares the authenticated
domain against the From: domain, and fails the message when neither matches, no
matter how valid the underlying results were.
Alignment has two modes, and the default surprises people. Under relaxed
alignment, the default, a match at the organizational domain is enough, so
mail.yourbank.com aligns with yourbank.com. Under strict, set with
adkim=s for DKIM or aspf=s for SPF, the domains must match exactly. Relaxed
is what lets your own subdomains and bounce domains work without special
handling. It is also why yourbank.net never aligns with yourbank.com: they
are different organizational domains, however similar they look to a reader.
The verdict is recorded in the Authentication-Results header, which the
receiving MTA stamps onto the message. That header is what your analysts read
during triage, and it states each mechanism’s result and the DMARC outcome
separately, which is how you can see two passes above a DMARC failure and
understand why.
With all three described, the division of labour is easier to see side by side.
| SPF | DKIM | DMARC | |
|---|---|---|---|
| What it evaluates | The connecting server’s IP address | A cryptographic signature over the body and selected headers | The SPF and DKIM results, against the From: domain |
| Which identity it authenticates | The envelope domain, from MAIL FROM | The signing domain, from the d= tag | The From: header domain, by alignment |
| Where it is published | A TXT record at the envelope domain | A public key at selector._domainkey | A TXT record at _dmarc |
| Survives a forward | No. The relay becomes the connecting server. | Usually. The signature travels with the message. | Whichever mechanism survived |
| Its characteristic failure | permerror past 10 DNS lookups | A mailing list alters the body and breaks the hash | Left at p=none indefinitely |
| What a pass does not tell you | Anything about the From: header | That the mail is safe, or that d= is your domain | That the message is safe. It settles identity, not content. |
The ladder: none, quarantine, reject
Understanding alignment pays off in one place: the p= tag published alongside
it. There are three values, and only two of them are protection. Each is an
instruction to the receiving MTA about mail that failed alignment, and it is
worth being precise about what each one actually instructs.
p=none tells receivers to take no DMARC-based action at all. The message is
delivered exactly as it would have been if you published nothing, and a report is
sent. Nothing about delivery changes, which is how a domain can hold a valid
DMARC record and remain completely spoofable.
p=quarantine tells receivers to treat failing mail as suspicious. In
practice that means the junk folder, though the precise handling is the
receiver’s choice. The message still reaches the recipient, who can find it and
act on it, so this is containment rather than prevention.
p=reject asks receivers to refuse the message outright, ideally during the
SMTP conversation and before it is ever accepted. The large consumer providers
generally do exactly that. Many enterprise filters accept the message and drop it
into quarantine instead, because their analysts need it there to review. Either
way the recipient does not get it in their inbox, which is the difference that
matters: quarantine relocates a forgery, and reject removes it.
One thing to hold on to: these are requests that receivers choose to honour, not enforcement you carry out. The standard is explicit that a receiver may decline to apply what you publish, and most large receivers feed your policy into a wider filtering decision rather than treating it as a switch. Its value comes from the fact that they honour it consistently, not from any power you hold over them.
Two tags modify that, and one trap sits beside them. Subdomains inherit your p=
policy automatically, so the danger is not a missing sp= tag but a published
one that is weaker than the parent: p=reject; sp=none is a real hole, and it
usually got there during a rollout and was never tightened. np= covers
subdomains that do not exist at all, which is the cheapest hardening available,
because nothing legitimate ever sends from a subdomain you never created.
The trap is pct=. It used to sample a percentage of failing mail, and it was
removed from the standard in 2026. Receivers must ignore tags they do not
recognise, so publishing p=reject; pct=10 today does not give you a ten percent
ramp. It gives you full enforcement immediately, which is the exact outage this
section exists to prevent. If pct= is sitting in your record, it is doing
nothing, and it should come out at the next change.
One distinction here is worth more than it looks, because almost nobody makes it:
p= and rua= are independent tags. Aggregate reports reach you because you
published a rua= address, not because your policy is none. They keep arriving
at p=reject. Reporting does not switch off when you start enforcing, so “we
need to stay at none to keep getting the data” is not a real constraint. A domain
with p=none and no rua= is neither defended nor watching.
Those reports arrive as compressed XML, typically daily, one file per reporting receiver. That is why “nobody reads them” is a tooling problem rather than a discipline problem: without a parser they are genuinely unreadable, and the budget line you actually need is a DMARC reporting platform rather than another awareness campaign.
The staged path follows directly, and dmarc.org’s
overview sets out the same sequence. Publish at
p=none with a working rua=, use the reports to find every legitimate sender
failing alignment, bring each into alignment or authorise it, then move to
p=quarantine, then p=reject. The reports are the tool. Enforcement is the
goal. Most organizations mistake the tool for the destination and stop.
Where it goes wrong
The cryptography almost never fails. The operations and the misreadings do.
- The policy has been at
p=nonefor two years. Somebody published a record, closed the audit finding, and moved on. You have telemetry and no protection, and everyone above you believes the opposite. This is the most common state of a domain that “has DMARC”. - The
include:chain has quietly blown the lookup budget. Each SaaS sender you authorise nests its own includes inside yours. Past 10 lookups evaluation returnspermerror, SPF stops contributing, and your authentication silently rests on DKIM alone. It shows up in the aggregate reports and nowhere else, which is another reason somebody has to be reading them. - The sender inventory is incomplete, so enforcement never comes or breaks payroll when it does. The aggregate reports exist precisely to close this gap, and usually nobody has parsed them.
- Selectors are never rotated. Every provider signing as you holds a private key you do not control and have not audited. Publishing a new key under a new selector is the intended rotation path and is almost never scheduled.
- A third party signs with its own
d=and therefore cannot align. The platform is authenticating correctly, for itself. Until it is configured to sign as your domain, its mail fails DMARC, and fixing that is a vendor conversation rather than a DNS change. Mailing lists cause the same failure by altering the body. Authenticated Received Chain (ARC) is the partial answer, and it is worth knowing its limits before a vendor offers it to you: it lets a forwarder record the results it saw, it repairs nothing by itself, receivers may ignore it, and it has to be implemented by the forwarder rather than by you. - Your other domains are wide open. Enforcement lands on the primary domain
while acquired brands, campaign domains, and parked domains sit there as free
impersonation infrastructure. A domain that sends no mail should say so in
every way available:
v=spf1 -all, a null MX record, a DMARC record atp=rejectwithsp=rejectandnp=reject, and a wildcard DKIM record revoking any key. That takes one afternoon per domain and it is the cheapest control in this article.
What it does not stop
Everything above can work perfectly and the phishing message still arrives. This is the section to hand upward before anyone tells a board that email is solved.
Lookalike domains. yourbank-secure.com publishes its own records,
authenticates flawlessly, and aligns perfectly with itself. DMARC has no opinion
about domains that are not yours. Your controls here are brand monitoring and
takedown, not DNS.
Display-name spoofing. The From: header
carries a friendly name alongside the actual address. DMARC checks the domain in
the address. It never checks the name, and most mobile clients show only the
name.
Compromised legitimate accounts. This is the one enforcement cannot touch. When an attacker is operating inside a real mailbox on your domain, the message is signed by your keys and aligns perfectly, because it is not a forgery in any technical sense. A great deal of business email compromise looks exactly like this, which is why “we moved to reject” is not an answer to “are we protected from invoice fraud”.
Content. Authentication settles identity. It never inspects links, attachments, or intent, and an aligned message can carry all three.
Mail spoofing other people’s domains. Publishing your policy protects everyone from being forged as you, and that includes your own staff: your gateway checks inbound mail against your published policy too, which is what kills the classic message from your chief executive to your finance team. What it does nothing about is mail forging somebody else’s domain at your people. Catching that means your gateway honours the policies other domains publish, which is a separate setting, usually in the same product you already own, and often left at monitor-only strength because nobody went looking for it.
Enforcement removes one specific and valuable attack: somebody sending as your exact domain. That is worth having. It is also one layer, and it expects brand monitoring, content filtering, and trained people standing around it. Treating it as a complete answer is how phishing keeps working against organizations that believe they have handled it.
The questions worth asking
You will not write the records. You will decide whether anyone is accountable for them, and whether what gets reported upward is true. These separate a programme from a published record:
- What is the
p=value on every domain we own, not just the one on our business cards, and when did somebody last check each of them? - Is our
sp=weaker than ourp=, left over from a rollout nobody finished, and do we publishnp=rejectfor subdomains that do not exist? - Do we have a current list of every service that sends as us, and whose job is it to update that list when a business unit buys something new?
- Who parses the aggregate reports, what tool do they use, and what did the last one change?
- How many DNS lookups does our SPF record currently consume, and who would notice if the next vendor pushed it past the limit?
- If we moved to
p=rejectnext week, what legitimate mail would stop arriving, and do we know that or are we assuming it? - On inbound mail, do we enforce the policies other organizations publish, or do we only publish our own and call that protection?
If those get crisp answers, you have a programme. If they get shrugs, you have a DNS record and an unlocked door, and the record is the part that will be quoted back to you.
A domain that monitors and never enforces is not protected. It is documented.