← Back to blog

SPF Record Setup: A Complete Guide to Configuring Sender Policy Framework

Step-by-step guide to creating, testing, and troubleshooting SPF DNS records. Covers all mechanisms (ip4, ip6, include, a, mx), qualifiers, the 10-lookup limit, and alignment with DMARC.

Updated October 21, 2026
SPF Record Setup: A Complete Guide to Configuring Sender Policy Framework

SPF Record Setup: A Complete Guide to Configuring Sender Policy Framework

Sender Policy Framework (SPF) is a DNS-based email authentication standard that lets domain owners publish a list of IP addresses and hostnames authorised to send mail on their behalf. When a receiving mail server gets a message, it looks up the SPF record for the sender's domain and checks whether the sending IP appears in that list. A pass result signals that the message is legitimate; a fail or softfail can trigger spam filtering or outright rejection.

SPF is one leg of the three-legged stool of email authentication. The other two are DKIM (which adds a cryptographic signature to the message headers) and DMARC (which ties SPF and DKIM together into a policy and tells receivers what to do with failures). You need all three for reliable inbox delivery, but SPF is usually the first you set up because it requires no cryptographic key management — just a DNS TXT record.

How SPF Works

When you send an email, the receiving server looks at the MAIL FROM address (also called the envelope sender or return-path) to find the domain to check. It then fetches the TXT record at that domain and evaluates the record against the connecting IP address.

The evaluation walks through the record's mechanisms left to right, testing each one against the sending IP. The first mechanism that matches determines the result. If nothing matches, the default result is neutral (effectively no opinion).

Anatomy of an SPF Record

An SPF record is a DNS TXT record at your domain (or subdomain). A typical record looks like:

v=spf1 ip4:203.0.113.0/24 include:mail.rovela.dev include:_spf.google.com ~all

Every record starts with v=spf1. After that come one or more mechanisms and, at the end, a catch-all mechanism.

Mechanisms

ip4 and ip6 are the most straightforward. They match a specific IP address or CIDR range:

ip4:203.0.113.5
ip4:203.0.113.0/24
ip6:2001:db8::/32

Use these for static IPs that your own servers, VPNs, or dedicated relays use to send mail.

include delegates to another domain's SPF record. When the evaluator hits an include, it fetches that domain's SPF record and evaluates it. If the IP matches anything in the included record, the include passes. This is how transactional email providers (like Rovela) let you authorise their sending infrastructure without listing every IP:

include:mail.rovela.dev

a matches the A (and AAAA) records of the current domain or a specified domain. Useful if you send from the same server that hosts your website:

a
a:mail.example.com

mx matches the mail exchange servers listed in your domain's MX records. This is only correct when your inbound and outbound mail servers are the same machines. Many organisations receive mail at Google Workspace or Microsoft 365 while sending through a separate platform; in that setup mx is wrong and silently authorises the wrong hosts.

mx
mx:example.com

exists performs an A-record lookup for a dynamic hostname and passes if any A record is returned. Advanced use case, rarely needed — it shows up in setups that encode the sending source into a subdomain and branch on it.

ptr performs a reverse DNS lookup. Avoid it — it is slow, unreliable, and deprecated by RFC 7208.

Qualifiers

Each mechanism can be prefixed with a qualifier that determines what result to return when the mechanism matches:

QualifierResultMeaning
+PassAuthorised sender (default, usually omitted)
-FailExplicitly not authorised; receivers should reject
~SoftFailProbably not authorised; receivers should accept but mark
?NeutralNo policy statement either way

The catch-all at the end of your record uses one of these qualifiers to cover all IPs that did not match any mechanism:

-all   # hard fail: reject mail from unlisted IPs
~all   # soft fail: accept but mark as suspect
?all   # neutral: no statement

Start with ~all (softfail) while you are auditing your sending sources. Move to -all once you are confident every legitimate sending source is in the record.

The 10-Lookup Limit

This is the most common cause of SPF failures in production. RFC 7208 limits the number of DNS lookups that an SPF evaluation may trigger to ten. Each include, a, mx, and exists mechanism counts as a lookup, as do nested includes inside the included records. Exceeding ten lookups produces a permerror result, which most receivers treat as a fail.

Look at a record that is easy to underestimate:

v=spf1 include:mailprovider1.com include:mailprovider2.com include:mailprovider3.com include:crm.example.com include:support.example.com ~all

…looks like five lookups, but each included domain's record can itself contain several include statements. A single large ESP's SPF record can consume four or five lookups on its own. The failure mode in practice is not "I added too many providers" — it is "I added three, and one of them quietly grew its internal dependencies."

To stay under the limit:

  1. Audit before adding. Read the current record with dig TXT yourdomain.com +short, then dig each included domain and expand the nesting by hand. An online SPF checker will also report the total lookup count directly.
  2. Use ip4/ip6 directly for servers whose IPs are stable. An IP mechanism costs zero lookups, so your own servers and fixed egress addresses should be CIDR blocks, not includes.
  3. Flatten includes if needed — replace include:provider.com with the actual IPs from their record. The cost is that the provider can change IPs without telling you, so this suits your own ranges and not cloud platforms.
  4. Use subdomains when you send from several very different systems. Keep transactional mail in send.example.com and marketing mail in news.example.com, each with their own SPF records, so their lookup budgets don't compete. This is the least fragile option.
  5. Re-check periodically. You don't control anyone else's SPF record, and a provider adding an include once or twice a year is normal. Put it in the quarterly audit rather than waiting for the bounce rate to move.

Setting Up SPF Step by Step

1. Audit your sending sources

Before touching DNS, list every system that sends mail using your domain:

  • Your own mail servers (inbound MX servers often relay outbound too)
  • Transactional email APIs (Rovela, SendGrid, Postmark, etc.)
  • Marketing email platforms (Mailchimp, HubSpot, etc.)
  • CRM and support tools
  • Internal applications (password resets, notifications, reports)
  • Office 365 or Google Workspace, if your team uses them

2. Get the SPF includes from each provider

Every reputable provider publishes their SPF record. Rovela's is include:mail.rovela.dev. For Google Workspace it is include:_spf.google.com. Check each provider's documentation.

3. Write the record

Combine everything into one TXT record at the root of your domain. You can only have one SPF record per domain (one TXT record that begins with v=spf1). Multiple SPF records cause a permerror.

v=spf1 ip4:203.0.113.0/24 include:mail.rovela.dev include:_spf.google.com ~all

4. Add it to DNS

Add a TXT record at @ (or your domain root) with the value above. TTL of 3600 (one hour) is typical. If you are migrating from an existing record, lower the TTL to 300 a day before you change it so the update propagates quickly.

5. Test before going to production

Use dig TXT yourdomain.com +short to confirm the record was picked up. Then use check-auth2@verifier.port25.com — send any email there and you will receive an automated reply showing the SPF result, the DKIM result, and the DMARC result.

Online tools like MXToolbox's SPF checker let you test against a specific IP without actually sending a message.

6. Monitor in DMARC reports

Once you have DMARC reporting set up (even p=none), you will receive aggregate reports showing which IPs are sending mail that claims to be from your domain and whether they are passing SPF. This is how you discover shadow senders you forgot to include.

Common Problems and Fixes

Multiple SPF records. Remove all but one. Combine any authorised sources into the single remaining record.

SPF passes but DMARC fails. DMARC requires the SPF-authenticated domain to align with the From: header domain. SPF checks the envelope sender (return-path), not the From header. If your ESP uses their own return-path domain, SPF alignment will fail; you need DKIM alignment instead. This is normal for most cloud email providers.

Forwarded mail failing SPF. Email forwarding rewrites the routing but usually keeps the original envelope sender, so the forwarding server's IP fails your SPF check. SPF was designed before forwarding was common. DMARC handles this via DKIM: as long as the DKIM signature passes, DMARC will pass even if SPF fails. Enable DKIM to protect forwarded mail.

Softfail landing in spam. ISPs are getting more aggressive about ~all. If your record is complete and stable, switch to -all. The stricter posture paradoxically improves inbox placement because it signals confidence.

Combining SPF with DKIM and DMARC

SPF alone is not enough. It only authenticates the envelope sender, and it breaks on forwarding. The full stack:

  1. SPF — authorises sending IPs for your domain
  2. DKIM — adds a cryptographic signature that survives forwarding
  3. DMARC — uses SPF and DKIM results to enforce a policy and send aggregate reports

A typical production setup for Rovela customers:

; SPF
yourdomain.com.  IN TXT  "v=spf1 include:mail.rovela.dev ~all"

; DKIM (the key is created in the Rovela dashboard; Rovela handles key rotation)
rovela._domainkey.yourdomain.com.  IN TXT  "v=DKIM1; k=rsa; p=<public key>"

; DMARC
_dmarc.yourdomain.com.  IN TXT  "v=DMARC1; p=quarantine; rua=mailto:dmarc@yourdomain.com; pct=100"

Rovela's one-click DNS setup handles SPF and DKIM in a single step for Cloudflare and DNSPod customers. Once DNS propagates, your outbound mail will pass all three checks.

Subdomains

SPF does not automatically apply to subdomains. If you send from notifications.yourdomain.com, you need a separate SPF record at that subdomain.

The more important direction is the reverse: a subdomain that will never send mail should carry an explicit v=spf1 -all. With no SPF record at all, anyone can spoof that subdomain with your brand on it, and receivers generally treat "no SPF" as no objection rather than a reason to reject. The record costs nothing:

; subdomains that never send
yourdomain.com.       IN TXT  "v=spf1 -all"
*.yourdomain.com.     IN TXT  "v=spf1 -all"

Be careful not to apply -all to a root domain that does send mail — that cuts off every legitimate sender at once.

Troubleshooting Order

When SPF misbehaves, work through this order instead of editing the record on instinct:

  1. Confirm which record is being read. dig TXT yourdomain.com +short. If more than one record begins with v=spf1, delete all but one — nothing else matters until that's fixed.
  2. Confirm which domain the receiver checked. SPF evaluates MAIL FROM, not the From: header. Your server logs show the real envelope sender.
  3. Count the lookups. Use a tool; don't eyeball it.
  4. Confirm the sending IP is actually listed. Compare the real egress IP against the flattened list. An unexpected NAT hop is a common surprise.
  5. Confirm alignment. SPF passing with DMARC failing is almost always an alignment problem rather than an SPF problem — those are two different checks.

Maintenance

An SPF record is living configuration, not a one-time setting:

  • Update it when you add a service. Every SaaS tool that sends on your behalf — CRM, helpdesk, analytics, notifications — belongs in the record the same day. A missing include doesn't raise an error; it just starts losing that mail.
  • Audit quarterly. Check that every include still resolves, that the IP blocks are still yours, and that the lookup count is under ten. When a provider retires an old domain, your include turns into a permerror and nothing tells you.
  • Clean up retired services. An include left behind by a tool you stopped using wastes lookup budget and, worse, keeps a sending authorisation permanently open. Either reason alone justifies removing it.
  • Lower the TTL before a big change. Drop from 3600 to 300 so a mistake can be rolled back quickly.
  • Watch it alongside DKIM. Maintaining SPF while letting DKIM drift shows up first as a slow decline in DMARC pass rates — visible in aggregate reports well before it shows up in bounce rates.