On this page

Email & domains

SPF record checker

API · Pro

Coverage: Works with domains from any country. We read the record as receiving servers do (RFC 7208): its mechanisms, how it ends, every include and redirect up to 30 lookups, and its count of DNS lookups against the limit of 10.

Open tool
On this page

Purpose

Check a domain’s SPF record: which servers may send email in its name, what happens to all the others (“-all”, “~all”, “+all”), how many DNS lookups it needs against the limit of 10 and every include.

Requirements

Anyone can read these guides, no account needed. Some tools require Pro, as indicated in each guide.

SPF is the DNS record where a domain lists the servers allowed to send its email. Without it, or with one that’s broken or too open, it’s easier to send fake emails in that domain’s name. Type a domain, an email address or a link and we’ll read its SPF and explain it.

How to use it

  1. Type the domain you want to check, or paste an email address or a link: we only use its domain.

  2. Press “Check SPF”. We read the SPF record and follow each include, as a receiving server would.

  3. Look at how the record ends and at the lookup count: what you want to see is “-all” or “~all” and 10 lookups or fewer.

Synthetic example

Note

Invented example, not a real lookup. Do not call or open its links.

Synthetic example
v=spf1 include:_spf.example.com ~all

Interpret the result

This domain has no SPF: It doesn’t say which servers may send its email, which makes it easier to impersonate. If it’s your domain, publish an SPF record.

The SPF record has errors: Receiving servers can’t apply it, so for them the domain has no SPF. The signals below say what’s wrong.

Anyone can send email as this domain: The record ends in “+all”, which authorises every server in the world. Set up like this, SPF protects nothing.

The SPF doesn’t fully protect the domain: The record doesn’t say what to do with servers that aren’t on its list, so fake email in the domain’s name isn’t flagged.

SPF is set up correctly: The domain lists the servers that may send its email and asks receivers to flag or reject the rest. SPF alone doesn’t stop impersonation: DMARC is what tells receivers what to do.

+all: any server may send (dangerous)

?all: the record says nothing about them

~all: marked as suspicious

-all: rejected

No “all”: the record says nothing about them

Limitations

Warning

We read the domain’s public DNS records. If you type an email address or a link, only its domain leaves your browser. The domain you look up isn’t stored.

Troubleshooting

That doesn’t look like a public domain. Try something like example.com.

DNS didn’t answer in time. Try again in a few seconds.

You’ve run a lot of checks in a row. Wait a minute and try again.

Use with the API

Warning

Needs an API key and credits. Each completed call costs 1 credit, even when there is no data. An active Pro account includes 20 credits per UTC calendar month, shared by every API route and spent first; unused monthly credits do not roll over. Credits bought on your account page work without Pro and never expire.

Note

Errors are never charged: 401 invalid_api_key (missing or invalid key), 403 pro_required (no Pro credits and no purchased credits), 422 invalid input, 429 quota_exceeded (no credits left), rate_limit_exceeded or ai_busy (the AI of sms-check is at capacity), 503 tool_warming (the data is still being prepared) or tool or provider unavailable. After a 429 or 503, retry once the seconds in the Retry-After header have passed.

Reads a domain’s SPF record as receivers do (RFC 7208): its terms, what it ends with, the DNS lookups across the whole include tree against the limit of 10, every include and whether it publishes SPF, and the record’s problems as signals. Nothing is stored.

Send the JSON body to the tool's own route, or to POST /v2/tools with the tool field added. Both routes return the same result.

Endpoint
POST https://api.nocall.io/v2/spf-check
POST https://api.nocall.io/v2/tools  {"tool":"spf-check","domain":"example.com"}

Parameters

NameTypeRequiredDescription
domainstring (1–320)YesA domain, or an email address or link whose domain is used, up to 320 characters. Public names only: IP addresses, single labels and special-use names (.local, .internal, .test…) are a 422.
bash
REQUEST_ID="$(uuidgen)" && [ -n "$REQUEST_ID" ] &&
curl --request POST 'https://api.nocall.io/v2/spf-check' \
  --header "Authorization: Bearer $NOCALL_API_KEY" \
  --header 'Content-Type: application/json' \
  --header "Idempotency-Key: $REQUEST_ID" \
  --data '{"domain":"example.com"}'

Example response (200)

This is the documented example from the API reference. Lookups use a fictional number, and aggregates and AI answers show the shape of the result, not live data.

JSON
{
  "data": {
    "tool": "spf-check",
    "result": {
      "domain": "example.com",
      "domainAscii": "example.com",
      "found": true,
      "record": "v=spf1 include:_spf.google.com ~all",
      "recordCount": 1,
      "terms": [
        {
          "qualifier": "pass",
          "mechanism": "include",
          "value": "_spf.google.com"
        },
        {
          "qualifier": "softfail",
          "mechanism": "all",
          "value": null
        }
      ],
      "allResult": "softfail",
      "lookups": 1,
      "includes": [
        {
          "domain": "_spf.google.com",
          "found": true
        }
      ],
      "signals": [
        "softfail_all"
      ],
      "valid": true,
      "attention": false
    }
  },
  "meta": {
    "requestId": "req_example",
    "unitsCharged": 1,
    "usage": {
      "periodStart": "2026-10-01",
      "unitLimit": 20,
      "unitsUsed": 3,
      "unitsRemaining": 17
    }
  }
}

Result fields (data.result)

FieldTypeDescription
domainstringThe domain in Unicode.
domainAsciistringThe same domain in ASCII (punycode), as DNS sees it.
foundbooleanWhether the domain publishes an SPF record.
recordstring | nullThe SPF record as published; null when there is none or more than one.
recordCountintegerHow many SPF records the domain publishes; more than one is an error.
termsarray<object>The record’s mechanisms and modifiers in order, each with its qualifier (pass, fail, softfail or neutral; null for redirect and exp) and value.
allResult"pass" | "fail" | "softfail" | "neutral" | nullWhat the record ends with (its all, or its redirect target’s): pass, fail, softfail or neutral; null when it has none.
lookupsintegerMechanisms and modifiers that query DNS, across the whole include tree. Receivers stop above 10 (permerror).
includesarray<object>Every include and redirect target in the order read, and whether it publishes SPF.
signalsarray<string (enum, 12)>no_spf, multiple_records, syntax_error, too_many_lookups, include_not_found, include_loop, plus_all, neutral_all, softfail_all, no_all, ptr_mechanism or macros.
validbooleanWhether a receiver can evaluate the record: one record, no syntax error, at most 10 lookups, every include found and no loop.
attentionbooleanWhether the result deserves a look: no SPF, an invalid record, or one that ends in +all, ?all or no all.

Frequently asked questions

What is SPF?

Sender Policy Framework: a DNS record where a domain lists the servers allowed to send its email. The server that receives a message checks whether the server that delivered it is on that list.

Which is better, “-all” or “~all”?

“-all” asks receivers to reject email from servers that aren’t listed; “~all” asks them to mark it as suspicious. Both protect, and many domains use “~all” and let DMARC decide what to do. “+all” and “?all” don’t protect.

Why does the limit of 10 lookups matter?

Each include, a, mx, ptr, exists and redirect makes the receiving server query DNS. If the whole record needs more than 10, it’s treated as an error and SPF stops working. Remove services you no longer use or ask your provider for a simpler include.

Does SPF stop fake emails on its own?

No. SPF checks the hidden envelope sender, not the address you see in “From”. DMARC is what ties the two together and asks receivers to quarantine or reject email that fails. Check the domain’s DMARC too.