← Blog

How to verify an email address without sending an email

Syntax, a live MX lookup, and disposable/role checks get you surprisingly far without touching a mailbox — but confirming the exact address exists still needs a send.

Contents

"Verify email without sending" sounds like a contradiction, and partly it is. You can learn a lot about an address before you ever put it in a To: field — whether it parses, whether the domain can receive mail at all, whether it's a throwaway or a shared inbox. What you cannot learn, with certainty and without sending, is whether that exact mailbox exists. This post is about the gap between those two things: how far the no-send checks get you, why the last mile needs a real message, and how to run the no-send layer in one call.

What "without sending" actually buys you

Three checks run without touching a mailbox.

Syntax. Does the string parse as an email address? Your language already does this. Django's EmailField and Rails' URI::MailTo::EMAIL_REGEXP are pure syntax — local, free, no network call. (Flask-WTF's Email() is syntax-only by default too, though the email_validator package underneath it can add an MX check if you turn on deliverability — which is exactly the next layer.) If you only need to keep bob@@gmail out of your database, stop here — you don't need an API.

MX records. Does the domain publish mail servers? This is a DNS lookup, not a mailbox check: it confirms the domain can receive mail, not that your specific address does. You can do it yourself.

import dns.resolver

def has_mx(domain: str) -> bool:
    try:
        return len(dns.resolver.resolve(domain, "MX")) > 0
    except dns.resolver.NXDOMAIN:
        return False

An address whose domain has no MX record is a dead end. That's the single highest-value no-send signal, and it costs one DNS query.

Disposable and role lists. Is the domain a known throwaway (mailinator.com, guerrillamail.com)? Is the local part a shared alias (info@, support@, admin@)? These are list lookups against data someone has to maintain. A side project can copy a public list; keeping it current is the tedious part.

None of these send anything, and all of them are things you could wire up yourself. The reason to reach for an API is to stop maintaining the DNS timeouts and the throwaway list, and to get one answer instead of three.

The one call

POST /v1/verify/email runs all three no-send checks and reports each one.

curl -s https://api.boundstone.io/v1/verify/email \
  -H "Authorization: Bearer bs_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"email":"jane@example.com"}'
{
  "valid_syntax": true,
  "domain": "example.com",
  "mx_found": true,
  "disposable": false,
  "role_account": false,
  "free_provider": false,
  "checks": {
    "performed": ["syntax", "mx", "disposable_list", "role_list"],
    "not_performed": ["smtp_mailbox", "catch_all"]
  }
}

The boolean keys map back to those checks: valid_syntax, mx_found, disposable, role_account. free_provider flags consumer domains like Gmail — useful for scoring a B2B signup, not a verdict, and it isn't one of the checks.performed. Keep the bs_live_ key on your server; it's a secret, never a browser or a form field.

Read the response honestly

Look at checks.not_performed. It reads ["smtp_mailbox", "catch_all"], and that's the point. The API tells you what it did not do so you don't mistake a clean no-send result for proof the mailbox exists.

checks.performed reads ["syntax", "mx", "disposable_list", "role_list"]. Everything on that list happened without sending. Nothing on it confirms delivery. An address with valid_syntax: true and mx_found: true is plausible — it parses, and its domain accepts mail — but "plausible" and "exists" are different claims, and we never blur them. For the difference between checking an address and confirming it, see email validation vs verification.

Why the mailbox needs a send

To confirm one specific mailbox without sending, you would open an SMTP connection and get as far as RCPT TO: without delivering — the classic SMTP probe. Two things break it.

First, servers lie. Many mail servers accept RCPT TO: for every address, to deny spammers a way to enumerate valid users, then bounce the message later. A 250 OK at probe time can still bounce an hour on. The probe looks authoritative and isn't.

Second, catch-all domains. A catch-all accepts mail for every possible local part, so anything@theirdomain.com comes back the same. There is no address you can probe that returns negative, which means the probe tells you nothing. That's why catch_all sits in not_performed — see what a catch-all email is for the full mechanics. Boundstone performs neither the SMTP probe nor catch-all detection, because a result we can't stand behind is worse than an honest gap.

The one method that survives both problems is a confirmation email: send a link, see who clicks. It is the only proof that the mailbox exists and someone reads it. It requires sending. That's the ceiling.

When the no-send layer is enough

Most of the time, it is. Blocking dead domains, throwaways, and typo'd syntax at signup removes the bulk of bad addresses without a single send. Route the rest to a confirmation email — which you were probably sending anyway — and use the no-send call to decide whether to bother.

You can run the checks with no key and no signup on the free email validator, then move to /v1/verify/email when you want it in your pipeline.

The short version

  • Syntax, MX, and disposable/role checks all run without sending. Your stdlib does syntax; a DNS query does MX; a maintained list does the rest.
  • One POST /v1/verify/email call folds all three in and reports checks.performed as ["syntax", "mx", "disposable_list", "role_list"].
  • Confirming that a specific mailbox exists needs an SMTP probe, and probes are defeated by servers that lie and by catch-all domains. Boundstone marks smtp_mailbox and catch_all as not_performed rather than guess.
  • The only certain proof is a confirmation email. "Verify without sending" gets you most of the way; the last step sends.

Frequently asked questions

Can you verify an email address without actually sending a message to it?

Yes. Without sending anything, you can check that the address is correctly formatted, confirm the domain publishes valid MX (mail exchange) records so it is set up to receive mail, and screen the address against disposable-domain and role-account lists. What you cannot confirm this way is whether the specific mailbox exists or accepts mail, since that requires an SMTP probe. Boundstone reports that SMTP mailbox check as not performed rather than guessing at it.

If an email passes validation, does that mean it will definitely receive my message?

No, and an honest tool should say so plainly. A valid result from Boundstone means the address is correctly formatted and its domain publishes MX records, but it does not prove the individual inbox exists, is active, or will accept mail. Confirming that would require SMTP mailbox and catch-all checks, which Boundstone lists as not performed instead of returning a false deliverable verdict. Treat valid as a strong syntax-and-domain signal, not a delivery guarantee.

How do you spot a fake or disposable email address without emailing it?

Boundstone flags several risk signals from the address and its domain alone: whether it uses a known disposable or throwaway domain, whether it is a role account like info@ or support@ rather than a person, and whether it is on a free provider such as Gmail. Each result comes back as its own field (disposable, role_account, free_provider) so you decide the policy, and none of these require sending a message. It does not do spam-trap detection or sender-reputation scoring, so use these flags as inputs to your own rules rather than a deliverability guarantee.

Thomas Tsui

Founder of Boundstone — building phone, email and IP validation you can actually verify.

One honest API for email, phone and IP — every response lists what it checked and what it didn't claim to. Free tier: 250 credits/month, no card, credits never expire.

More from Boundstone — API documentation · Benchmark methodology · The benchmark series · Buyer's checklist