Email spoofing and DNS you never configured

Your SPF record exists, but does it actually work? The errors that silently switch it off

Having an SPF record feels like a solved problem. You published the TXT record, your mail flows, done. But SPF has a cruel property: a record can be present, look correct, and enforce nothing, because it's broken in a way the spec says receivers must treat as "permerror", a permanent error, at which point they ignore your SPF and fall back to "shrug, deliver it." Your record is there. It just isn't doing its job, and you'd never know from the fact that it exists.

These are the four ways SPF silently switches itself off. Each is a real RFC 7208 condition, and each leaves you as spoofable as having no record at all, while giving you the false comfort of a record that's technically published.

Two records is the same as a broken one

The SPF spec is blunt: a domain must publish exactly one v=spf1 record. Two is not "extra coverage", it's a permerror, and receivers discard both. This happens constantly: you add SendGrid's SPF as a second standalone record instead of merging it into your existing one, and now you have two v=spf1 TXT records and zero working SPF. The fix is to merge them into a single record with all the include: mechanisms in one line.

$ dig +short TXT yourdomain.com
dig +short TXT yourdomain.com
"v=spf1 include:_spf.google.com -all"
"v=spf1 include:sendgrid.net -all"
Two v=spf1 records = permerror. Receivers ignore both. You have no working SPF.
Each line looks fine alone. Together they're a permanent error, and your SPF enforces nothing.

More than ten lookups, and SPF gives up

SPF lets you include: other domains' records, which themselves include more, and so on. To stop this expanding forever, the spec caps the total at ten DNS lookups (counting include, a, mx, redirect, and friends recursively). Go over ten and it's a permerror, SPF ignored.

It's easy to blow past ten without trying. Each SaaS you add (_spf.google.com, sendgrid.net, a CRM, a help desk, a marketing tool) pulls in its own includes, and those nest. A record that started clean creeps over the limit as the business adds vendors, and the day it crosses ten, your SPF silently stops working for everyone. The fix is SPF "flattening", replacing nested includes with the IP ranges they resolve to, or trimming vendors you no longer send through, to get back under the cap.

Dead includes and void lookups: the slow rot

Two more permerror-class problems come from includes that no longer resolve. Void lookups, more than two mechanism targets that return NXDOMAIN or an empty answer, are flagged by the spec because they signal a record pointing at things that don't exist anymore. And the related case: an include: whose target publishes no SPF at all, a vendor you stopped using whose include now resolves to nothing, a decommissioned service, a typo'd domain. The include is dangling. It bloats your record, counts against your lookup limit, and signals rot.

; two records (permerror), and the second is bloated + dangling
yourdomain.com TXT "v=spf1 include:_spf.google.com -all"
yourdomain.com TXT "v=spf1 include:sendgrid.net
 include:old-crm-we-dropped.com include:typo-vendor.io
 include:mailtool.com include:helpdesk.com -all"
; > 10 nested lookups; old-crm/typo-vendor publish no SPF
One record, under ten lookups, no dead includes, ending in a hard -all.

Why this matters as much as missing SPF entirely

The whole point of SPF is to let receivers reject mail from servers you didn't authorize. A permerror means receivers can't evaluate your policy, so they don't, which leaves you exactly as spoofable as a domain with no SPF, the open-relay scenario where anyone can send as you. The danger is the false sense of security: a missing record is at least obviously missing, while a broken-but-present record reads as "handled" on every checklist until someone actually evaluates it. And because SPF underpins DMARC enforcement, a silently-failing SPF quietly undermines the whole email-authentication stack you thought you'd built.

Reading it from outside

SPF lives in public DNS, which is why an attacker can read it, and why a scanner can too, with no access to your DNS panel or mailbox. SurfaceCheckr reads your SPF record the way a receiving mail server does and evaluates it the way the spec requires: it flags more than one v=spf1 record, counts the recursive lookups against the ten-lookup cap, counts void lookups, and checks whether each include: target actually publishes an SPF record. So it catches the records that exist but enforce nothing, the failure mode a "do I have SPF?" glance always misses. It reads what's published and reasons about it; it can't send mail to prove the point, and won't. The next-door reads are getting SPF right in the first place and moving your DMARC off p=none so the failures actually get acted on.

Find it before someone else does.

Paste your domain. The grade and issue count are free, and you'll see in a couple of minutes exactly what's reachable from outside.