SPF record checker
Looks up a domain
A domain’s SPF record is the list of hosts it says are allowed to send mail using its name. Type a domain and you will see the record exactly as it is published, what each term in it does, and — the part a record cannot tell you about itself — how much of RFC 7208’s ten-lookup budget the whole evaluation spends, counted through every include: along the way.
This one is not a browser tool. Reading DNS needs a resolver and a browser does not have one, so the domain you type is sent to our server, which does the lookups and sends back the answer. We do not log the domain, there is no account and no cookie involved, and nothing else about you is part of the request.
Reading the answer
What the record is actually saying
An SPF record is one TXT record beginning v=spf1, followed by terms separated by spaces. A receiver reads them strictly left to right and stops at the first mechanism that matches the connecting IP address. The qualifier on that mechanism — + pass, - fail, ~ softfail,? neutral, with +assumed when none is written — is the answer for the whole record. Nothing after the match is looked at.
What it authorises is narrower than most people expect. SPF checks the envelope sender — the MAIL FROM address the sending server gives at the SMTP level, which ends up in Return-Path — and the HELO name. It says nothing about the From:header a person actually reads. Those two can be completely different addresses, and on their own SPF will not notice. Tying them together is DMARC’s job, not SPF’s.
The ten-lookup budget, and why it is counted across everything
RFC 7208 §4.6.4 allows an evaluation ten DNS-querying terms. Six kinds of term spend one each: include, a, mx, ptr, exists and redirect. The rest are free — ip4 and ip6 are literal address ranges, and all matches without asking anything.
The count is for the entire evaluation, not for one record. Every record reached through an include: keeps spending from the same ten, and so does everything those records include. A record with three terms in it can comfortably cost fourteen, and that is the number a receiver counts.
Going over is not a warning. The RFC requires the receiver to return PermError, and a PermError means the record produced no usable result at all — not a fail, not a pass. The domain is evaluated as though it had published nothing. Two properties make this the quietest failure in email: it happens at the receiver, which has no reason to tell you, and it is triggered by records inside your includes that your provider can change without telling you either. A record that worked for two years can cross the line on a morning nobody touched it.
This page walks the chain and counts the same way a receiver does, which is why the number it reports can be much larger than the record looks. Two different includes that both reach one shared record are not a loop and are not deduplicated — the RFC charges each include its own lookup and re-evaluates the record it names, so the shared one is paid for twice.
“At least” means the walk did not finish
Sometimes the count comes back as a lower bound rather than a total. There are three reasons, and the result says which applies: a record in the chain could not be read, a target was written as a macro so there is no single name to follow, or the budget ran out and there was no point reading further.
In all three cases the true cost is higher than the number shown, never lower. A count presented as a total when the walk stopped early would be the one mistake this page cannot afford, because the whole point of the number is the line it is close to.
What the ending decides, and the ending you get when you write none
The last mechanism in almost every record is all, which matches everything and therefore decides what happens to any sender the record did not already account for. -all states that such a sender is not authorised. ~allis RFC 7208’s explicit “in transition” qualifier: probably not authorised, accept it anyway and make a note. Both are working, ordinary records, and a great deal of legitimate mail is sent under ~all.
?all makes no statement at all, which leaves a receiver exactly where it would be with no record. +all — or a bare all, which means the same thing — authorises every host on the internet. That is weaker than publishing nothing, because a receiver reads it as a considered decision rather than an absence.
A record with no all and no redirect= does not simply end. RFC 7208 §4.7 supplies a default result of Neutral, so it behaves as though ?all had been written. The record is doing less than it looks like it is doing, which is the case worth spotting.
include: is not a nested record, and redirect= is not include:
An include:runs the named domain’s record as a separate question and uses only the answer: a pass over there is a match here, and anything else is simply not a match, so evaluation carries on with the next term. The included record’s own ending is discarded. A -allinside a record you include does not cause your mail to be rejected, which is the single most common misreading of the mechanism — RFC 7208 §5.2 says so directly.
redirect=is the opposite. It hands the whole question to another domain, ending and all, and the other record’s result becomes yours. It is also a modifier rather than a mechanism, so it is only consulted when no mechanism matched (§6.1). Publish a redirect= alongside an all and the redirect can never be reached, because all always matches first.
Terms that are worth a second look
ptr still parses and still works, and RFC 7208 §5.5 says in as many words that its use is strongly discouraged. It asks the receiver to do a reverse lookup on the connecting address and then forward lookups on whatever comes back, which is slow, spoofable at the reverse-DNS end, and a cost borne by everyone who receives your mail rather than by you.
Macros — %{d}, %{i}and the rest of §7 — are reported here and deliberately not expanded. Expanding one needs the connecting IP, the HELO name and the sender address of an actual delivery, and there is no delivery here. A guess at what a macro would become is worth less than saying that it is there.
A term the RFC does not define is not ignored by a receiver. An unrecognised mechanism is a syntax error, and a syntax error anywhere in the record is a PermError for the whole record — the same outcome as running out of lookups.
Two records is the same as no policy
RFC 7208 §4.5 is unambiguous: if more than one record at a name starts v=spf1, the result is PermError. Receivers do not merge them, do not pick the stricter one, and do not pick the first. This is easy to do by accident, because adding a second TXT record is the natural way to add a second sending service, and the DNS interface will accept it without complaint. Other TXT records at the same name — verification tokens, DMARC-unrelated strings — are not SPF and do not count.
What SPF cannot do for you
It does not survive plain forwarding. When a mailing list or a forwarding address relays a message without rewriting the envelope sender, the connecting IP is now the forwarder’s and the SPF check fails on mail that is perfectly legitimate. That is a known and accepted limitation of the mechanism, and it is why DMARC treats a DKIM signature as an independent way to pass.
It also does not sign anything, so it says nothing about whether a message was altered in transit, and a pass is not a statement that mail is wanted. A sender who owns a domain and publishes a correct record passes SPF while sending anything they like.
What this page cannot tell you
It reports a published record. It does not perform an evaluation, because an evaluation needs a connecting IP address, a HELO name and a MAIL FROM address, and nobody is delivering mail here. So it will not tell you whether a particular server would pass, and it does not check the separate §4.6.4 sub-limits on how many names an mx or ptr term may expand to, or the void-lookup limit.
It also reports what our resolver was told. A domain served differently to different networks, or changed in the last few minutes, can look different from here than it does from a receiver. Answers are cached for a few minutes so that a popular link does not turn into a flood of identical DNS queries; when a result came from that cache, it says so.
What a correct record does not protect you from
SPF, DKIM and DMARC between them stop someone forging mail fromyour domain. None of them does anything about the address itself — who has it, who they gave it to, and what arrives at it once a list changes hands.
Giving each sender a different address is the thing Maski does, and it means that when one of them leaks, you switch off that one address instead of rebuilding your mail setup around the problem.
One of the free email tools.