[ Servers & DevOps  /  6 min read ]

SPF, DKIM and DMARC setup: a practical guide with real records

[ Short answer ]

To set up SPF, DKIM and DMARC, publish one SPF TXT record listing every service that sends mail for your domain, enable DKIM signing in each of those services and publish their keys, then add a DMARC record at _dmarc starting with p=none. Read the aggregate reports, fix failures, then move to quarantine and reject.

A correct SPF, DKIM and DMARC setup comes down to three DNS records: one SPF record listing every service allowed to send as your domain, a DKIM key for each of those services so messages are cryptographically signed, and a DMARC record that tells receivers what to do when both checks fail. If your emails are going to spam, or bouncing since Google and Yahoo tightened their sender rules, one of these three is usually missing or broken. Below are the real records I publish for Google Workspace and Microsoft 365, the SPF lookup limit that silently breaks setups, and the DMARC rollout I use so nothing legitimate gets blocked.

Why your emails are going to spam

Receivers such as Gmail, Yahoo and Outlook ask two questions about every message: is this sender really who they claim to be, and do recipients want this mail? SPF, DKIM and DMARC answer the first question. Without them, your mail looks exactly like the spoofed mail criminals send in your name, and it gets treated that way.

Since February 2024, Google and Yahoo have enforced published sender requirements. Every sender needs SPF or DKIM. Bulk senders, which Google defines as anyone sending close to 5,000 or more messages a day to personal Gmail accounts, need SPF, DKIM and a DMARC record (at minimum p=none), alignment with the From domain, one-click unsubscribe for marketing mail, and a spam complaint rate kept below 0.3% in Postmaster Tools. Microsoft announced similar rules for Outlook.com consumer mailboxes in 2025. Even if you send far less than that, meeting the bulk-sender bar is the simplest way to stay out of the spam folder.

Step 1: publish a single SPF record

SPF is a TXT record at the root of your domain listing the servers allowed to send mail for it. The rule people break most often: there must be exactly one record starting with v=spf1. Adding a second one for a new tool causes a permerror, and SPF fails for everything.

SPF for Google Workspace

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

SPF for Microsoft 365

example.com.  TXT  "v=spf1 include:spf.protection.outlook.com -all"

Adding other senders

Your newsletter platform, CRM, helpdesk and web server may all send as your domain. Each gets added to the same record, not a new one:

example.com.  TXT  "v=spf1 include:_spf.google.com include:sendgrid.net include:mailgun.org ip4:203.0.113.10 ~all"

Use the include value each provider documents; do not guess it. Many marketing platforms send from their own domain by default and ask you to set up a custom return-path subdomain instead, in which case they do not belong in your root SPF record at all.

The SPF 10-lookup limit (and how to stay under it)

RFC 7208 caps SPF evaluation at 10 DNS lookups. Every include, a, mx, exists, redirect and ptr costs one, and so does every nested include inside those. ip4, ip6 and all are free. Go over 10 and the result is a permerror, which DMARC treats as a fail. The record still looks fine in your DNS panel, which is why this goes unnoticed for months.

Google's include costs several lookups on its own because it nests other includes, so a record with Google plus four or five marketing tools can easily hit the limit. To count lookups, recursively resolve each include:

dig +short TXT example.com | grep spf1
dig +short TXT _spf.google.com
dig +short TXT spf.protection.outlook.com

Ways to get back under 10, in the order I prefer them:

  • Remove services you no longer use. Old includes linger for years.
  • Drop a and mx if those hosts do not send mail; they are often copied in from templates.
  • Move bulk and transactional mail to a subdomain such as mail.example.com with its own SPF record and its own 10-lookup budget.
  • Replace an include with ip4 ranges only for your own servers, whose IPs you control. Flattening a third party's include breaks the day they change IPs.

Step 2: turn on DKIM signing

DKIM adds a signature to each message that receivers verify against a public key in your DNS. Unlike SPF, it survives forwarding, which makes it the more reliable half of DMARC. Each sending service needs its own DKIM key, published under its own selector.

DKIM record for Google Workspace

In the Admin console go to Apps → Google Workspace → Gmail → Authenticate email, generate a 2048-bit key, and publish it as a TXT record at the selector Google shows, which is google by default. Only after the record resolves do you click Start authentication.

google._domainkey.example.com.  TXT  "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA..."

A 2048-bit key is longer than the 255-character limit for a single TXT string. Most DNS panels, including Cloudflare's (if your DNS is there, my Cloudflare setup service covers these records too), split it automatically; some older ones need you to paste it as several quoted strings.

DKIM for Microsoft 365

Microsoft 365 uses two CNAME records that point at keys Microsoft hosts and rotates for you. Open the DKIM page in the Microsoft Defender portal, select your domain, and copy the exact two CNAME targets it shows. The format has changed over the years, so always copy them from the portal rather than from an old guide. Once both CNAMEs resolve, enable signing on the same page.

selector1._domainkey.example.com.  CNAME  (target shown in the Defender portal)
selector2._domainkey.example.com.  CNAME  (target shown in the Defender portal)

Step 3: a DMARC record example and a safe rollout

DMARC passes when SPF or DKIM passes and the domain that passed aligns with the domain in the visible From address. That alignment is what stops someone passing SPF with their own domain while showing yours to the recipient. The record goes at _dmarc:

_dmarc.example.com.  TXT  "v=DMARC1; p=none; rua=mailto:dmarc-reports@example.com; fo=1"

Never start at p=reject. Almost every organization has a sender nobody remembered: an invoicing tool, a website contact form, a printer that emails scans. My rollout looks like this:

StageRecord policyHow longWhat you are doing
1. Monitorp=none2–4 weeksCollecting reports, finding every legitimate sender
2. Partial quarantinep=quarantine; pct=251–2 weeksA quarter of failing mail goes to spam; watch for complaints
3. Quarantinep=quarantine2–4 weeksAll failing mail goes to spam
4. Rejectp=rejectPermanentSpoofed mail is refused outright

Only move to the next stage when the reports show all your legitimate sources passing. If you have subdomains that never send email, add sp=reject once you reach the end, and publish v=spf1 -all on domains that send no mail at all, so they cannot be spoofed either.

How to read DMARC aggregate reports

The rua address receives aggregate reports, usually daily, from Google, Yahoo, Microsoft and others. They arrive as zipped XML. Each record element tells you one sending IP, how many messages it sent, and how they fared:

<record>
  <row>
    <source_ip>198.51.100.25</source_ip>
    <count>412</count>
    <policy_evaluated>
      <disposition>none</disposition>
      <dkim>fail</dkim>
      <spf>pass</spf>
    </policy_evaluated>
  </row>
  <identifiers><header_from>example.com</header_from></identifiers>
</record>

What I look for: any IP with a high count and a DMARC fail that belongs to a service you use. That is a legitimate sender you still need to add to SPF or configure DKIM for. Low-volume failures from IPs you do not recognize are usually spoofing, and they are exactly what the policy is meant to block. Reading raw XML gets tedious fast, so use a DMARC report parser once volumes grow; a dedicated mailbox or subdomain for reports keeps them out of your inbox.

Verify the whole setup

Send a message to a Gmail account, open it, and choose Show original. You want to see SPF: PASS, DKIM: PASS and DMARC: PASS, all against your own domain. Repeat it for each system that sends mail, not just your mailbox, because the contact form and the newsletter are usually the ones failing. A web server sending mail directly through PHP mail() is the worst offender; I route it through an authenticated SMTP relay as part of server setup and configuration.

None of this is difficult, but the records live in DNS alongside everything else, and one typo can take down mail delivery. If you want it done carefully and documented, including cleaning up old records and moving DMARC all the way to reject, that is standard work in my DNS management service. If you are also moving hosts, keep your MX and authentication records intact during the cutover, as described in my website migration checklist. Small fixes are billed at $20/hour, and a full email authentication rollout gets a fixed price agreed in writing through DNS and email record management.

Frequently asked questions

Do I need all three of SPF, DKIM and DMARC?

Yes, in practice. Google and Yahoo require bulk senders to have all three, and even small senders get better inbox placement with them. SPF alone breaks on forwarding, DKIM alone does not tell receivers what to do with failures, and DMARC depends on at least one of the other two passing and aligning.

Can I have two SPF records?

No. A domain must have exactly one TXT record starting with v=spf1. Two records cause a permerror and many receivers then treat SPF as failed. Merge all the includes into a single record instead.

What is the difference between ~all and -all?

~all is a softfail: mail from unlisted servers is accepted but marked suspicious. -all is a hard fail. Once DMARC is enforcing, receivers act on the DMARC policy rather than the SPF qualifier, so the difference matters less than people think. ~all is a safe default while you are still discovering senders.

Why are my emails still going to spam with SPF, DKIM and DMARC passing?

Authentication proves who sent the message, not that recipients want it. Spam complaints, a new domain with no sending history, a shared IP with a poor reputation, missing unsubscribe links and spammy content all still count. Check Google Postmaster Tools for your domain's spam rate and reputation.

[ Want it done for you? ]

DNS & Email Deliverability

DNS migrations, SPF, DKIM and DMARC, and email out of spam. Hourly work is $20/hour; defined projects get a fixed price in writing.

See the service

[ Let's talk ]

Broken, slow, or not built yet?

Describe it in a few lines and you'll get a real reply from the person who'd do the work — same working day, no discovery call required.