DEV Community

George Kioko
George Kioko

Posted on

Why Regex Email Validation Is Lying to You (And What Actually Works)

If you validate emails with regex, you are checking if a string looks like an email. You are not checking if anyone will receive your message.

I learned this the hard way. 12% bounce rate on a 5,000 email campaign. Sender reputation tanked. Half the "valid" emails were dead mailboxes that regex happily approved.

here is what actually works and why the difference matters.

What regex checks

/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/
Enter fullscreen mode Exit fullscreen mode

This tells you the string has an @ symbol, a dot, and some characters around them. That is it.

totally.fake.person@nonexistent-domain-12345.com passes regex. Nobody will ever receive that email.

What SMTP verification checks

SMTP verification actually talks to the mail server. It connects on port 25, introduces itself with EHLO, then asks "would you accept mail for this address?" The server responds with a code:

  • 250 = yes, this mailbox exists
  • 550 = no, user unknown
  • 252 = catch all (accepts everything)

This is the same protocol your email client uses to send mail. You are just stopping before actually delivering anything.

The 5 layers of real validation

I built an email validator that runs 5 checks in sequence:

Layer 1: Format check. Yes, regex. But just as a first filter to reject obvious garbage.

Layer 2: Domain check. Does the domain have MX records? If there are no mail servers configured, nobody is receiving email there. dig MX example.com tells you instantly.

Layer 3: Disposable detection. Is this mailinator, guerrillamail, tempmail? I maintain a list of 400+ disposable domains. These addresses work for about 10 minutes then disappear.

Layer 4: Role detection. admin@, info@, support@ are role addresses. They usually go to a shared inbox that nobody monitors for cold outreach.

Layer 5: SMTP handshake. The real check. Connect to the MX server, ask if the mailbox exists. This catches the dead addresses that everything else misses.

What this looks like in practice

Input: hello@stripe.com

{
  "email": "hello@stripe.com",
  "valid": true,
  "format_valid": true,
  "mx_found": true,
  "smtp_check": "valid",
  "is_disposable": false,
  "is_free": false,
  "is_role_based": false,
  "domain": "stripe.com",
  "mx_records": [
    {"priority": 10, "exchange": "aspmx.l.google.com"}
  ],
  "score": 100
}
Enter fullscreen mode Exit fullscreen mode

Input: test@mailinator.com

{
  "email": "test@mailinator.com",
  "valid": false,
  "format_valid": true,
  "mx_found": true,
  "smtp_check": null,
  "is_disposable": true,
  "score": 40,
  "reason": "Disposable email address"
}
Enter fullscreen mode Exit fullscreen mode

The disposable check caught it before we even bothered with SMTP.

The bounce rate difference

Before SMTP validation: 12% bounce rate, emails landing in spam, sender score dropping.

After: under 2% bounce rate. Same email copy, same sending infrastructure. The only change was filtering out dead addresses before hitting send.

Cost comparison

Method Cost per 1,000 emails Accuracy
Regex only Free ~60% (misses dead mailboxes)
ZeroBounce $1.60 ~95%
Hunter.io $3.00 ~93%
NeverBounce $3.00 ~96%
This API $2.00 ~98% (real SMTP)

Try it

The validator is on Apify Store with a free tier: Email Validator API

Also available on RapidAPI if you prefer REST.

Python quickstart

from apify_client import ApifyClient

client = ApifyClient("YOUR_TOKEN")
run = client.actor("george.the.developer/email-validator-api").call(
    run_input={"email": "hello@stripe.com"}
)

result = client.dataset(run["defaultDatasetId"]).list_items().items[0]
print(f"Valid: {result['valid']}, Score: {result['score']}")
Enter fullscreen mode Exit fullscreen mode

curl

curl "https://george-the-developer--email-validator-api.apify.actor/validate?email=hello@stripe.com" \
  -H "Authorization: Bearer YOUR_TOKEN"
Enter fullscreen mode Exit fullscreen mode

I build data tools. 57 actors on Apify Store, 869 users. Follow the build log at @ai_in_it on X.

Top comments (0)