Every signup form has the same quiet problem: people type email addresses wrong, or on purpose.
You get [email protected]. You get test@test. You get a throwaway address from a disposable inbox that will be gone in ten minutes. Then you send a welcome email, it bounces, your sender reputation drops, and the real user never hears from you.
A regex does not fix this. This guide shows what proper email validation checks, why each check matters, and how to run them all with one API call.
Why a regex is not email validation#
The usual regex answers one question: does this string look like an email address? That is useful for instant feedback in the form. It is nowhere near enough for the server.
All of these pass a typical regex and are still bad:
[email protected]— a typo for gmail.com[email protected]— the domain is not real[email protected]— a disposable inbox[email protected]— a shared role address, rarely a real person
Email validation is a stack of checks, each catching a different kind of bad address.
The five checks that matter#
1. Syntax#
Does the address follow the rules: one @, a valid local part, a valid domain? This is the check a regex does. It is cheap, so do it first, and do it again on the server.
2. Domain exists#
Does the part after the @ resolve in DNS at all? Fake and misspelled domains fail here.
3. MX records#
An MX record tells the world which servers accept mail for a domain. No MX record means mail has nowhere to go. This single check removes a large share of made-up addresses. You can read the details in the MX record explainer on Cloudflare.
4. Disposable and role addresses#
Disposable providers give out inboxes that live for minutes. People use them to get past your signup wall, and you can never reach them again. Role addresses such as info@, admin@ and support@ are shared mailboxes. You may still want them, but you should know when you have one.
5. Typo suggestions#
If the domain looks like a misspelling of a popular provider, ask the user: "Did you mean [email protected]?" This recovers real users who would otherwise never get your email.
Validate an email with one API call#
You can build these checks yourself, but keeping a disposable-domain list current and handling DNS edge cases is real maintenance. The Email Validation API on APIHiver runs all five checks in one request and returns a score.
Get a key first: create a free APIHiver account, open the API and subscribe to the Basic plan, which is free and includes 500 requests a month. Your key goes in the X-API-Key header.
cURL#
curl "https://email-validator.p.apihiver.com/v1/[email protected]" \
-H "X-API-Key: YOUR_API_KEY"What comes back#
{
"email": "[email protected]",
"score": 95,
"domain": "gmail.com",
"valid_syntax": true,
"mx_found": true,
"mx_records": [
"gmail-smtp-in.l.google.com",
"alt1.gmail-smtp-in.l.google.com",
"alt2.gmail-smtp-in.l.google.com"
],
"disposable": false,
"role_account": true,
"free_provider": true,
"deliverable": "likely",
"did_you_mean": null
}The fields map straight onto the checks above:
| Field | Meaning |
|---|---|
valid_syntax | The address is well formed |
mx_found | The domain has mail servers |
disposable | A throwaway provider |
role_account | info@, support@ and similar shared addresses |
free_provider | Gmail, Outlook and other free providers |
deliverable | likely, unknown or no |
did_you_mean | A suggested fix when the domain looks mistyped |
score | 0–100 summary of the above |
Node.js example#
Run the check on your server when the user submits the form, never only in the browser.
async function checkEmail(email) {
const url = new URL("https://email-validator.p.apihiver.com/v1/validate");
url.searchParams.set("email", email);
const res = await fetch(url, {
headers: { "X-API-Key": process.env.APIHIVER_KEY },
signal: AbortSignal.timeout(5000),
});
if (!res.ok) throw new Error(`Validation failed: ${res.status}`);
return res.json();
}
export async function signup(email) {
const v = await checkEmail(email);
if (!v.valid_syntax || v.deliverable === "no") {
return { ok: false, error: "That email address doesn't look right." };
}
if (v.disposable) {
return { ok: false, error: "Please use a permanent email address." };
}
if (v.did_you_mean) {
return { ok: false, error: `Did you mean ${v.did_you_mean}?` };
}
// continue creating the account
return { ok: true };
}Python example#
import os
import requests
def check_email(email: str) -> dict:
r = requests.get(
"https://email-validator.p.apihiver.com/v1/validate",
params={"email": email},
headers={"X-API-Key": os.environ["APIHIVER_KEY"]},
timeout=5,
)
r.raise_for_status()
return r.json()
result = check_email("[email protected]")
if result["disposable"]:
print("Blocked: disposable address")Clean an existing list in bulk#
Have a list of old signups to scrub? The batch endpoint checks up to 100 addresses per call.
curl -X POST "https://email-validator.p.apihiver.com/v1/validate/batch" \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"emails": ["[email protected]", "bad@"]}'Each item comes back in results in the same shape as a single check, so bad@ returns valid_syntax: false and deliverable: "no".
Catch typos while the user is still typing#
For a friendlier form, call the suggest endpoint as soon as the user leaves the email field:
curl "https://email-validator.p.apihiver.com/v1/[email protected]" \
-H "X-API-Key: YOUR_API_KEY"{ "email": "[email protected]", "suggestion": "[email protected]" }Show the suggestion as a one-click fix. It costs one request and saves a user.
Stop duplicate accounts from Gmail tricks#
Gmail ignores dots in the local part and everything after a +. So [email protected] and [email protected] reach the same inbox, which makes it easy to create many accounts for free trials.
The normalise endpoint returns the canonical form:
curl "https://email-validator.p.apihiver.com/v1/[email protected]" \
-H "X-API-Key: YOUR_API_KEY"{
"email": "[email protected]",
"changed": true,
"normalized": "[email protected]",
"had_plus_tag": true
}Store the normalized value in a unique column and compare against it, and duplicates stop at the database.
What validation cannot do#
Be honest with yourself about the limits:
- No tool can promise an inbox exists. Many mail servers accept any address or refuse to confirm. That is why the
deliverablefield sayslikely, notyes. - Validation is not consent. For anything important, still send a confirmation link.
- Keep the browser check as well. A light regex or the browser's
type="email"input gives instant feedback. The API check is for the server.
Pricing and limits#
The Email Validation API on APIHiver has a free Basic plan (500 requests a month, 2 requests per second), and paid plans as you grow:
| Plan | Price | Requests per month | Rate limit |
|---|---|---|---|
| Basic | Free | 500 | 2 per second |
| Pro | ₹299 / month | 10,000 | 5 per second |
| Ultra | ₹999 / month | 50,000 | 10 per second |
| Mega | ₹2,499 / month | 200,000 | 20 per second |
Cache results for a few hours when you can: the same address rarely changes status, and caching cuts your request count.
Next steps#
- Open the Email Validation API and try it live in the playground, no code needed.
- Pair it with the Disposable Email Detection API if you only need the throwaway check.
- Validating phone numbers too? See the Phone Number Validation API.
- Browse every API on APIHiver and call them all with one key.
- What Is a REST API?: new to APIs? Start with this plain-English guide.