On Page Navigation
An SPF record is one line of text in your DNS, and it does one job: it lists the servers allowed to send mail using your domain. If you are reading this, something has probably already gone wrong. A scanner flagged the domain, a client mentioned that your invoices land in junk, or you added a sending tool and half your mail stopped arriving. The syntax fits on a single line and is strict enough that one missing character changes the answer. Here is what each part means, and where it usually goes wrong.
Every SPF record is a DNS TXT record on the domain that sends the mail, and it always starts with v=spf1. After that comes a list of mechanisms, each describing a set of servers, read strictly left to right. The first mechanism that matches the sending server decides the result, and nothing after it is evaluated.
A working record for a business on Google Workspace with one marketing tool looks like v=spf1 include:_spf.google.com include:servers.example-esp.com ~all. Three mechanisms in order, then a catch-all. That is the whole grammar. Everything below is detail about those parts.
The record is published as TXT on the domain itself, not on a hostname like _spf. Pasting it into whatever hostname the DNS control panel suggested, rather than the root of the domain, is a common first mistake, and it means nothing you write has any effect at all.
include is the one you will use most. It says: go and read that other domain's SPF record, and if it authorises this server, so do I. That is how you delegate to a mailbox provider such as Google Workspace or Zoho Mail without needing to know IP addresses that change without telling you. Read the wording carefully, because an include does not import the other record's catch-all and therefore never rejects anything on its own.
ip4 and ip6 name addresses or ranges directly. They are the only mechanisms that cost you nothing, because they require no further DNS query. If you control a server with a fixed address, naming it outright beats every other option.
a authorises whatever the domain's A record points at, and mx authorises the servers in its MX records. Both read well and both are usually wrong. Your web server and your inbound mail servers are rarely the machines sending outbound mail. The mx habit in particular is inherited from an era when one box did both jobs.
ptr still appears in records copied from old tutorials. Do not use it. It is slow, unreliable, and the specification itself tells receivers not to rely on it.
Every mechanism can carry a qualifier: plus for pass, minus for fail, tilde for softfail, question mark for neutral. Leave it off and you get pass. In practice the only qualifier most people ever write is the one on the final all, and it is the most argued-about character in email.
-all says anything not listed above is not us, reject it. ~all says anything not listed above is probably not us, accept it and mark it. Neither is universally right. Hard fail is stronger and unforgiving of the sending tool you forgot about, which in most businesses exists. Softfail is safer while you are still finding your sending sources, and weaker once you have found them all.
The honest sequence is to start on softfail, spend a month reading DMARC reports until the list of senders stops surprising you, then tighten. Going straight to hard fail on a domain nobody has audited is how a business discovers that its accounting system has been mailing statements from an address no one remembered setting up.
A domain may publish exactly one SPF record. If a receiver finds two TXT records beginning v=spf1, the result is a permanent error, and a permanent error is treated worse than having no record at all. This is the most common defect we find on domains that more than one person has touched.
It happens because a second record feels like the natural way to add a sender. You already have one for your mailbox provider, you sign up for a helpdesk, their setup page says add a TXT record, so you add it. Both records are individually correct. Together they are broken. The fix is always to merge the mechanisms into one line, never to publish another.
Length is the related trap. A single TXT string cannot exceed 255 characters, so a longer record has to be published as several quoted strings that the receiver joins back together. Most DNS hosts handle that correctly now. Some older registrar control panels truncate instead, which produces a record that looks right in the panel and is invalid on the wire.
Before writing a record, list the systems that send mail using your domain. The list is always longer than expected. The mailbox provider is obvious and so is the marketing platform. What gets missed is the application sending receipts and password resets, the helpdesk replying to tickets, the accounting system mailing invoices, and the website itself.
A WordPress site sends mail whether or not anyone configured it to: form notifications, admin alerts, order confirmations. If that mail leaves through the host's default PHP mailer rather than a real sending service, it originates from an address range no SPF record will ever list, and it fails quietly.
Routing site mail through a proper sending service fixes that and gives you one place to look when delivery goes wrong. Our own Email Delivery for Cloudflare plugin covers that gap on Cloudflare-hosted domains, and any reputable relay does the same job.
Most SPF problems are not typing errors. The record is syntactically fine and the result is still wrong, because SPF has a handful of rules that are easy to satisfy on the day you write the record and easy to violate six months later without touching it.
This is the failure that catches everybody eventually. When a receiver evaluates your record, every mechanism that needs a DNS query counts against a budget of ten. Include, a, mx, ptr, exists and the redirect modifier all count. The ip4, ip6 and all mechanisms do not.
The budget is not ten includes. It is ten lookups in total, counted recursively. Include a provider whose own record includes three more and you have spent four. Exceed the budget and evaluation stops with a permanent error, which means your record authorises nothing at all. Every server you carefully listed stops passing at the same moment.
There is a second, quieter limit. No more than two of those lookups may come back empty. Two void lookups, usually from an include pointing at a domain that no longer publishes a record, and the whole evaluation fails the same way. That is how a record which worked for two years breaks on a Tuesday, because a vendor you stopped using retired their DNS entry. Both limits are set out in section 4.6.4 of RFC 7208, which is worth reading once if this is yours to own.
The symptom is characteristic and easy to misread. Mail is fine from some senders and fails from others, or was fine and now is not, with nothing having changed at your end. The cause is usually a third party adding an include to their own record. Your email marketing platform can push you over the limit without ever mentioning it.
Open the headers of a message that arrived. Every major receiver writes an Authentication-Results header, and its SPF component reads pass, fail, softfail, neutral, none, permerror or temperror. Those words mean specific things and they point in different directions.
Permerror is a syntax or limit problem in your own record, so the work is on your side. Fail means the record is correct and the sending server is not on it, so either it is not you or you have missed a sender. Softfail is the same finding on a record that ends in a tilde rather than a minus. None means no record was found at all, which on a subdomain usually means precisely that.
A record on the root domain says nothing about mail.example.com or notifications.example.com. Every subdomain that sends needs its own record. This surprises people because DMARC does apply to subdomains by default, so assuming the two behave alike is a reasonable guess. It is the wrong one.
The practical consequence is a business that tightens its main domain, considers the job finished, and carries on sending unauthenticated mail from the subdomain its application uses. Check every hostname you actually send from. The same logic is why cold outreach belongs on its own domain with its own record, since separating the reputation only works if the DNS is separate too.
When a recipient forwards your message, the forwarding server relays it using its own address, which is not on your record, so SPF fails. Nothing is wrong with your configuration and there is nothing you can do about it from your end. Mailing lists produce the same result for the same reason.
That is the strongest argument against relying on SPF alone. A DKIM signature travels with the message and survives forwarding, so a forwarded message can still align for DMARC after SPF has failed. A domain publishing a hard fail with no DKIM signature is turning every forwarded message it sends into a coin flip.
The usual answer to the lookup limit is flattening: replace the include mechanisms with the address ranges they currently resolve to, taking the lookup count to zero. It works, and it is widely sold as a service.
It also converts a record that maintains itself into one that does not. The whole reason include exists is that providers change their sending addresses, and when they do, your flattened record is wrong and nothing tells you. Flattening is therefore not a fix, it is a subscription to a recurring task. Reach for it when you genuinely cannot get under ten. Remove senders you no longer use first, which costs nothing and is usually enough.
If you send from one mailbox provider and nothing else, most of this is over-engineering. Publish the provider's include, end the record in softfail, and get on with your day. The complexity here scales with the number of systems sending as you, and a business with one system does not have a project on its hands.
Equally, if you have inherited a domain carrying a decade of DNS nobody can explain, do not begin by editing the SPF record. Begin by finding out what is sending. Changing authentication before you know what is being authenticated is how people take their own invoices offline for two weeks.
Writing the record is twenty minutes. Knowing what belongs in it takes longer, and keeping it correct as tools arrive and leave is the part nobody budgets for. Most of the broken records we look at were correct on the day they were written.
A checklist that holds up: one record and only one, comfortably under ten lookups, every sending system accounted for, softfail until the sender list has stopped surprising you, DKIM published alongside it, and DMARC reporting switched on so the domain tells you when something changes. Review it whenever a tool is added or removed, because that is the only trigger that matters.
If you would rather that lived with somebody else, it is the substance of what managed business email covers: records set up correctly, sending sources kept inventoried, and changes made before your recipients notice them.
Authentication is also only the first layer. Once the records are right and mail still lands in junk, the wider deliverability picture takes over: sending reputation, message content, and how much you send at once.