REST API · JSON · SDKs in 9 languages

Real-time email validation API for developers

Check an email address while the user is still on your form. One GET request to /v1/info checks the syntax (with typo suggestions), looks up the MX records, asks the mailbox over SMTP without sending an email, flags disposable, role and free-provider addresses and, on paid plans, runs catch-all detection. You get back a state, a reason code and a score from 0 to 1. Whole lists go through the bulk endpoint, up to 100,000 addresses per job. Used by over 8,000 marketers and developers.

  • 100 free validations a month
  • No credit card
  • Checks run in Germany
  • Pay only for definitive results
curl -H "apikey: YOUR-API-KEY" "https://api.emailvalidation.io/v1/info?email=anna@example.com"

Try the live API

Send a request, see the real response

Edit the address in the request or pick an example. It goes to the same API your code will call: you get the real response, and the Code tab shows the same request in five languages.

From API key to first result in three steps

No SDK needed: any language that can send an HTTPS request can call the API.

  1. Step

    Create a free account

    Sign up and copy your API key from the dashboard. The free plan includes 100 credits a month (one per validation), at up to 10 requests a minute.

    apikey: YOUR-API-KEY
  2. Step

    Call GET /v1/info

    Pass the address as email and your key in the apikey header. Use the header rather than the query parameter, because query parameters can end up in access logs. Use --data-urlencode for tagged addresses: without it, the + in anna+news@example.com arrives as a space. On the Small plan and up, add catch_all=1 for catch-all detection.

    curl -sS -G "https://api.emailvalidation.io/v1/info" \
      --data-urlencode "email=anna@example.com" \
      -H "apikey: YOUR-API-KEY"
    
  3. Step

    Act on the state

    Branch on state and log reason: accept deliverable addresses, ask for a correction when an address is undeliverable, and decide case by case for unknown ones and for catch-all addresses (reason low_deliverability).

    curl -sS -G "https://api.emailvalidation.io/v1/info" \
      --data-urlencode "email=anna@gmial.com" \
      -H "apikey: YOUR-API-KEY" | jq '{state, reason, score, did_you_mean}'
    

Endpoints

Seven endpoints, one base URL

Every call goes to https://api.emailvalidation.io and returns JSON. Authenticate with your API key in the apikey header or the apikey query parameter.

  • One key, header or querySend the key as a header to keep it out of URLs and logs. Free and Small include 1 API key, Medium 2 and Large 5, and sandbox keys come with the Medium plan and up.
  • Catch-all on requestAdd catch_all=1 to /v1/info or catch_all to a bulk job to test whether the domain accepts every address. Available from the Small plan.
  • Also an MCP serverAI agents reach the same checks at https://api.emailvalidation.io/mcp. Set up the MCP server.
  • GET/v1/infoValidate one address. Parameters: email, catch_all (1 or 0).
  • POST/v1/bulkStart a bulk job from a JSON array or a CSV or TXT file, up to 100,000 addresses.
  • GET/v1/bulkList your bulk jobs, newest first.
  • GET/v1/bulk/{job_id}Status, counts and progress of one job.
  • GET/v1/bulk/{job_id}/resultsDownload the results as JSON or CSV.
  • DELETE/v1/bulk/{job_id}Delete a job together with its list and results.
  • GET/v1/statusYour monthly quota: total, used and remaining. Free to call.

GET /v1/info

What the response tells you: 21 fields

Every response has the same 21 fields, so your code never has to guess which keys exist. To accept or reject at signup, branch on state. Keep reason for your logs and support tickets, rank or segment a list with score, and show did_you_mean as a “Did you mean …?” hint in your form.

FieldTypeMeaning
emailstringThe address that was checked.
userstringThe local part before the @.
tagstringThe tag part of the address, if it has one.
domainstringThe domain part after the @.
format_validbooleanWhether the address follows the email syntax rules.
mx_foundbooleanWhether the domain has MX records, the usual sign that it can receive email.
smtp_checkbooleanWhether the receiving mail server accepted the mailbox in the SMTP check.
catch_allboolean | nullWhether the domain accepts mail for every address. null unless you send catch_all=1.
rolebooleanA role-based address such as support@ or postmaster@.
disposablebooleanAn address at a disposable email service.
freebooleanAn address at a free email provider such as Gmail or Yahoo.
scorenumberQuality score from 0 (bad) to 1 (good).
statestringdeliverable, undeliverable or unknown.
reasonstringWhy the address got its state, see the table below.
did_you_meanstringA suggested correction for a likely domain typo, for example gmail.com for gmial.com. A suggestion only: it does not change the other fields.
catch_all_resolutionobject | nullFor a catch-all domain: how far the check got without sending an email, with domain-level evidence such as the mail provider. null for any other result.
bounce_probabilitynumber | nullAn estimated chance from 0 to 1 that mail to the address bounces. null for now.
statusstringWhat the result means for sending: valid, invalid, catch_all, risky, do_not_mail or unknown.
sub_statusstring | nullWhy, for example role_based, mailbox_full or accept_all. null for a plain valid result.
explanationstringOne fixed English sentence per sub-status that you can show to people.
recommended_actionstringWhat to do: send, send_with_caution, suppress or retry_later.

Three states, 11 reasons

Branch on state in your code and keep reason for your logs and support team. A user who asks “why was my address rejected?” then gets a real answer.

deliverable

The mail server accepts the address. Accept it, but treat low_deliverability and low_quality with care.

valid_mailbox
A valid mailbox that can receive email.
low_deliverability
The domain accepts every address (catch-all), so no single mailbox can be confirmed, or the address is disposable or its mailbox is full.
low_quality
The mailbox exists, but it is a role address such as info@ or support@, often read by several people or by nobody.

undeliverable

Mail will bounce. Block it or ask for a correction.

invalid_format
The address format is invalid.
invalid_mx
MX records are missing or invalid.
invalid_mailbox
The mail server refused the address.
invalid_smtp
Only returned with sandbox keys, for a test address.

unknown

The server could not be asked. Retry later.

no_connect
No connection to the mail server.
timeout
The SMTP connection timed out.
unavailable_smtp
The server did not allow verification.
unexpected_error
An unexpected error occurred.

Full definitions in the /v1/info documentation.

Bulk email verification API

A whole list in one request

POST a JSON array or upload a CSV or TXT file with up to 100,000 addresses (25 MB). The job runs in the background: poll its status or let us call your webhook, then download the results.

  • Only unique, valid addresses are billedDuplicates (ignoring case and surrounding spaces) and empty or malformed rows are free, and a job that needs more than your remaining quota is refused before anything is charged.
  • Refunds for unknown resultsAddresses whose result is unknown are refunded when the job completes, within a fair-use allowance; a failed job is refunded in full.
  • Signed webhookOne POST when the job completes or fails, signed with HMAC-SHA256, with up to six delivery attempts. It carries the job, never the addresses.
  1. queuedAccepted, quota charged
  2. processingChecked per mail server
  3. completedResults ready for 30 days
  4. failedFully refunded
POST /v1/bulk
curl -X POST "https://api.emailvalidation.io/v1/bulk" \
  -H "apikey: YOUR-API-KEY" \
  -F "file=@contacts.csv" \
  -F "email_column=email" \
  -F "webhook_url=https://example.com/hooks/emailvalidation"

201 · job created

{
  "job_id": "629954218123464704",
  "status": "queued",
  "counts": {
    "total": 5,
    "unique": 3,
    "duplicates": 1,
    "invalid": 1,
    …
  },
  "quota": { "charged": 3, "refunded": 0 },
  …
}

Results your way

  • JSON with a row number, the input and 19 result fields per address, including status, sub_status and recommended_action
  • CSV: your original columns plus 18 emailvalidation_* columns
  • Cells starting with = + - or @ are escaped, so the CSV is safe to open in a spreadsheet
  • Download as often as you like until the job expires, or delete it right away

Errors and limits

Latency, rate limits and quota

The SMTP mailbox check waits for the receiving mail server, so a fast server gives you a fast result and a slow one a slow result. Every error has an HTTP status and a code, so your integration can tell a bad request from a full quota.

  • You pay for definitive resultsOnly deliverable and undeliverable results count against your quota. Unknown results and invalid formats are free within a fair-use allowance, and validation errors are free. Status checks, job lists, downloads and deletions are free too.
  • You set the time limitA check takes at most the timeout you send, from 3 to 60 seconds (30 by default). Give your HTTP client a few seconds more. A signup form that must answer quickly can ask for less; if the mail server hasn't answered in time, you get unknown with the reason timeout, free within the fair-use allowance.
  • Check on blur, not on every keystrokeStart the check when the email field loses focus. The result is then often ready before the user clicks submit, and a slow mail server never blocks the signup: accept the address and recheck it later.
  • Checks at the same timeA team runs up to 5 single checks at the same time on the free plan and 25 on paid plans. The next one gets 429 concurrency_limit_exceeded and is not billed.
  • Rate limits in the headersThe free plan allows 10 requests a minute. Responses carry X-RateLimit-Remaining-Quota-Month, and X-Cost shows what a call counted.
StatusMeaning
200Success.
201Bulk job created.
401No API key, or the key is invalid.
403Key not allowed, or plan_upgrade_required for a feature your plan does not include.
404Endpoint or job not found, or results no longer available.
409job_not_completed: results requested before the job finished.
422Validation error; the errors object names the field.
429Rate limit or monthly quota exceeded.
500Internal error on our side. Contact support.

Limits by plan

PlanCredits a monthLimitsAlso included
Free10010 requests a minute, 5 checks at the same time1 API key, no credit card
Small5,000No per-minute limit, 25 checks at the same time1 API key, catch-all detection, audit trail
Medium25,000No per-minute limit, 25 checks at the same time2 API keys, team management, sandbox API keys
Large100,000No per-minute limit, 25 checks at the same time5 API keys, IP and URL whitelisting, overages, custom SLA and integration

Keeping track of quota

  • Only definitive results (deliverable or undeliverable) count. Unknown results are free within a fair-use allowance.
  • In bulk jobs, duplicates and invalid rows are free.
  • For lists, don't loop over /v1/info: send the list to POST /v1/bulk (up to 100,000 addresses per job) and wait for the signed webhook.

Rate limit and quota headers

HeaderMeaning
X-RateLimit-Limit-Quota-MonthYour monthly quota.
X-RateLimit-Remaining-Quota-MonthRequests left this month.
X-RateLimit-Limit-Quota-MinuteRequests allowed per minute, on plans with a minute limit such as the free plan (10).
X-RateLimit-Remaining-Quota-MinuteRequests left in the current minute.
X-CostWhat the call counted against your quota: 1 for a validation, 0 for sandbox requests and free results; for a bulk job, the number of unique valid addresses.
X-RateLimit-Remaining-Overage-MonthOverage left, when overage is enabled and the monthly quota is used up (with X-RateLimit-Limit-Overage-Month).

Official SDKs and integrations

Install a client library or call the REST API directly. Official SDKs for JavaScript, Python, PHP, Ruby, Go, C#, R, Rust and Perl wrap the same call.

JavaScript

npm install @everapi/emailvalidation-js --save

Python

pip install emailvalidationio

PHP

composer require everapi/emailvalidation-php

Official SDKs are also listed for Ruby, Go, C#, R, Rust and Perl.

Code for Python, Node.js and PHP

Each snippet calls the REST endpoint directly, so it runs without an extra dependency. All three follow the same rule: if the check fails or your client times out, let the signup through and recheck the address later. A check takes up to 30 seconds by default, so the client timeout is 35 seconds; send a lower timeout parameter if your form has to answer faster.

Python

import os
import requests

API = "https://api.emailvalidation.io/v1/info"

def check_email(email: str) -> dict | None:
    try:
        r = requests.get(
            API,
            params={"email": email},
            headers={"apikey": os.environ["EMAILVALIDATION_KEY"]},
            timeout=35,
        )
        r.raise_for_status()
        return r.json()
    except requests.RequestException:
        return None  # fail open: accept, recheck later

result = check_email("anna@gmial.com")
if result and result["state"] == "undeliverable":
    suggestion = result.get("did_you_mean")  # suggested correction, if any

Node.js (18+)

async function checkEmail(email) {
  const url =
    "https://api.emailvalidation.io/v1/info?email=" + encodeURIComponent(email);
  try {
    const res = await fetch(url, {
      headers: { apikey: process.env.EMAILVALIDATION_KEY },
      signal: AbortSignal.timeout(35_000),
    });
    if (!res.ok) return null;
    return await res.json();
  } catch {
    return null; // fail open: accept, recheck later
  }
}

const result = await checkEmail("anna@gmial.com");
if (result?.state === "undeliverable") {
  // ask the user to fix the address, suggesting result.did_you_mean if set
}

PHP

function check_email(string $email): ?array {
    $ch = curl_init("https://api.emailvalidation.io/v1/info?email=" . urlencode($email));
    curl_setopt_array($ch, [
        CURLOPT_HTTPHEADER     => ["apikey: " . getenv("EMAILVALIDATION_KEY")],
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT        => 35,
    ]);
    $body = curl_exec($ch);
    $code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);
    if ($body === false || $code !== 200) {
        return null; // fail open: accept, recheck later
    }
    return json_decode($body, true);
}

$result = check_email("anna@gmial.com");
if ($result && $result["state"] === "undeliverable") {
    $suggestion = $result["did_you_mean"] ?? null;
}

Where teams call the API

Check an address at the moment it enters your system, before it costs you a bounce.

Signup forms

Catch typos and throwaway inboxes before the account exists, and suggest the right domain.

Checkout

Make sure order confirmations and invoices reach the buyer.

CRM imports

Keep invalid and role addresses out of your contact database.

Email marketing

Clean lists before a campaign to protect your sender reputation.

API pricing

One validation costs one credit, and prices are public, so you don’t need a sales call. Credits belong to the account, not to each seat, and also pay for the email finder: an email search or a LinkedIn email search uses 10 credits. Yearly billing gives you 2 months free. Prices exclude VAT.

Free

$0/month

100 email validations

Start for free
Small

$9.99/month

5,000 email validations

≈ $0.0020 per validation

Choose Small
MediumMost popular

$34.99/month

25,000 email validations

≈ $0.0014 per validation

Choose Medium
Large

$94.99/month

100,000 email validations

≈ $0.00095 per validation

Choose Large

Cancel any time · Two months free on yearly plans · All prices excl. VAT · Compare all plans

Comparing email validation APIs

When you test providers, check these five things. This page answers all five for emailvalidation.io.

  1. One call or several. Does a single request return the syntax, MX, SMTP, disposable, role and catch-all results?
  2. Machine-readable reasons. Do you get a reason code your code can branch on, or only a label?
  3. What uses a credit. Do unknown results, duplicates and failed calls count against your quota?
  4. Where the checks run. Where is the data processed, and what does that mean for GDPR?
  5. Published prices. Can you see the price without a sales call?

To see how other providers handle them, read our comparisons:

Email validation API FAQ

Short answers to what developers ask before they integrate.

Is the email validation API free?

Yes, to start. The free plan includes 100 credits a month (one per validation) at up to 10 requests a minute, with 1 API key and no credit card. Paid plans start at $9.99 a month for 5,000 credits.

What is a real-time email validation API?

An endpoint you call while an address is being entered, for example at signup, at checkout or during a CRM import. It returns a verdict in the same request, so you catch a bad address before it reaches your database. Here, that endpoint is GET /v1/info.

How does the API check an address without sending an email?

It checks the syntax, looks up the domain’s MX records and asks the receiving mail server over SMTP whether it would accept the mailbox. The conversation ends before any message is sent.

How long does a check take?

It depends mostly on how fast the receiving mail server answers the SMTP check. A check takes at most the timeout you send, from 3 to 60 seconds (30 by default). If the server hasn’t answered by then, you get unknown with the reason timeout, which is free within the fair-use allowance.

What are the rate limits?

The free plan allows 10 requests a minute and 5 checks at the same time. Paid plans have no per-minute limit and allow 25 checks at the same time. For whole lists, use the bulk endpoint instead of many single calls.

Which response field should my code check?

Use state to accept or reject an address, reason for your logs, score (0 to 1) to rank or segment addresses, and did_you_mean to suggest a typo fix.

What does a catch-all result mean?

Some domains accept mail for every address, so the mailbox check cannot confirm one person. For domains we already know to be catch-all, we skip the mailbox check, and the address comes back as deliverable with the reason low_deliverability, so you can treat it separately. Send catch_all=1 (Small plan or higher) and the catch_all field tells you whether the domain is catch-all; without it the field is null.

Can I validate a whole list through the API?

Yes. POST /v1/bulk takes a JSON array or a CSV or TXT file with up to 100,000 addresses. Only unique, valid addresses are billed, and you get the results as JSON or as your CSV with the result columns added.

Which programming languages can I use?

Any language that can send an HTTPS request. There are official SDKs for JavaScript, Python and PHP, and SDKs are also listed for Ruby, Go, C#, R, Rust and Perl.

Do failed requests count against my quota?

No. Only definitive results (deliverable or undeliverable) count. Unknown results and addresses with an invalid format are free within a fair-use allowance, validation errors are not charged, and in a bulk job, addresses whose result is unknown are refunded when the job completes.

Is an email verification API the same as an email validation API?

Yes. Email validation API, email verification API and email checker API are names for the same thing: an API that tells you whether an address is valid and will receive mail. This one checks the syntax, the domain and its MX records and the mailbox over SMTP, and flags disposable, role and free-provider addresses. How it compares with ZeroBounce, NeverBounce and Kickbox is in our comparison of email validation APIs.

What if I need more credits than my plan includes?

The Large plan supports overages. On the other plans, you can move up a plan at any time: Small has 5,000 credits, Medium 25,000 and Large 100,000. For more than 100,000 checks a month, ask about a custom plan.

Can AI agents use the API?

Yes. Claude, Cursor and other MCP clients can check addresses through the emailvalidation.io MCP server at https://api.emailvalidation.io/mcp. See MCP setup.

Does the API validate phone numbers?

No, it checks email addresses only. For phone numbers, see numlookupapi, a sister product in the everapi family.

What happens when I reach my monthly quota?

Once any grace or overage quota is used up too, further requests return 429 until the quota resets at the start of your next billing month, or until you upgrade. The X-RateLimit-Remaining-Quota-Month header shows how many requests you have left, so your code can see it coming.

Is the API GDPR compliant?

We process your data in line with the GDPR. The API and every email check run on our own servers in Germany. Requests reach them through Cloudflare, which also stores uploaded lists. Our list of sub-processors names every provider that processes your data and where, and our Trust Center shows the security measures in place.

Start validating emails for free

100 free validations every month. No credit card required. Upgrade when you need more.