Bulk email verification API

Email list cleaning service with a bulk verification API

Upload a CSV or TXT file, or send the addresses as JSON. emailvalidation.io checks every unique address in the background and gives you back your list with a result for every row, as CSV or JSON. A webhook tells you when the job has finished.

Example request and response

Upload a file and pass a webhook URL. The answer (201) is the queued job: how many rows the list has, how many unique, valid addresses will be checked, and the requests charged. Already have the list in your code? Send {"emails": [...]} as JSON instead of a file. Every parameter is in the bulk documentation.

curl https://api.emailvalidation.io/v1/bulk \
  -H "apikey: YOUR-API-KEY" \
  -F file=@contacts.csv \
  -F webhook_url=https://example.com/hooks/emailvalidation
{
  "job_id": "629954218123464704",
  "status": "queued",
  "source": "csv",
  "catch_all": false,
  "counts": {
    "total": 5,
    "unique": 3,
    "duplicates": 1,
    "invalid": 1,
    "processed": 0,
    "deliverable": 0,
    "undeliverable": 0,
    "risky": 0,
    "unknown": 0
  },
  "progress": 0,
  "quota": {
    "charged": 3,
    "refunded": 0
  },
  "webhook": {
    "status": "pending",
    "attempts": 0
  },
  "error": null,
  "created_at": "2026-10-05T08:13:09+00:00",
  "started_at": null,
  "finished_at": null,
  "expires_at": "2026-11-04T08:13:09+00:00",
  "links": {
    "self": "https://api.emailvalidation.io/v1/bulk/629954218123464704",
    "results": null
  },
  "webhook_secret": "whsec_faf08666fa26ea2b20c188fa97822ecb4fcd9bc39598cc41"
}

What every row of your list gets back

state, reason
deliverable, undeliverable, risky or unknown, and why, for example valid_mailbox, invalid_mailbox, invalid_mx or invalid_format.
score
A quality score from 0 (poor) to 1 (good).
format_valid, mx_found, smtp_check
Whether the address is well-formed, whether its domain has MX records, and whether the mail server accepted the mailbox.
disposable, role, free
Throwaway addresses, role addresses such as info@ or support@, and addresses at free email providers.
catch_all
Whether the domain accepts mail for any address. Filled when you ask for the catch-all check (plans from Small), otherwise empty.
did_you_mean
A suggested address when the domain looks like a typo.
email, user, tag, domain
The address as it was checked, and its parts.

Use cases

Before a campaign

Remove undeliverable and disposable addresses from an export before you send, and send to risky (catch-all) addresses in smaller batches.

Regular CRM clean-ups

Export your contacts on a schedule, submit the file, and import the results CSV back when the webhook arrives. Your columns are kept and the result columns are added; check cells that start with =, +, - or @, such as phone numbers, because they get a leading ' so that spreadsheet programs do not run them as formulas.

Moving to a new email tool

Check a list before you import it into a new email service provider, so the new account does not start with a high bounce rate.

Old sign-up lists

Verify addresses that were collected without validation, such as old newsletter or event sign-ups, before you write to them again.

AI agents

Through the MCP server, an agent can submit a list, follow the job and delete it. It downloads the results over the REST API.

How a list cleaning job works

  1. Submit the list with POST /v1/bulk: a CSV or TXT file, or a JSON array of addresses. The answer is the job, with status queued.
  2. Wait for the webhook, or check GET /v1/bulk/{job_id} about once a minute until its status is completed. Checking a job is free. On the free plan, which allows 10 requests a minute, a submitted list counts against that minute’s limit too, so wait until the next minute before you check the job (details).
  3. Download the results with GET /v1/bulk/{job_id}/results: as CSV, with your columns plus the emailvalidation_* columns, or as JSON.
  4. Delete the job with DELETE /v1/bulk/{job_id} once you have the results, or let it expire 30 days after it finished.

Every unique address gets the same checks as a single request to the email validation API: syntax, MX records, a live check of the mailbox over SMTP, and the disposable, role and free-provider flags. Duplicates are checked once and repeat that result in every row where they appear. Rows without a valid address are kept and marked undeliverable with the reason invalid_format.

What a job costs

  • Charged when you submit: one request of your quota per unique, valid address. Addresses are compared without regard to case and surrounding spaces, so Anna@Example.com and anna@example.com count once. The X-Cost header and quota.charged show the amount.
  • Free: duplicates, rows without a valid address, and checking, listing, downloading and deleting jobs.
  • Refunded: addresses we could not verify because of a failure on our side, when the job completes. Deleting a job refunds the addresses not checked yet, and a failed job is refunded. Refunds go back to your current quota and cannot raise it above its monthly size, so a refund after your quota has reset gives back at most what you have used since the reset.
  • Checked first: a list is only accepted if your quota has more requests left than the list costs. Otherwise the API answers 429 with the number of requests the job needs, before anything is stored or checked.

Files and limits

LimitValue
FormatsCSV (comma, semicolon, pipe or tab), TXT (one address per line), JSON array
Rows per list100,000 (1,000 with a sandbox key)
File size, or all JSON items together25 MB
Columns per CSV row500

A header row is detected. The address column is the one you name with email_column (its title or its number); without it, the API uses the column titled like email, and otherwise the column with the most addresses in the first 100 rows. The CSV and TXT rules are in the documentation.

Your list and your data

  • Lists and results are encrypted with AES-256 before they are stored, on top of our storage provider’s encryption at rest. While a job runs, its addresses are kept encrypted in our database, and they are deleted from it when the job finishes.
  • The results are only available through the API, with an API key of your account. There are no public download links, and the webhook carries the job’s status and counts, never addresses or results.
  • The stored list and the results of a job are deleted 30 days after the job finished, or right away when you delete the job.
  • The webhook is signed with HMAC-SHA256 and a secret for each job, goes only to https URLs on public hosts, and is sent in up to 6 attempts over about 2.5 hours until your endpoint answers with a 2xx status. See Webhooks.

Free tool, dashboard or API?

  • A few addresses, no account: the free bulk email verifier on this site, which checks a few addresses an hour.
  • A file now and then, no code: upload it in the emailvalidation.io dashboard.
  • Recurring lists, automation, up to 100,000 rows: the bulk API on this page, with webhooks and results in your own column layout.

Test without using your quota

Sandbox keys work with bulk jobs. A sandbox job is free, accepts up to 1,000 rows and never contacts a mail server: the documented test addresses get their made-up results, and every other address is deliverable. Its webhook is signed like a live one, so you can test your receiver before you send a real list.

Start on the free plan

Bulk jobs are part of every plan, including the free plan with 100 requests a month. Each unique, valid address in a list costs one request. Paid plans start at $9.99 a month for 5,000 requests.

Frequently asked questions

What does an email list cleaning service do?

It checks every address on a list and tells you which ones to remove before you send: addresses that do not exist, domains without a mail server, typos and throwaway addresses. emailvalidation.io does this through an API: you submit the list as a job and download it again with a result for every row.

How long does cleaning a list take?

You do not wait for it: the API answers at once with a job id, and a webhook or polling tells you when the job has finished. To protect deliverability, the checks are spread out per receiving mail server, so a large list can take a day or longer, especially when many of its addresses are at the same provider or company domain.

What does it cost?

One request of your quota per unique, valid address, charged when you submit the list. Duplicates and rows without a valid address are free, addresses we could not verify because of a failure on our side are refunded to your current quota, and checking, downloading and deleting jobs is free. The free plan includes 100 requests a month.

Which files can I upload?

CSV files (comma, semicolon, pipe or tab, with or without a header row) and TXT files with one address per line, up to 25 MB and 100,000 rows. You can also send the addresses as a JSON array. The address column is detected, or you name it with email_column.

Do I get my own columns back?

Yes. The results CSV keeps your columns and your delimiter and appends 15 emailvalidation_* columns. It has one row for every row of your list, in the same order, including rows with an empty or invalid address. Two changes to check before you import it: cells that start with =, +, - or @ get a leading ' so that spreadsheet programs do not run them as formulas, and a file without a header row gets one (column1, column2, …).

How is my list stored, and when is it deleted?

Lists and results are encrypted with AES-256 before they are stored and can only be downloaded through the API with a key of your account; there are no public links. The stored list and the results of a job are deleted 30 days after the job finished, or right away when you delete the job.

Can I check a small list without an account?

A few addresses, yes. Without an account, the free bulk email verifier checks a few addresses an hour, and you can download the results as CSV. For more, create a free account: the free plan includes 100 requests a month, and bulk jobs are part of it.

Related

Free email tools

Start using our email validation software today!

Get 100 validations per month for free