SMTP, the protocol that moves email between servers, was designed in 1982 and has no concept of identity. Any server can connect to any mail server and claim to be sending on behalf of any domain. The From: line in an email is a text field. Nothing in the protocol checks it.
Everything about email authentication follows from that one gap. SPF, DKIM, and DMARC are three DNS-based standards bolted onto SMTP over the past two decades, and each answers a different question:
| Standard | Question it answers |
|---|---|
| SPF | Is this server allowed to send mail for this domain? |
| DKIM | Was this message actually authorized by the domain, and has it been modified? |
| DMARC | Do the SPF/DKIM results match the From: address the recipient sees, and what should happen if they don't? |
You need all three. Since February 2024, Gmail and Yahoo require SPF or DKIM from every sender and the full trio from bulk senders (5,000+ messages a day, by Gmail's definition); Microsoft added matching requirements for high-volume Outlook senders in 2025. Falling short means rejected or junked mail, not a warning. This post explains what each record does, how the three interact, and the mistakes that cause most authentication failures.
The Two "From" Addresses#
Before any of the three standards makes sense, you need to know that every email has two sender addresses, and they are usually different:
- The envelope sender (also called Return-Path, MAIL FROM, or bounce address). This is set during the SMTP conversation, before the message content is transmitted. It's where bounces go. Recipients don't normally see it, though it survives as the
Return-Path:header if someone digs into the raw message. - The header From is the
From:line inside the message. This is what shows in the recipient's mail client.
An email sent through euromail for yourdomain.com has an envelope sender like [email protected] (a sending subdomain of your own domain, with the message's ID embedded so we can match the bounce back to it) and a header From of [email protected] (what your customer sees).
This split matters because SPF checks the envelope sender, DKIM checks a signature chosen by the sending system, and only DMARC checks the address the human actually reads. Attackers exploit exactly this gap: a phishing email can pass SPF for the attacker's own envelope domain while displaying your domain in the From line. Without DMARC, nothing connects the two.
SPF: An Allowlist of Sending Servers#
SPF (Sender Policy Framework, RFC 7208) is a TXT record on your domain listing the servers permitted to send mail for it. When a mail server receives a message, it looks up the SPF record of the envelope sender's domain and checks whether the connecting IP is on the list.
A typical record:
yourdomain.com. TXT "v=spf1 include:spf.euromail.dev -all"
Reading left to right: version 1, authorize every IP that spf.euromail.dev's own SPF record authorizes, and fail everything else. The record lives on whatever domain appears in your envelope sender, which is not necessarily your apex: with euromail it goes on the em.yourdomain.com sending subdomain, because that's the domain in the envelope. The include: mechanism is what lets you delegate to an email provider without hardcoding their IP addresses, and the final all mechanism sets the default. The qualifier in front of it matters:
-all(fail): unauthorized mail should be rejected~all(softfail): unauthorized mail is suspect but shouldn't be rejected outright+all(pass): every server on the internet is authorized. Never use this. It announces that your SPF record is decorative.
Two rules trip people up constantly. First, a domain can have only one SPF record; if you use multiple services, merge them into a single record with multiple include: mechanisms. Second, evaluating a record may use at most 10 DNS-querying mechanisms (include:, a, mx, and friends), counted recursively through every nested include:. Accumulate enough SaaS tools in one record and you'll silently exceed the limit, at which point SPF returns a permanent error for all your mail.
SPF also has a structural weakness: it breaks on forwarding. When a university mailbox or an old ISP address forwards mail onward, the forwarding server's IP isn't in your SPF record, so the check fails even for legitimate mail. Forwarders can work around this by rewriting the envelope sender (a scheme called SRS), but many don't, and as the sender there's nothing you can do about it. It's the reason DKIM exists and the reason DMARC doesn't require both checks to pass.
DKIM: A Cryptographic Signature That Travels With the Message#
DKIM (DomainKeys Identified Mail, RFC 6376) takes a different approach. Instead of validating the connecting server, the sending system signs each message with a private key, and receiving servers verify the signature against a public key published in your DNS.
The public key lives at <selector>._domainkey.<signing domain>. For a euromail domain, that's:
euromail._domainkey.em.yourdomain.com. TXT "v=DKIM1; k=rsa; p=MIIBIj..."
Here euromail is the selector and em.yourdomain.com is the signing domain. Selectors let a domain publish several keys at once, which is what makes key rotation possible: publish a new key under a new selector, switch signing over, then retire the old record. Keys should be 2048-bit RSA; Gmail requires at least 1024 bits and recommends 2048, and 1024-bit keys are considered weak enough that there's no reason to generate one today.
The signature itself rides in a DKIM-Signature: header. It covers selected headers (always including From) plus a hash of the message body. A receiving server recomputes the hashes, fetches the public key from <selector>._domainkey.<domain>, and verifies. If anything covered by the signature was altered in transit, verification fails.
Because the signature is part of the message rather than a property of the connection, DKIM survives forwarding. That makes it the more robust of the two mechanisms in practice. Its weakness is the mirror image: anything that rewrites the signed content breaks it. Mailing lists that append footers or rewrite subject lines are the classic case.
One thing DKIM does not do on its own: it doesn't require the signing domain to have any relationship to the From address. A spammer can validly DKIM-sign a message with spammer-domain.com's key while the From line says yourbank.com. The signature passes. Connecting the signing domain to the visible From address is DMARC's job.
DMARC: Tying It to the Address Recipients See#
DMARC (Domain-based Message Authentication, Reporting, and Conformance, RFC 7489) closes the loop with a concept called alignment. A message passes DMARC when at least one of the two mechanisms passes and that mechanism's domain aligns with the header From domain:
- SPF alignment: the envelope sender domain aligns with the From domain
- DKIM alignment: the DKIM signing domain (the
d=value in the signature) aligns with the From domain
"Aligns" is looser than "matches". In DMARC's default relaxed mode, sharing the organizational domain is enough: em.yourdomain.com aligns with yourdomain.com. Strict mode (aspf=s / adkim=s in the record) requires an exact match, and almost nobody needs it.
One aligned pass is enough. This is a deliberate design decision, not a loophole: SPF breaks on forwarding and DKIM breaks on content rewriting, so requiring both would fail large amounts of legitimate mail. Providers that use their own bounce domain for the envelope sender leave SPF passing but unaligned, and DKIM carries the DMARC pass alone; euromail instead puts the envelope sender on a subdomain of your own domain (em.yourdomain.com), so both mechanisms align. And on forwarded mail, DKIM-only passes are normal and healthy for everyone.
The record also declares what receivers should do with mail that fails:
_dmarc.yourdomain.com. TXT "v=DMARC1; p=reject; rua=mailto:[email protected]"
Three policies exist: p=none (deliver normally, just send me reports), p=quarantine (send failures to spam), and p=reject (refuse them). Strictly speaking the policy is a request that receivers may override, but the large mailbox providers honor it. The rua tag is where receiving servers send daily aggregate reports: XML summaries of every source that sent mail claiming your domain, with pass/fail counts per IP.
Those reports are the underrated half of DMARC. They're the only way to see who is sending as your domain across every participating receiver, which includes all the major mailbox providers: services you forgot about, spoofing attempts you'd otherwise never know occurred. Reading raw DMARC XML is miserable, which is why tooling exists to parse it; euromail ingests and visualizes these reports if you point your rua tag at us.
The standard rollout, and the reason p=none exists at all:
| Phase | Policy | What you're doing |
|---|---|---|
| 1 | p=none | Collect reports for a few weeks. Find every legitimate service sending as your domain and fix its authentication. |
| 2 | p=quarantine | Enforce softly once reports show your real mail aligning. |
| 3 | p=reject | Full enforcement. Spoofed mail from your domain gets refused at the door. |
The common failure mode is stalling at phase 1 forever. p=none satisfies Gmail's minimum requirement, but it tells receivers to deliver spoofed mail normally. Treat it as a monitoring phase with an end date, not a destination.
How a Passing Message Actually Looks#
Putting the three together, here's the lifecycle of one message sent through euromail for yourdomain.com. All the sending records live on the em.yourdomain.com subdomain, which keeps your transactional email reputation separate from the root domain:
- Your API call hits
POST /v1/emails. The worker builds the MIME message and DKIM-signs it with the 2048-bit key whose public half you published ateuromail._domainkey.em.yourdomain.com, withd=em.yourdomain.comin the signature. - An SMTP connection opens from one of our sending IPs with envelope sender
[email protected], whereabc123is the message's ID; if it bounces, the reply routes back to us carrying the ID of exactly which email failed. - The receiving server checks SPF:
em.yourdomain.com's record saysv=spf1 include:spf.euromail.dev ~all, and the connecting IP is on that list. Pass, andem.yourdomain.comaligns withyourdomain.comunder relaxed mode. - It verifies the DKIM signature against your DNS record. Pass, and
d=em.yourdomain.comaligns too. - DMARC: both mechanisms passed aligned; either alone would have been enough. Your
p=rejectpolicy never triggers. - A spoofer trying the same From address from their own server fails both aligned checks, and your
p=rejecttells the receiver to refuse the message.
Authentication doesn't guarantee inbox placement. It's the entry ticket, after which reputation, complaint rates, and content decide the rest; we've written about watching that side of the equation in Google Postmaster Tools. But without the ticket you don't get evaluated at all.
The Mistakes We See Most#
Two SPF records on one domain. Usually the result of pasting a new provider's record instead of merging it into the existing one. Multiple v=spf1 records are a permanent error: receivers can't evaluate either one, so under DMARC your SPF contributes nothing. Merge everything into one record.
Blowing the 10-lookup limit. Each include: counts, recursively. Marketing tool, helpdesk, CRM, payroll... records accumulate includes for years and then break with no visible symptom except failing authentication. Check your record with a validator that counts lookups whenever you add a service.
A DKIM record that's cut off. 2048-bit public keys exceed the 255-character single-string limit in TXT records. Most DNS providers split long values automatically, but some truncate silently. If DKIM fails immediately after setup, compare the published record character by character against what your provider gave you.
DMARC without rua. A policy with no reporting address means enforcing blind. You get the protection but lose the visibility, and visibility is what tells you before you move to p=reject whether you're about to break a legitimate sender.
Forgetting subdomains. By default your DMARC policy covers subdomains, but a separate sp= tag can override it, and subdomains with their own DMARC records take precedence. Spoofers deliberately target unprotected subdomains of otherwise locked-down domains.
Setting This Up in Practice#
If you're running your own mail infrastructure, you now have keys to generate, signing to configure, and three records to maintain per domain. If you're using an email provider, the provider generates all of it and your job is copying three DNS records.
With euromail, adding a domain returns everything in one API response: your SPF record, your DKIM public key, a return-path record for bounce routing, and a recommended DMARC record. We check for the records every five minutes and show per-record status in the dashboard, and once mail is flowing, the DMARC monitoring dashboard tracks your alignment rate from the aggregate reports receivers send back.
Each of these three standards has enough depth for a post of its own: SPF's macro syntax and lookup-limit workarounds, DKIM's canonicalization modes and rotation strategy, DMARC's alignment edge cases. We'll dig into them separately. This one covers what you need to ship: three TXT records, one aligned pass, and a policy that actually says reject by the time you're done.