uCheckeruChecker
Mark AvrilovPublished updated 14 min read

SPF, DKIM, and DMARC setup: a step-by-step guide

Three DNS records without which mailbox providers treat your mail with suspicion. Since February 2024, Gmail has required SPF, DKIM and DMARC from anyone sending more than 5,000 messages a day to personal Gmail accounts. Yahoo introduced similar rules for bulk senders that same February. Microsoft followed in 2025 for the consumer Outlook.com addresses on outlook.com, hotmail.com and live.com: domains sending over 5,000 messages a day need SPF, DKIM and DMARC at p=none or stricter. Its first announcement routed non-compliant mail to Junk, but the final rule, in force since 5 May 2025, rejects it with 550 5.7.515. The details are in our breakdowns of the Gmail requirements and the Yahoo requirements.


What SPF, DKIM, and DMARC actually do

The short version: they prove that a message came from you, not from someone who spoofed the From header. Each protocol covers a different part of that proof.

SPF (Sender Policy Framework) is a list of servers permitted to send mail on behalf of your domain. When a message arrives, the receiving server checks the sender's IP against your SPF record in DNS. If it matches, fine. If not, suspicious. SPF never looks at the content, though: mail sent through a hijacked account at your ESP leaves from an authorized server and passes SPF. Checking the message itself is the job of DKIM.

DKIM (DomainKeys Identified Mail) is a cryptographic signature. Each message is signed with a private key on the sending server. The receiving server fetches the corresponding public key from DNS using a selector, then verifies the signature. If the body or headers were changed in transit, the signature won't match. What DKIM does not tell the receiver is what to do with a message whose signature fails or is missing, and that part falls to DMARC.

DMARC (Domain-based Message Authentication, Reporting & Conformance) ties SPF and DKIM together into a single policy. It tells receiving servers what to do with messages that fail authentication, and sends you reports about who is sending from your domain.

Step 1. Configuring SPF

An SPF record is a TXT record in your domain's DNS that lists the legitimate sources of your outbound mail.

Minimal example

yourdomain.com.  IN  TXT  "v=spf1 include:_spf.google.com ~all"

Breaking it down:

  • v=spf1: the version tag. Always spf1; no other version exists.
  • include:_spf.google.com: authorizes Google Workspace servers to send on your behalf.
  • ~all: soft fail for everything else. The message isn't rejected, but it gets flagged.

A more realistic example

Say you use Google Workspace for corporate mail, Mailgun for transactional messages, and Brevo (formerly Sendinblue) for marketing campaigns.

yourdomain.com.  IN  TXT  "v=spf1 include:_spf.google.com include:mailgun.org include:sendinblue.com -all"

Notice -all instead of ~all. That is a hard fail: anything not on the list gets rejected, which is stricter and makes your domain harder to spoof. Use -all in production once you're confident you know every sending source.

Verification

dig TXT yourdomain.com +short | grep spf

You should get exactly one line starting with v=spf1. Exactly one. With two records, RFC 7208 evaluation ends in a permerror and SPF stops working altogether.

Common SPF mistakes

  • More than 10 DNS lookups. SPF caps at 10 lookups, and include, a, mx, ptr, exists and redirect all count toward it. Exceed the limit and the record is invalid. Check with dmarcian.com/spf-survey or mxtoolbox.com/spf.aspx.
  • Two TXT records with v=spf1. Merge everything into one record. RFC 7208 requires exactly one SPF record per domain.
  • Forgetting a sending service. You connect a new service but leave its include out of SPF, and its messages fail SPF. Take the value from the service's documentation: many send with an envelope on their own domain, in which case no include is needed at all.
  • Using +all. This authorizes anyone to send from your domain, a pointless record that we've seen in production, and it never ends well.

Step 2. Configuring DKIM

DKIM uses a key pair: a private key on the sending server and a public key in DNS. The server signs the headers and body of every message. The receiving side looks up the public key by selector and verifies the signature.

Generating keys

If you use an external ESP (Mailgun, SendGrid, Postmark), they generate the keys and you add a CNAME or TXT record. For a self-hosted server (Postfix, Exim, Haraka):

# Generate a 2048-bit RSA key
openssl genrsa -out dkim_private.pem 2048
openssl rsa -in dkim_private.pem -pubout -out dkim_public.pem

# Extract the public key as a single line (for DNS)
grep -v "^-" dkim_public.pem | tr -d '\n'

DNS record

Publish the public key as a TXT record at selector._domainkey.yourdomain.com. The selector is any string you choose. Common choices are s1, mail, google, or the ESP name.

s1._domainkey.yourdomain.com.  IN  TXT  "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2K...your_key..."

A 2048-bit key is longer than 255 characters, the limit for a single TXT string. Some DNS panels split it for you; with others you split it by hand into quoted segments of up to 255 characters. Receivers join them with no spaces, so a stray space at a join breaks the key.

Verification

dig TXT s1._domainkey.yourdomain.com +short

The response should contain v=DKIM1 and the public key. No response means either the selector is wrong, or the record hasn't propagated yet, with TTLs usually at 300–3600 seconds.

Common DKIM mistakes

  • 1024-bit key. It works: RFC 8301 requires receivers to accept keys from 1024 bits, but recommends signing with at least 2048.
  • Mismatched selector. Your Postfix config says selector=mail, but the DNS record is under s1._domainkey. The signature will fail: selectors must match exactly.
  • Spaces or line breaks in the key. The public key in DNS must be a continuous base64 string inside quotes. An extra newline makes the key invalid.
  • No key rotation plan. Few people think about this until something goes wrong. Rotate keys regularly, as the DKIM key rotation guide explains: create a new selector (s2), publish it in DNS, switch the server, then remove the old one. Zero downtime if you do it in that order.

Step 3. Configuring DMARC

DMARC combines SPF and DKIM into a single policy. Without it, receiving providers decide on their own what to do with failed messages. With it, you tell them.

Starting record

_dmarc.yourdomain.com.  IN  TXT  "v=DMARC1; p=none; rua=mailto:dmarc-reports@yourdomain.com; ruf=mailto:dmarc-forensic@yourdomain.com"

Breaking it down:

  • v=DMARC1: the only version.
  • p=none: take no action, just collect reports. Start here.
  • rua: address for aggregate reports (XML files, sent daily or more often).
  • ruf: address for failure reports (per-failure details). They contain message fragments, so many providers do not send them.
  • There is no pct=100 here, although older guides include it. RFC 9989, which replaced RFC 7489 in May 2026, dropped the tag, and 100 was always the default anyway.

The path to p=reject

In practice, this rollout takes 4–8 weeks. Don't rush it. One forgotten integration and your legitimate mail goes straight to trash.

The sequence:

  1. Weeks 1–2: p=none. Collect reports. Look at who is sending from your domain. You will almost always find services you forgot about: a CRM, a ticketing system, a survey tool.
  2. Weeks 3–4: p=quarantine; t=y. Under RFC 9989, t=y asks receivers not to apply the policy as written but one level below it: none for quarantine, quarantine for reject. Read the reports and watch complaint and bounce rates.
  3. Weeks 5–6: p=quarantine. The flag is gone and all failing messages go to spam. If two weeks of reports turn up none of your own senders, you can move on.
  4. Weeks 7–8: p=reject. Spoofed messages are now rejected at the SMTP level.

An earlier version of this plan used pct=25 in weeks 3 and 4, so a quarter of failing mail went to spam. Implementations of RFC 9989 ignore that tag and apply the whole policy, which is why the transition is now set with t=y.

Verification

dig TXT _dmarc.yourdomain.com +short

You should see a string starting with v=DMARC1. Empty response means either the record name is wrong, say the _dmarc. prefix is missing, or DNS hasn't updated yet.

Common DMARC mistakes

  • Jumping straight to p=reject. There is almost always a forgotten sending service, and the result is lost legitimate mail.
  • No rua address. DMARC without reports is like monitoring without alerts. Use a free parser: DMARC Analyzer, Postmark DMARC, or dmarcian's free tier.
  • Alignment mismatch. DMARC checks that the domain in From matches the domain in SPF (envelope-from) or DKIM (the d= tag). If your ESP uses its own domain in the envelope-from, SPF alignment fails. Fix it with custom DKIM (d=yourdomain.com) or a custom return-path subdomain.

Alignment: the detail that breaks everything

DMARC requires at least one protocol (SPF or DKIM) to both pass and align with the From header domain. Without alignment, DMARC fails even if SPF and DKIM individually pass.

Example. You send from team@yourdomain.com. Your ESP uses bounce-12345@esp.com as the envelope-from. SPF is checked against esp.com, but From is yourdomain.com. Different domains. SPF alignment fails.

The fix: configure DKIM with d=yourdomain.com, which most ESPs support via custom DKIM. DKIM alignment then passes and DMARC is satisfied. Alternatively, set up a custom return-path subdomain like mail.yourdomain.com, which makes SPF alignment pass too.

Forwarding breaks SPF, not DKIM

When a recipient forwards a message, it is sent on by their own mail server from its own IP, so the original domain's SPF fails. The DKIM signature stays valid as long as nobody changed the message. That is why DMARC needs only one of the two checks to pass, and why a DKIM signature with your own domain matters more than SPF. Mailing lists that append a footer break the signature too; for such intermediaries there is ARC (RFC 8617), which carries the results of checks made before the message was modified.

How to read DMARC reports

Aggregate reports arrive as a compressed XML file. For every IP that sent mail as your domain they list the message count, the SPF and DKIM results and the policy applied. The first weeks are about inventory: find every sender of your own and get it passing. XML is unpleasant to read by eye, so reports usually go to an analysis service. If that service is on another domain, it must confirm it accepts the reports with a DNS record, or nothing arrives. How to check that is covered in the DMARC checker.

Verifying everything together

After setup, send a test message to a Gmail account. Open it, click "Show original." In the headers you'll see:

Authentication-Results: mx.google.com;
    dkim=pass header.i=@yourdomain.com header.s=s1;
    spf=pass (google.com: domain of team@yourdomain.com designates 198.51.100.42 as permitted sender);
    dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=yourdomain.com

Three passes means everything works. If you see fail or softfail, go back to that specific step.

Diagnostic tools

  • mail-tester.com: send a message to the generated address, get a score from 0 to 10 with a breakdown of SPF, DKIM, and DMARC.
  • mxtoolbox.com: DNS record checks, blacklist lookup, SMTP diagnostics. You can also check each record here: SPF, DKIM, DMARC.
  • Google Postmaster Tools: if you send to Gmail, this shows domain and IP reputation, spam rates, and authentication errors.
  • dig / nslookup: quick checks from the terminal. No GUI, but instant results.

Full dig checklist:

# SPF
dig TXT yourdomain.com +short | grep spf

# DKIM (substitute your selector)
dig TXT s1._domainkey.yourdomain.com +short

# DMARC
dig TXT _dmarc.yourdomain.com +short

# MX (confirm the domain accepts mail at all)
dig MX yourdomain.com +short

What about subdomains

Your root domain's DMARC policy also covers subdomains that have no record of their own, and the sp= tag sets a separate policy for them. SPF is needed on every subdomain used in the message envelope. DKIM can sign with the root domain, which is enough under relaxed alignment, though a separate selector per subdomain is handier when several services send.

A typical setup for a mid-size company:

  • yourdomain.com: corporate mail (Google Workspace, Exchange)
  • mail.yourdomain.com: marketing campaigns (ESP)
  • notify.yourdomain.com: transactional notifications (Postmark, SES)

Each subdomain gets its own SPF record and its own DKIM selector. More work upfront, but problems with your marketing sends hit your transactional mail less. A password-reset email should never land in spam because a promo campaign picked up complaints.

Once all three records work and your DMARC policy is stricter than none, you can add a logo next to your messages with BIMI. The record is built in the BIMI generator.

SPF, DKIM, DMARC are the foundation

Without authentication, even a perfectly clean list won't save your deliverability. But authentication without a clean list is only half the job. Hard bounces, spam traps, and dead addresses damage domain reputation just as much as a missing DKIM record.

Records configured? Next step: make sure your list is clean. Upload your list to uChecker and within minutes you'll see invalid addresses, spam traps, and risky contacts. Download the results and clean before your next send.

SPF record setupDKIM configurationDMARC policyDNS TXT record emailemail server configuration

Mark Avrilov · Author

Published Updated