An include target does not exist or publishes no SPF record
If an include in your SPF record points at a name that publishes no SPF record, or at a name that does not exist, SPF returns permerror as soon as evaluation reaches that include. Terms after it are never evaluated, so the senders they list cannot get an SPF pass. A server matched by an earlier term still gets that term's result.
Measured 2026-09-08: 4 of 320 audited domains (1.25%) named an include target that publishes no SPF record. These are domains someone had a reason to check, so this is an upper bound and not an internet-wide rate — method, window and exclusions in SPF Observatory 2026.
What was observed
An include: in your record names a host, and a TXT lookup on that host returns nothing beginning v=spf1.
What causes it
These are protocol and measurement causes only. We do not speculate about what a receiver did with the result.
- A typo in the include target.
- The vendor changed its SPF hostname and the old one stopped publishing.
- An inbound hostname was used where the vendor's SPF include belongs —
mail.vendor.comrather thanspf.vendor.com. - The vendor was retired and its zone no longer answers.
When the include target does not exist
The result is the same when the name in the include does not exist at all. RFC 7208, section 4.3:
... or if the DNS lookup returns "Name Error" (RCODE 3, also known as "NXDOMAIN" [RFC2308]), check_host() immediately returns the result "none".
Section 5.2 then turns that "none" into permerror for the include, the same as for a target with no SPF record.
Order matters
Take this record:
v=spf1 include:_spf.google.com include:spf.missing.example ~all
Servers listed in include:_spf.google.com match first and pass. Mail from any other server reaches include:spf.missing.example and gets permerror. If the broken include is the first term, every server gets permerror.
How to verify it yourself
- See what the include actually resolves to
dig +short TXT _spf.google.com - An empty answer is the fault; a record starting v=spf1 is fine
dig +short TXT spf.example-vendor.com
Run dig TXT on each include target. A target that does not exist shows status NXDOMAIN in the header. A target with no SPF record returns no line that contains v=spf1.
Check this record Reads the live record and counts every DNS lookup it costs.
The safe fix, and what it can break
Correct the target, or remove it if you no longer send through that vendor. Get the current include from the vendor's own documentation rather than from an older copy of your record — that is where the stale value came from.
What can break: Removing an include removes every sender it covered. If you are unsure whether the vendor is still in use, check DMARC reports for its sources before deleting rather than after.
Examples
v=spf1 include:spf.retired-vendor.example ~allv=spf1 include:_spf.google.com include:spf.protection.outlook.com include:sendgrid.net ~allWhat the standard says
RFC 7208 §5.2: “The "include" mechanism triggers a recursive evaluation of check_host()”
What does “include target has no SPF record” mean and why is it PermError?
The include triggers a recursive evaluation (RFC 7208 §5.2). If the target publishes no record, that recursion cannot reach a result, and the parent evaluation returns permerror rather than ignoring the line.
What are the common causes?
A typo; a vendor that changed its SPF hostname; an inbound mail hostname used where the vendor's SPF include belongs; or a vendor you stopped using whose zone no longer answers.
How do I see what an include resolves to?
dig +short TXT <target>. An empty answer is the fault. Note the TXT: without it dig returns the CNAME or A record and tells you nothing about SPF.
Where do I find the correct include for the major providers?
Each vendor's own current documentation — Google, Microsoft, SendGrid, Mailchimp, Brevo and HubSpot all publish theirs. We deliberately do not reprint the values here: a stale include copied from a third-party page is how this fault appears in the first place.
How is this different from a lookup timeout?
A timeout is temperror: the answer could not be obtained right now, and a retry may succeed. An empty answer is permerror: the record was obtained and it says nothing. Retrying will not fix it.
How do I fix it and re-check?
Correct or remove the target, wait for the previous answer's TTL to expire, then re-run the dig above and the checker linked on this page.
What we do not claim
We report what your DNS publishes and what an evaluator would return from it. We do not state what any mailbox provider will do with that result: those decisions are theirs, they are not published, and we cannot measure them from here.
Reviewed by Venkat Nookala, last reviewed 2026-10-18.