Skip to content

Catch bad email before it bounces.

One POST request checks the syntax, the domain’s live mail servers, the mailbox itself, and open disposable and role lists — then hands you a reasoned verdict and a typo suggestion, without ever sending a message.

Free credits every month. No credit card required. The demo on this page runs against the live service.

Live demo

POST /demo/email · no key needed

try:

Response

Verify any address to see the full API response, straight from the live service.

syntax, DNS, provider rules, open lists, and SMTP mailbox checksone credit covers the full answerunverified answers cost nothing, undeliverable ones nothing within fair useno mail is ever sent

Every response field, documented.

This is the actual contract of POST /api/v1/email — booleans are tri-state: false is a checked negative, null means the check did not apply (for example after invalid syntax). Each response also carries sources naming the datasets consulted and meta with your credit usage.

Field What it tells you
emailThe address as checked: local part preserved, domain lowercased and converted to punycode. Wrappers people paste — a display name (Mia K <mia@…>), a mailto: prefix, spreadsheet quotes, trailing punctuation, invisible characters — are stripped first. Input that still fails the syntax check is echoed back.
normalized_emailThe canonical inbox the mail actually reaches: lowercased, plus-tag stripped, and Gmail dots and googlemail.com folded away. Dedupe your list on this, not on the raw input.
is_aliasWhether the address carries a plus-tag (mia+promo@…) — the same inbox under a disposable label, a favorite of signup-bonus farmers.
is_gibberishWhether the local part reads as keyboard mash (xkqzwv@…). Deliberately conservative: y counts as a vowel to protect names like krzysztof, and digit-only locals (normal on qq.com) are never flagged.
looks_generatedWhether the username looks machine-made or a placeholder rather than a person's choice: a hex string of 16 or more characters with at least one a–f, a dashed UUID, 20 or more alphanumerics mixing upper case, lower case and digits, one or two letters followed by four or more digits, any word (with at most one separator) followed by six or more digits, or a placeholder word — test, tester, testing, temp, fake, asdf, asdfasdf, qwerty, abc, abcd, aaa, xxx, sample, example, foo, foobar, null, none, noname, dummy, placeholder — with optional trailing digits. A heuristic about the string, never about the mailbox; +20 on the score.
local_part_patternThe shape of the username, read with the plus-tag and up to four trailing digits removed: first.last, first_last, first-last, firstlast, f.last, flast, first.l, firstl, last.first, lastfirst, first or last (the name shapes, recognised with the bundled name lists), numeric (digits only), word (an alphabetic token the lists do not know), mixed (letters and digits forming no name shape) or other. The bundled first-name list is small, so a lone first name the list lacks reads as last.
first_nameThe name token the bundled dictionary recognised as a first name, lowercased as typed, only for shapes that carry a full first name. Derived from the address you sent, never looked up anywhere, and never a promise of correctness: a pair like mia.kowalski reads positionally, while a lone name the first-name list lacks lands in last_name instead.
last_nameThe name token the bundled dictionary recognised as a surname, only for shapes that carry a full surname. Derived from the address you sent; nothing is appended from outside, and the lists say nothing about gender.
deliverableThe verdict: deliverable (the exact mailbox was confirmed), risky (a burner, a typo-squat, a parked domain, mail served from a blocklisted network, a web-only domain, a no-reply or role inbox, a full mailbox, a mailbox that was dead and exists again, a catch-all, or a mailbox the handshake could not confirm), or undeliverable (bad syntax, an impossible username, no usable mail servers, or a missing or disabled mailbox).
reasonWhy the verdict is not deliverable. Undeliverable: invalid_syntax, invalid_local_part, no_mx_records, null_mx, mx_unresolvable, mailbox_not_found, mailbox_disabled. Risky: likely_typo, parked_domain, disposable, mx_blocklisted, implicit_mx, mailbox_full, no_reply, role, recycled_mailbox, catch_all, unverified.
risk_scoreA branchable 0–100 composite of the individual signals with published weights: disposable 80, parked domain 60, typo-squat 60, blocklisted mail network 60, web-only domain 30, role 30, catch-all 30, domain under 30 days old 30, recycled mailbox 30, full mailbox 20, gibberish 20, generated 20, no-reply 20 (on top of role), widely seen 20, catch-all behind a security gateway 15 (instead of 30), domain under 180 days 10, no SPF on a business domain 10, unverified mailbox 10, registration ending within 30 days 10, plus-tag alias 5, relay 5. Undeliverable is always 100.
risk_levelThe score bucketed for easy branching — low, medium (30+), or high (60+) — using the same thresholds as the IP endpoint.
risk_signalsThe signals that fired, each as { signal, weight, dataset } in the published order, so the score is the sum of the weights and every weight names the dataset it was read from. Empty when nothing fired, and empty on an undeliverable verdict, where the verdict is the answer and the score is fixed at 100.
syntax_validWhether the address parses under RFC 5322 grammar.
domainThe ASCII (punycode) domain actually used for the DNS and list checks.
domain_categoryThe class of the domain, first match wins: relay (a forwarding service such as Firefox Relay or SimpleLogin), disposable, webmail (a free mailbox provider), military, government or academic from their suffixes, or other. Never "business": from here a personal domain and a company domain look alike.
mx_foundWhether the domain has usable mail servers. An RFC 7505 null MX ("this domain accepts no mail") counts as false, and so do MX records that only point at loopback, private, or non-existent hosts.
mx_implicitTrue when the domain publishes no MX record and mail would fall back to its own address (RFC 5321). Such web-only domains rarely accept mail, so the verdict is risky and no mailbox check is run.
mx_providerWho runs the domain's mail, from its MX hostnames: google, microsoft, zoho, proofpoint, mimecast, and a dozen more, or "other" for self-hosted. Useful for routing and qualifying B2B signups.
mx_provider_typeWhat that provider is: mailbox_provider (Google, Microsoft, Zoho, Proton, Fastmail, Yahoo, iCloud, Yandex, GMX, Tutanota, HEY), security_gateway (Proofpoint, Mimecast, Barracuda — they accept everything at the edge and sort it out behind), transactional (Mailgun, Amazon SES), hosting (Rackspace, GoDaddy), self_hosted (every MX host under the domain itself), or other. Null when there is no provider.
mx_blocklistedWhether any of the domain's mail hosts resolves into a network on the threat blocklists the IP product already installs (Spamhaus DROP and ASN-DROP, the abuse.ch botnet list). Mail served from a hijacked or criminal netblock is a burner-domain signal the disposable list has not caught yet: +60 and a risky verdict. false is a checked negative; null means no MX, unresolvable hosts, or no blocklist feed installed.
mx_network_typeThe class of network the first resolvable mail host sits in: hosting when it is inside a datacenter range, otherwise the operator's type from the ASN database (education, government, hosting, isp). Null when unknown. Informational; it carries no weight.
has_spfWhether the domain publishes an SPF policy. Real companies almost always do; a missing record suggests a parked or throwaway domain.
dmarc_policyThe domain's DMARC policy — none, quarantine, or reject — or null when it publishes none. A strict policy signals a domain someone actually operates.
domain_registered_atThe date the domain was registered, from public RDAP registry data. Null for free providers and burners (not consulted) and where the registry does not publish it.
domain_age_daysDays since registration. Fraud rings register domains hours before they use them; anything under 30 days adds 30 to the risk score, under 180 adds 10.
domain_expires_atWhen the registration ends, from the same RDAP record as the registration date, consulted exactly when that is (business domains only). A registration ending within 30 days adds 10: most healthy domains renew at the last minute, so it is a nudge, not a verdict.
parkedWhether the domain's nameservers belong to a parking or for-sale service. A parked domain that still accepts mail is a harvesting catch-all rather than a mailbox provider: +60 and a risky verdict. Evaluated only when the domain has usable mail servers; null otherwise, or when the nameserver lookup failed.
disposableWhether the domain — or a parent domain handing out subdomains — is a known burner-email provider, or routes its mail through one: a brand-new burner domain still points its MX at a listed operator. A local allow and deny list overrides the synced upstream, and a relay service is never disposable: for one, this is forced false.
is_relayWhether the domain belongs to a permanent alias or forwarding service: Firefox Relay, SimpleLogin, Addy.io, DuckDuckGo Email Protection, Proton Pass, Sign in with Apple's private relay and the rest. A relay address is a real person's real mailbox reached through a name they control and often kept for years, which is why it is never reported as disposable; it adds 5, because the identity behind it is withheld. Ordinary iCloud Mail and Proton Mail mailboxes are not relays, and an iCloud+ Hide My Email alias on icloud.com cannot be told apart from one.
relay_serviceThe relay service's name when is_relay is true.
roleWhether the local part is a role account such as admin@, support@, or billing@ — over a thousand prefixes from an open list, checked with any plus-tag removed, plus any no-reply spelling the list lacks.
role_typeWhich kind of role: no_reply (mail to it is discarded by design), postmaster (the RFC 2142 family — postmaster, abuse, hostmaster, webmaster, security), support, sales, info, admin, billing, marketing, careers, legal, or other for a listed username outside those families. Null when the address is not a role.
free_providerWhether the domain is a known free mailbox provider like gmail.com, outlook.com, or seznam.cz — thousands of providers and country variants from an open list.
smtp_checkedWhether a definitive mailbox-level SMTP answer was obtained. Included in every lookup at the same single credit; when mail servers will not say (greylisting, timeouts), it reports false instead of guessing.
smtp_checked_atWhen the mailbox probe actually ran, as an ISO 8601 timestamp. Confirmed answers are shared across customers for up to a week, so this can predate the lookup; null when no definitive answer was obtained.
mailbox_existsWhether the exact inbox exists, from the SMTP-level check. Null when unconfirmed, or when a catch-all domain makes existence unknowable.
previously_invalidWhether this mailbox exists now but answered "no such mailbox" to an earlier handshake. That is the shape of a recycled address, the spam-trap kind included, so the verdict is risky with reason recycled_mailbox and +30. false means it exists with no such history; null whenever the mailbox is not confirmed.
previously_invalid_atThe date of that earlier not-found answer. It is kept for a year under a keyed hash of the address, and erased with the address.
catch_allWhether the domain accepts mail for every address, which turns the verdict risky: a mailbox there can never be individually confirmed. Behind a security gateway the weight is 15 rather than 30, because the gateway accepts everything by design and the domain behind it is a real, administered one.
smtp_reasonThe detail behind the mailbox check: no_mailbox, mailbox_full, disabled, greylisted, timeout, no_connect, mx_unreachable, provider_unavailable when the verification provider itself could not be reached, or delivered_recently when your own account reported the address delivered within 90 days, which counts as a confirmed mailbox for your lookups. A full mailbox is risky and a disabled one undeliverable; the rest explain an unverified answer.
mailbox_confidenceFor catch-all domains and unanswered checks only: a recomputable 0–100 estimate that the specific mailbox exists. Starts at 50; DMARC, SPF, an established mail provider, an old registration, and a name-shaped address add to it; gibberish, a fresh domain, and a plus-tag take away. Once five or more delivery outcomes have been reported for the domain, a bounce rate of 10% or less adds 15 and one of 50% or more removes 20, and a username that follows the naming convention seen in the domain's confirmed deliveries adds 15 while a name shape that breaks it takes 10 away. A relay alias stays at 50 and moves only on the evidence against it: a bounce rate of 50% or more, or a plus-tag. A published heuristic, not a probe.
widely_seenWhether three or more other accounts looked this address up in the last 24 hours: an address hitting many signup forms in one day is being used by something automated. Counted from a keyed hash and account ids only, never the address, and +20 when it fires. Null where nobody could count: the guest demo, test addresses, invalid syntax.
did_you_meanA suggested correction ("[email protected]" for [email protected]), offered after the mail-server check fails or when the domain is a known typo-squat of a major provider — those resolve on purpose, to harvest misdirected mail. Candidates are the big mailbox providers, the thousand most-linked domains and the domains you verify most; a domain outside the provider list is suggested only when its own mail servers accept mail.
ok_to_sendYour account's sending policy applied to this answer: false for every undeliverable verdict, and otherwise when a blocked signal fired, the score is over the policy's ceiling, or a catch-all or unverified mailbox sits under its confidence floor. The published defaults block disposable, likely_typo, parked_domain, mx_blocklisted and no_reply and any score over 60; GET, PUT and DELETE /api/v1/email/policy read, change and reset them.
blocked_byThe rule that made ok_to_send false, in the order they are applied: undeliverable, the name of the first blocked signal that fired, risk_score, or mailbox_confidence. Null when ok_to_send is true.

One request, and a verdict you can act on at the form.

  • Invalid syntax answers instantly, without touching DNS
  • Disposable and role flags explain every risky verdict
  • Uncertain answers are free, and undeliverable ones are free within fair use — you pay for working addresses
  • Repeats of a charged lookup are free for seven days
$ curl https://spaw.co/api/v1/email \
    -H "Authorization: Bearer sk_live_…" \
    -H "Content-Type: application/json" \
    -d '{"email": "[email protected]"}'

{
  "success": true,
  "data": {
    "deliverable": "risky",
    "reason": "disposable",
    "syntax_valid": true,
    "mx_found": true,
    "disposable": true,
    "domain_category": "disposable",
    "local_part_pattern": "word",
    "role": false,
    "risk_signals": [{ "signal": "disposable", "weight": 80, … }, …],
    "did_you_mean": null,
    "ok_to_send": false,
    "blocked_by": "disposable",
    "sources": […, { "dataset": "disposable-domains", … }],
    …
  },
  "meta": { "credits_used": 1, "credits_remaining": 499, "cache_hit": false }
}

Every data source, named in every response.

The sources block lists exactly the datasets a lookup consulted, with the version of each, so any verdict can be traced back to the list or the live check behind it. A check that never ran is never listed.

DatasetCovers
rfc-5322-syntaxRFC 5322 parsing of the address itself — the one check an invalid address ever reaches.
live-dnsLive DNS MX, SPF, and DMARC resolution
disposable-domainsCurated disposable-domain lists
role-addresses, free-provider-domainsOpen role-address and free-provider lists
typo-domains, provider-username-rulesProvider username rules and typo-squat map
mx-provider-patternsThe mail providers behind a domain’s MX hostnames, which name mx_provider.
mailbox-smtpSMTP mailbox checks, partner infrastructure
delivery-feedbackDelivery outcomes your own account reported in the last 90 days, which confirm a mailbox without a probe. Only your own.
rdap-registrationRDAP registry registration dates

Data synced on 2026-10-12: the newest sync of the open lists and curated maps behind the answers on this page. Every response carries the same dates in its sources block.

The form helper, on your signup form in minutes.

A dependency-free script wires the API into any form: it corrects typos before they become dead signups and flags addresses that cannot receive mail.

Create a publishable key

A pk_ key is safe to ship in page source: it can only run single lookups through the four browser endpoints (email, phone, IP and postal address), and only from the domains you allow. Prefer your secret key server-side? A five-line proxy works too.

Mark your input

Include the script and add data-spaw-email to the field. The helper checks on blur and renders "Did you mean…?" corrections and dead-address notices.

Enforce your own policy

Every verdict fires a spaw:result event with the full response, so you decide what to do about disposable or role addresses. The helper itself never blocks a submit.

Protect it with Turnstile

Store a Cloudflare Turnstile pair on the key and add data-turnstile-site-key to the script tag. The helper fetches a fresh token before every lookup and the endpoint refuses lookups without one, so bots cannot spend your credits.

<script
    src="https://spaw.co/spaw-form.js"
    data-key="pk_live_…" defer></script>

<input type="email" name="email" data-spaw-email>

<script>
  // optional: your own policy on top
  addEventListener('spaw:result', (event) => {
    if (event.detail.disposable) {
      // e.g. disable the submit button
    }
  });
</script>

Where one credit pays for itself.

Protect sender reputation

Keep dead domains and burner inboxes out of your list before they bounce and drag your deliverability down.

Stop trial abuse

Disposable detection with subdomain matching closes the loop on serial free-trial signups from temp-mail services.

Fix typos at the form

Turn did_you_mean into an inline "Did you mean…?" prompt and rescue signups that would otherwise silently fail.

What we won’t pretend to know.

Email verification is full of vendors selling certainty they don’t have. We document our limits instead.

Unknown is an answer we will give you

When mail servers refuse to say whether an inbox exists (catch-all domains, greylisting), we return null and smtp_checked: false instead of a confident guess. Nothing is ever simulated.

A message is never sent

Mailbox checks are SMTP handshakes that stop before any mail is transmitted, run on dedicated verification infrastructure. Nothing ever lands in an inbox or a spam folder, and your own domain and sender reputation are never involved.

A score you can recompute, not a black box

risk_score is just the documented flags added up with published weights — disposable, typo-squat, a parked domain, a blocklisted mail network, role, catch-all, a freshly registered domain, an unverified mailbox — and risk_signals lists exactly the ones that fired. Branch on the number for convenience, or ignore it and use the explicit booleans and dataset versions behind it.

Common questions about email lookups.

Does "deliverable" mean the inbox exists?

When mailbox_exists is true, yes: an SMTP-level check confirmed the exact inbox, and a missing one flips the verdict to undeliverable. Where mail servers will not say — catch-all domains, aggressive greylisting — we return null and smtp_checked: false rather than guessing. Every lookup includes this check at the same single credit.

Do you ever send email to the addresses I check?

Never. The free checks are syntax parsing, live DNS, and curated open lists. The mailbox check is an SMTP handshake that ends before any message is transmitted, so nothing ever reaches an inbox or a spam folder.

How fresh is the disposable-domain list?

It syncs weekly from an open aggregate of tens of thousands of burner domains, with subdomain matching so team.mailinator.com is caught by the mailinator.com entry. Every response names the list version that produced it.

What about international addresses?

Internationalized domains (mia@müller.de) are converted to their punycode form — the form DNS actually resolves — before the mail-server and list checks, and the response reports that canonical domain.

Verify your first address in minutes.

Create a key, send one POST request, and keep free lookups every month on us.

Get your API key