The short answer

Email was designed without any proof of who sent a message. Anyone can connect to a mail server and type From: ceo@example.com, and the oldest phishing trick is to do exactly that with your domain. Three standards close that gap, and each one is published as a TXT record in your DNS zone:

  • SPF, defined in RFC 7208, lists the servers allowed to send mail for a domain.
  • DKIM, defined in RFC 6376, adds a cryptographic signature that receivers verify with a public key from DNS.
  • DMARC, defined in RFC 9989, which replaced the original RFC 7489 in May 2026, requires one of those checks to pass for the same domain the reader sees in the From line, and publishes what to do when neither does.
SPF and DKIM alone do not stop spoofing.

Both check a domain, but not necessarily the one in the From line. An attacker can pass SPF and DKIM for a domain they own while showing yours. Only DMARC, with a policy of quarantine or reject, closes that gap.

How a message is checked when it arrives

When a message reaches your organization's mail gateway, the receiving server runs SPF and DKIM side by side, checks whether each result lines up with the From domain, and then applies DMARC. The diagram follows one message from 203.0.113.10 that claims to be from example.com.

How a receiving mail server checks SPF, DKIM and DMARC A message from 203.0.113.10 arrives at your MX claiming to be from example.com. SPF checks whether the sending IP is authorized for the MAIL FROM domain, and DKIM checks the signature with the selector's public key. Each passing result must also align with the From domain. DMARC passes if at least one aligned check passes and the message goes to the inbox. Otherwise the domain's DMARC policy applies: reject refuses the message, quarantine sends it to junk, and none delivers it while reporting. In test mode, t=y, receivers handle failing mail one step softer. Sending server 203.0.113.10 says it is example.com SMTP Message arrives at your MX SPF MAIL FROM: bounce@mail.example.com DKIM DKIM-Signature: d=example.com; s=s1 DMARC From: CEO <ceo@example.com> Public DNS Each check reads a TXT record the domain owner publishes. Both checks run SPF Is the sending IP authorized? Checks 203.0.113.10 against the SPF record of the MAIL FROM domain, mail.example.com. TXT v=spf1 ip4:203.0.113.0/24 -all DKIM Is the signature valid? Verifies the signature with the public key published for selector s1 at example.com. s1._domainkey TXT v=DKIM1; p=MIIBIj… Pass Pass Does it align with the From domain? mail.example.com ↔ example.com Not aligned Aligned Does it align with the From domain? d=example.com ↔ example.com Aligned Not aligned Fail Fail or not aligned Fail Fail or not aligned DMARC Did SPF or DKIM pass and align? One aligned pass is enough. The policy is in DNS: _dmarc TXT v=DMARC1; p=reject Yes: DMARC pass No: DMARC fail Passes DMARC; local policy applies Normal spam and content filtering still applies. Reports go to rua Participating receivers send daily aggregate reports. Apply the domain's policy (p=) reject Usually refused during SMTP quarantine Quarantine requested; local policy applies none No DMARC enforcement requested Test mode (t=y) handles failing mail one step softer: reject → quarantine, quarantine → none. How a receiving mail server checks SPF, DKIM and DMARC A message arrives at your MX claiming to be from example.com. SPF checks whether the sending IP is authorized for the MAIL FROM domain, and DKIM checks the signature with the selector's public key. Each passing result must also align with the From domain. DMARC passes if at least one aligned check passes and the message goes to the inbox. Otherwise the domain's DMARC policy applies: reject refuses the message, quarantine sends it to junk, and none delivers it while reporting. In test mode, t=y, receivers handle failing mail one step softer. Message arrives at your MX SPF MAIL FROM: bounce@mail.example.com DKIM DKIM-Signature: d=example.com DMARC From: ceo@example.com SPF Is the sending IP authorized? Checks 203.0.113.10 against the SPF record of mail.example.com. TXT v=spf1 ip4:203.0.113.0/24 -all Then: does it align with From? mail.example.com ↔ example.com Pass + aligned Fail or not aligned DKIM Is the signature valid? Verifies the signature with the key published for selector s1. s1._domainkey TXT v=DKIM1; p=MIIB… Then: does it align with From? d=example.com ↔ example.com Pass + aligned Fail or not aligned DMARC Any aligned pass? SPF or DKIM must pass and align with the From domain. One is enough. _dmarc TXT v=DMARC1; p=reject Yes: pass No: fail Passes DMARC; local policy applies Normal spam and content filtering still applies. Apply the domain's policy (p=) reject Usually refused at SMTP quarantine Sent to junk or held none No enforcement requested Test mode (t=y) handles failing mail one step softer: reject → quarantine, quarantine → none. Reports go to rua Participating receivers send daily aggregate reports to the domain owner.
Red dashed paths show a check failing or not aligning. DMARC only needs one aligned pass; if there is none, the domain's published policy decides what happens.

Every receiver that supports DMARC follows this order, whether it is a large mailbox provider or your own gateway checking inbound mail. That is why the same three records protect both your customers, who receive mail claiming to be from you, and your staff, who receive mail claiming to be from partners and suppliers.

The three identities in every message

Most confusion about email authentication comes from the fact that a single message carries several domain names, and each standard looks at a different one.

IdentityWhere it livesChecked bySeen by the reader?
Envelope sender, also called MAIL FROM or Return-PathThe SMTP conversation; bounces go hereSPFNo
Signing domain, the d= tagThe DKIM-Signature headerDKIMNo
Header FromThe From: headerDMARC, through alignmentYes

A newsletter platform might send your campaign with a MAIL FROM of bounces.mailer.example.net and a DKIM signature from mailer.example.net, while the From line shows news@example.com. SPF and DKIM both pass, but for the platform's domain, not yours. DMARC fails until the platform is set up to sign as example.com or to use a bounce domain under it.

SPF: which servers may send

An SPF record is a TXT record at the domain used in MAIL FROM. It lists the addresses and services allowed to send for that domain and ends with a default for everything else.

$ dig +short TXT example.com
"v=spf1 ip4:203.0.113.0/24 include:_spf.mailprovider.example -all"

The receiver evaluates the mechanisms from left to right and stops at the first match. ip4 and ip6 match address ranges, include pulls in another domain's SPF record, and the final all catches everything else. Its qualifier sets the result: -all is a hard fail, ~all is a soft fail, and +all authorizes the entire internet, which defeats the record.

  • One record per name. Two TXT records starting with v=spf1 at the same name produce a permanent error, and receivers treat the domain as having no valid SPF.
  • Ten DNS lookups at most. Each include, a, mx, exists and redirect counts, including those inside included records. Going over the limit is also a permanent error, and it is easy to hit after adding a few SaaS senders.
  • Forwarding breaks SPF. When a mailbox forwards a message, the next hop sees the forwarder's IP, which your record does not list. That is one reason DKIM matters.

The TXT records guide covers how SPF shares the TXT type with other verification records, and SPF/DMARC Misconfigurations lists the mistakes that most often weaken it.

DKIM: a signature that survives forwarding

The sending system signs selected headers and the body with a private key and adds a DKIM-Signature header. The d= tag names the signing domain and s= names the selector, which tells the receiver where to find the public key:

DKIM-Signature: v=1; a=rsa-sha256; d=example.com; s=s1; h=from:to:subject:date; bh=…; b=…

$ dig +short TXT s1._domainkey.example.com
"v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA…"

Because the signature travels inside the message, it still verifies after simple forwarding. It fails when something changes the signed content on the way, such as a mailing list that adds a footer or a gateway that rewrites links. Selectors let each sending service have its own key, so you can add or retire a provider without touching the others. Key sizes, selector naming and rotation are covered in DKIM Explained: Selectors and Key Rotation.

Alignment: the step that stops spoofing

DMARC only counts an SPF or DKIM pass if its domain aligns with the From domain. There are two modes, set separately for each check:

ModeTagRuleFrom: example.com aligns with
Relaxed (default)aspf=r, adkim=rSame organizational domainexample.com, mail.example.com, eu.news.example.com
Strictaspf=s, adkim=sExactly the same nameexample.com only

Relaxed alignment is right for almost everyone, because it lets you give each sending service its own subdomain. Strict alignment is occasionally used to stop a team that controls a subdomain from sending as the parent domain.

Alignment is what makes the attacker's job hard. They can publish SPF and DKIM for attacker.example and pass both checks, but neither result aligns with example.com in the From line, so DMARC fails and your policy applies.

DMARC: the policy and the reports

The DMARC record is a TXT record at _dmarc under the From domain:

$ dig +short TXT _dmarc.example.com
"v=DMARC1; p=reject; sp=reject; rua=mailto:dmarc-reports@example.com; adkim=r; aspf=r"
TagMeaning
pRequested disposition for failing mail: none (no DMARC enforcement), quarantine (request suspicious treatment) or reject (request rejection). Receivers may override these requests under local policy
spPolicy for subdomains; if absent, subdomains inherit p
npPolicy for subdomains that do not exist at all, a favorite of spoofers; if absent, sp and then p apply
tTest mode. With t=y, receivers treat failing mail one step softer than the policy: reject becomes quarantine and quarantine becomes none. The default is t=n
ruaWhere participating receivers send daily aggregate reports. Not every receiver sends them, so a quiet report is not proof that no mail was sent
rufWhere to send per-message failure reports; few large receivers send them, for privacy reasons
adkim, aspfAlignment mode for DKIM and SPF, relaxed by default

Older guides use a pct tag to apply the policy to a percentage of failing mail. RFC 9989 removed it, because receivers only applied 0 and 100 consistently, and replaced it with t. Receivers that follow the current standard ignore pct, so a record such as p=reject; pct=25 can mean rejecting all failing mail. Use t=y for a softer step instead. Receivers that have not moved to RFC 9989 yet ignore t, so during the transition pair it with pct=0, which those older receivers read the same way: p=quarantine; t=y; pct=0 is handled as none by both generations, and newer receivers ignore the pct tag. Remove any other pct value.

Aggregate reports, defined in RFC 9990, are XML summaries grouped by sending IP. Each row says how many messages that IP sent as your domain and whether SPF and DKIM passed and aligned. Most large mailbox providers send them, which makes them the best way to discover the services that send as you, from the CRM to the payroll system, before you start rejecting mail.

A safe path to p=reject

  1. Publish v=DMARC1; p=none; rua=mailto:… and confirm reports arrive. If the report address is in another domain, that domain must authorize it with a v=DMARC1 TXT record named after both domains, such as example.com._report._dmarc.reports.example.net for reports sent to an address at reports.example.net.
  2. Read two to four weeks of reports. List every source that sends as your domain and mark each as yours, a vendor's, or unknown.
  3. For each legitimate vendor, turn on DKIM signing with your domain and, where offered, a custom bounce domain so SPF aligns too. Retire anything nobody owns.
  4. Keep p=none for at least a month, then move to p=quarantine for at least another month and keep reading reports. Publishing it first as p=quarantine; t=y; pct=0 gives a gentler step that both old and new receivers honor.
  5. When the only failures left are spoofing and known forwarding, move to p=reject and set sp=reject.
Lock down domains that never send mail

Parked and defensive domains are popular for spoofing because nobody watches them. Give each one v=spf1 -all, a DMARC record with p=reject, and a null MX record (MX 0 .) so receivers know at once that no mail should come from it.

Mailing lists and p=reject

Mailing lists often change messages in ways that break DKIM, and they resend from their own servers, which breaks SPF. RFC 9989 says domains whose users post to mailing lists should not publish p=reject, because subscribers at other domains may stop receiving those posts or be unsubscribed. For a domain used by staff, p=quarantine is often the right end state. If you still choose reject, warn users first. Brand and transactional domains that people never use for list mail can go to reject safely.

Large mailbox providers now expect this work. Since February 2024, Google and Yahoo have required bulk senders to authenticate with SPF and DKIM and publish at least a p=none DMARC record, and mail from domains without them is increasingly filtered or refused.

What DMARC does not stop

DMARC can reduce exact-domain spoofing at receivers that enforce the requested policy. Receiver policy can override the requested disposition, and DMARC does not guarantee delivery or rejection. Phishing that avoids your domain needs other controls:

  • Lookalike domains such as examp1e.com or a homograph built from other scripts, covered in Internationalized Domain Names. The attacker owns the domain and can pass DMARC for it.
  • Display-name spoofing, where the name reads "Example IT Support" but the address is a free mailbox.
  • Compromised accounts and vendors. Mail sent from a real, hijacked mailbox passes every check.

Once you are at enforcement, BIMI can display your logo next to authenticated mail, which gives readers a visible signal that is hard to fake. Protecting the mail in transit, so it cannot be read or redirected on the way to you, is a separate job covered in Secure Email Transport: STARTTLS and DANE.

How DNS Panopticon helps

The shared DNS scan reads a domain’s SPF and DMARC records; Domain Visualizer shows records and Security Posture displays findings for a missing SPF record, more than one SPF record, an SPF record that ends in +all, a missing DMARC record, and a policy left at p=none. It also looks for DKIM keys at the common selector1 and selector2 selectors. Your provider may use other selector names, so a missing result there is a prompt to check, not proof that DKIM is off.

Website Recon is useful from the other direction. When a suspicious message arrives, scan the domain in its From line to see when it was registered, by whom, and whether it looks like an impersonation of a domain you know.

To see how one message fared, paste its headers into Email Header Analyzer. It draws the route the message took, sets the envelope sender and DKIM signing domain beside the From address with their alignment, and shows the SPF, DKIM and DMARC results the receiving server recorded. The headers are parsed in your browser and never uploaded.

FAQ

If SPF and DKIM both pass, why can DMARC still fail?

Because DMARC also requires alignment. SPF can pass for a bulk mail provider's bounce domain and DKIM can pass for the provider's own signing domain, while the From address shows your domain. Neither result is about your domain, so DMARC fails until the provider signs with your domain or uses a custom bounce domain under it.

Do I need both SPF and DKIM for DMARC?

DMARC passes with either one aligned pass, but you should deploy both. SPF breaks when mail is forwarded, and DKIM breaks when a mailing list or gateway rewrites the message, so having both keeps legitimate mail passing in more situations.

Is p=none useless?

It requests no enforcement under DMARC; it does not guarantee delivery, because receivers still apply their own anti-abuse policies. It is a useful first step for monitoring. It turns on aggregate reports, which show the services sending as your domain from the receivers that report, so you can fix them before moving to quarantine and then reject.

Does DMARC stop all phishing?

No. It reduces exact-domain spoofing, where an attacker puts your own domain in the From address, at receivers that enforce the policy. It does not stop lookalike domains, display-name tricks, or mail sent from a real account that has been compromised. Those need user training, lookalike monitoring and account security.