← Blog

Real-time vs batch email validation: which should you use?

Two shapes of the same check — a synchronous call at the point of capture, or a CSV job for the list you already have — with the same honest result either way.

Contents

You have two situations and one question. There is a signup form where a new address arrives one at a time, and there is a spreadsheet of forty thousand addresses you exported last year and never touched again. Real-time vs batch email validation is not really a contest. It is two shapes of the same check, and which one you reach for depends on a single thing: when the addresses show up. This post shows both calls side by side, says when each fits, and is plain about the one thing neither of them does.

Before either of them, a note on doing less. A malformed address — no @, no dot in the domain — you can catch in your own code without spending anything. If that is all you need, the validate email in Python walkthrough covers the stdlib-level syntax pass, and for a one-off human check the free email validator tool takes a single address with no signup. Reach for the API when you want the domain actually checked for mail records, not just the string.

The two shapes

Real-time is one address, one synchronous call to /v1/verify/email, run at the point of capture. It costs 1 credit and the answer comes back on the request — fast enough to sit inline in a form submit.

Batch is a CSV of addresses sent to /v1/bulk/email, processed as a job. Credits are reserved per row and refunded for rows that error.

Same endpoint family, same checks, same not_performed list. The only real difference is timing: one address as it arrives, or a file of addresses you already have.

Real-time: validate at the point of capture

The point of capture is a signup form, a checkout, an API intake — anywhere one address shows up and you want an answer before you write it to your database.

curl -X POST https://api.boundstone.io/v1/verify/email \
  -H "Authorization: Bearer bs_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"email":"you@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"]
  }
}

One thing that matters here more than anywhere else: the bs_live_ key is a server-side secret. A signup form runs in the browser, so call the API from your own backend route and never ship the key to the client.

// server route — the key stays on your infrastructure
const res = await fetch("https://api.boundstone.io/v1/verify/email", {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${process.env.BOUNDSTONE_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ email }),
});
const result = await res.json();

Batch: validate a list you already have

A batch job is for the addresses that arrived before you had validation — an export, a CRM dump, a list you inherited. You send raw CSV and get back a job.

curl -X POST https://api.boundstone.io/v1/bulk/email \
  -H "Authorization: Bearer bs_live_YOUR_KEY" \
  -H "Content-Type: text/csv" \
  --data-binary @list.csv

That returns HTTP 202 with a job_id. When it finishes, pull the results:

curl https://api.boundstone.io/v1/bulk/JOB_ID/results.csv \
  -H "Authorization: Bearer bs_live_YOUR_KEY"

The free tier caps a job at 250 rows; paid jobs go up to 10,000. Credits are reserved per row up front and refunded for any row that errors, so a malformed line in the middle of your file does not quietly cost you. If you would rather not write code at all, the dashboard has a CSV upload and a paste box that run the same job. The bulk email validation from a CSV post walks the whole workflow end to end.

The result is identical — that's the point

Whichever mode you use, the checks are the same. Every result carries:

"checks": {
  "performed": ["syntax", "mx", "disposable_list", "role_list"],
  "not_performed": ["smtp_mailbox", "catch_all"]
}

A "valid" from a batch of forty thousand means exactly what a "valid" from a live signup means — there is no quieter, cheaper version of the check for lists. (One field to read carefully: free_provider is returned so you can see a Gmail or Outlook address for what it is, but it is not a member of performed. It is a flag, not a verdict.)

When each fits, and why you use both

Real-time is the front door: run it as new addresses arrive so bad data never lands in the first place. Batch is the backlog: run it once over the list you already have to find the dead domains and disposables sitting in it today.

Most teams use both. Batch-clean the existing list, then wire real-time into the signup path so it stays clean. Same checks on both ends means the list you cleaned and the addresses you add next are held to one standard, not two.

What neither one does

Both modes stop at the same honest line, and it is worth reading not_performed out loud: smtp_mailbox and catch_all. Boundstone does not knock on the mailbox to confirm the specific inbox exists, and it does not probe whether a domain accepts everything. Those are the checks vendors most often imply and least often actually run, so we list them as not done rather than dress them up. What you do get — real MX records on the domain, syntax, disposable and role-account flags — is enough to reject the large share of bad addresses that never had a chance of receiving mail. The not_performed list is not an apology. It is the reason a valid here means what it says.

The short version

  • Real-time — POST /v1/verify/email, one address, synchronous, 1 credit. Use it at the point of capture. Keep the bs_live_ key server-side.
  • Batch — POST /v1/bulk/email, raw CSV, 202 + job_id, results at /v1/bulk/:id/results.csv. Free cap 250 rows, paid up to 10,000; per-row credits refunded on error.
  • Same check either way — identical performed and not_performed; a batch valid equals a live valid.
  • Use both — batch to clean the list you have, real-time to keep the new ones clean.
  • Do less first — catch broken syntax in your own code before spending a credit.

Frequently asked questions

What's the difference between real-time and batch email validation?

Real-time validation checks a single address the moment it's entered, such as on a signup or checkout form, so you can accept or reject it instantly. Batch validation processes a whole list at once, which is better for cleaning an existing database before a campaign. With Boundstone the logic is identical either way: a single real-time call to /v1/verify/email, or a bulk CSV job at /v1/bulk/email that reserves one credit per row and refunds any row that errors. The only real difference is whether you send one address or thousands.

Should I use real-time or batch email validation for my use case?

Use real-time validation at the point of entry, like signup forms, checkout, or lead capture, where you need an instant decision to catch typos and throwaway addresses before they enter your system. Use batch validation to clean an existing list before a large send, checking thousands of records in one job instead of one call at a time. Many teams do both, running real-time to keep new data clean and periodic batches to re-check older records, since a domain that resolved months ago may not today. Boundstone's free tier gives 250 credits a month with no card and credits that never expire, so you can try either approach.

Does a 'valid' result from real-time or batch validation mean the email can actually receive mail?

No, and an honest validator should say so plainly. A Boundstone 'valid' result confirms correct syntax, a domain with real MX records, and that the address isn't on our disposable or role-account lists; it does not confirm that the specific mailbox exists or will accept mail. We do not perform SMTP mailbox verification or catch-all detection in either real-time or batch mode. Every response lists exactly what was checked and what wasn't, so you always know the limits of what 'valid' proves.

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