SPF Lookup Counter
Count the DNS lookups your SPF record needs, and see which include costs how many. Free and open source (MIT).
npx spf-lookup-counter example.com
Why the number matters
SPF allows at most 10 DNS lookups and 2 void lookups per check (RFC 7208 §4.6.4). Go over either limit and receiving mail servers return permerror. SPF then fails for all your mail, and DMARC can no longer pass on SPF.
It usually happens without anyone changing your record: a provider you include: adds another nested include, and your total goes from 9 to 11.
What you get
$ npx spf-lookup-counter primedevforce.com
primedevforce.com
v=spf1 include:secureserver.net -all
DNS lookups: 3 of 10 allowed
Void lookups: 0 of 2 allowed
Term Lookups
include:secureserver.net 3
include:spf-0.secureserver.net 2
include:spf.protection.outlook.com 1
- Exact counts, not just "more than 10", so you know how far over you are.
- A tree of every include with its cost, so you know which one to remove or replace.
- Void lookups, loops,
+all, missing or duplicate records, and terms that never take effect. - Honest when it can't finish: if a lookup fails, the result says could not complete and gives a lower bound. It never reports a pass it couldn't check.
- Private by default: uses your own DNS resolver. No dependencies.
Options
| Option | What it does |
|---|---|
--json | Print the full result as JSON |
--server <ip> | Use this DNS server instead of the system one |
--doh [url] | Use DNS-over-HTTPS (Cloudflare by default). The names you look up are sent to that provider |
Exit code 0 means no errors, 1 means errors found and 2 means it could not complete. That makes it easy to run in CI after a DNS change.
Fixing a record that is over the limit
- Look at the Lookups column. Start with the biggest numbers.
- Remove includes for services you no longer send mail through.
- Replace
aandmxwithip4:orip6:ranges if your own servers rarely change. IP ranges cost no lookups. - Move a sending service to a subdomain with its own SPF record, if the provider supports it.
Use it as a library
import { countSpfLookups } from "spf-lookup-counter";
const r = await countSpfLookups("example.com");
console.log(r.lookups, "of", r.lookupLimit);
Full details of what is and isn't counted are in the README.