DEV Community

Cover image for Email Validation That Actually Works
APIVerve
APIVerve

Posted on • Originally published at blog.apiverve.com

Email Validation That Actually Works

Startups burn through $40,000+ in email marketing costs sending campaigns to addresses that don't exist. It happens more often than you'd think.

Not spam. Not unsubscribes. Just... bounces. Thousands of them. Sender reputation tanks so hard that eventually emails to real customers start landing in spam folders. The whole domain gets flagged.

All because their signup form accepted anything that looked vaguely email-shaped.

This happens more than you'd think. And it's completely preventable.

The Regex Trap

Every developer's first instinct is regex. You google "email validation regex," you find something like this on Stack Overflow:

const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;

if (emailRegex.test(email)) {
  // "valid" email
}
Enter fullscreen mode Exit fullscreen mode

Here's what this catches: whether there's an @ symbol with stuff on both sides and a dot somewhere after it.

Here's what it doesn't catch:

  • test@doesnotexist.invalid — Perfect format. Domain doesn't exist.
  • nobody@gmail.con — That's not gmail.com. Typo.
  • temp@10minutemail.com — Real email. Abandoned in 10 minutes.
  • support@myspace.com — Valid domain. Mailbox might not exist.

The regex validates format. It doesn't validate reality.

I've seen production systems running the "official" RFC 5322 email regex—all 6,300 characters of it—and still letting through garbage because technical validity isn't the same as practical validity.

What Actually Matters

When someone gives you an email address, you need to know three things:

1. Can mail be delivered there?

Does the domain exist? Does it have MX records (mail server configuration)? Can you actually connect to that mail server? These are real network checks, not pattern matching.

2. Is the mailbox real?

Some mail servers will tell you if a specific address exists. Not all do—Gmail won't, for privacy reasons—but many corporate mail servers will reject invalid addresses at the SMTP level.

3. Is it a throwaway?

Guerrilla Mail. 10 Minute Mail. Mailinator. Thousands of services exist specifically to give people disposable addresses. If someone's using one, they're probably not a real lead.

None of this is possible with regex.

How Real Validation Works

const response = await fetch(
  `https://api.apiverve.com/v1/emailvalidator?email=${encodeURIComponent(email)}`,
  { headers: { 'x-api-key': 'YOUR_API_KEY' } }
);

const { data } = await response.json();
Enter fullscreen mode Exit fullscreen mode

One call. Here's what comes back:

{
  "status": "ok",
  "data": {
    "email": "john.doe@acme-corp.com",
    "domain": "acme-corp.com",
    "username": "john.doe",
    "isValid": true,
    "isRegexValid": true,
    "isMxValid": true,
    "isSmtpValid": true,
    "canConnect": true,
    "hasTypo": false,
    "isCompanyEmail": true,
    "isFreeEmail": false,
    "smtp": {
      "valid": true,
      "reason": "Connected"
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Let's break down what each of these tells you.

isRegexValid

Yes, the API does the regex check too. You get it for free. But this is just the first gate, not the final answer.

isMxValid

Does this domain have MX records? MX records tell the internet where to deliver mail for a domain. No MX records = domain doesn't receive email = fake address.

This catches all those @doesnotexist.invalid addresses instantly.

isSmtpValid and canConnect

Can we actually reach the mail server and talk to it? Some domains have MX records pointing to servers that don't respond. Maybe they're misconfigured. Maybe they went out of business. Either way, you can't deliver mail there.

hasTypo

This is underrated. The API knows common email domains and catches typos:

  • gmial.com → probably meant gmail.com
  • yaho.com → probably meant yahoo.com
  • hotmal.com → probably meant hotmail.com

Instead of bouncing their first email and losing the user forever, you can prompt: "Did you mean @gmail.com?"

This single field probably saves more signups than everything else combined.

isCompanyEmail vs isFreeEmail

Here's where it gets interesting for B2B.

If someone signs up with jane@bigcorp.com, they're probably from BigCorp. That's a sales lead.

If someone signs up with randomuser847@gmail.com, they're... someone with a Gmail account. Could be a tire-kicker. Could be a student. Could be the CEO of a company who just prefers Gmail.

You shouldn't reject free email addresses. But you might want to:

  • Route company emails to sales immediately
  • Ask free email users for more context
  • Prioritize company emails in your outreach

This field lets you segment automatically.

The Disposable Email Problem

Valid emails aren't all created equal.

const dispResponse = await fetch(
  `https://api.apiverve.com/v1/emaildisposablechecker?email=${encodeURIComponent(email)}`,
  { headers: { 'x-api-key': 'YOUR_API_KEY' } }
);

const { data } = await dispResponse.json();

if (data.isDisposable) {
  // This address will be abandoned in minutes
}
Enter fullscreen mode Exit fullscreen mode

Disposable email services are popular because they work. Need to download a whitepaper without getting spammed? 10minutemail.com. Signing up for a free trial you'll never use? guerrillamail.com.

The Disposable Email Checker API knows about thousands of these services—and the list grows constantly because new ones pop up all the time.

Should you block them? Depends on your business.

Block if: You're collecting leads for sales, offering limited free trials, or building anything where fake signups hurt you (abuse, fraud, gaming free tiers).

Allow with caution if: You just need a working email for transactional messages. The address might be temporary, but it works right now.

Don't block if: You're running a privacy-focused service where you actually want to let people stay anonymous.

Most B2B SaaS should probably block or at least flag disposable addresses. Your "10,000 free users" aren't impressive if 8,000 of them are the same person rotating through temporary emails.

Putting It All Together

Here's a complete validation function that handles everything:

async function validateEmail(email) {
  const headers = { 'x-api-key': process.env.APIVERVE_KEY };

  // Step 1: Validate the email itself
  const validRes = await fetch(
    `https://api.apiverve.com/v1/emailvalidator?email=${encodeURIComponent(email)}`,
    { headers }
  );
  const { data: validity } = await validRes.json();

  // Hard failures
  if (!validity.isValid || !validity.isMxValid) {
    return {
      valid: false,
      reason: 'invalid',
      message: "That email address doesn't look right. Double-check it?"
    };
  }

  // Typo detection
  if (validity.hasTypo) {
    // In a real app, you'd suggest the correction
    // The domain tells you what they probably meant
    return {
      valid: false,
      reason: 'typo',
      message: `Did you mean @${validity.domain.replace(/gmial|gmai(?!l)|yaho(?!o)|hotmal(?!l)/, match => {
        const fixes = { 'gmial': 'gmail', 'gmai': 'gmail', 'yaho': 'yahoo', 'hotmal': 'hotmail' };
        return fixes[match] || match;
      })}?`,
      originalDomain: validity.domain
    };
  }

  // Step 2: Check for disposable addresses
  const dispRes = await fetch(
    `https://api.apiverve.com/v1/emaildisposablechecker?email=${encodeURIComponent(email)}`,
    { headers }
  );
  const { data: disposable } = await dispRes.json();

  if (disposable.isDisposable) {
    return {
      valid: false,
      reason: 'disposable',
      message: "Please use a permanent email address."
    };
  }

  // Everything checks out
  return {
    valid: true,
    isCompanyEmail: validity.isCompanyEmail,
    isFreeEmail: validity.isFreeEmail,
    domain: validity.domain,
    deliverable: validity.isSmtpValid
  };
}
Enter fullscreen mode Exit fullscreen mode

Now your signup form can give actually helpful feedback:

const result = await validateEmail(userInput);

if (!result.valid) {
  showError(result.message);
  return;
}

if (result.isCompanyEmail) {
  // Flag for sales team
  await tagLead(email, 'company-email');
}

// Continue with signup
Enter fullscreen mode Exit fullscreen mode

When to Validate

Don't validate on every keystroke. That's annoying and expensive.

Validate on blur (when they leave the field). They've finished typing, now check it.

Or validate on submit. The whole form at once.

Client-side first, always. Before burning an API credit, do a basic sanity check:

emailInput.addEventListener('blur', async (e) => {
  const email = e.target.value.trim();

  // Quick local checks first
  if (!email) return;
  if (!email.includes('@')) {
    showError("That doesn't look like an email address");
    return;
  }

  // Now the real validation
  setLoading(true);
  const result = await validateEmail(email);
  setLoading(false);

  if (!result.valid) {
    showError(result.message);
  } else {
    clearError();
  }
});
Enter fullscreen mode Exit fullscreen mode

This way you're not burning credits validating empty strings or asdf.

The Business Impact

Let me get concrete about why this matters.

Deliverability Math

Email deliverability is a numbers game. Mailbox providers (Gmail, Outlook, Yahoo) track your bounce rate. Too many bounces? You get flagged.

Industry benchmarks say keep your bounce rate under 2%. That means if you send 1,000 emails, fewer than 20 should bounce.

Without validation, I've seen bounce rates hit 15-20% on cold outreach. That's not just wasted emails—it's actively destroying your sender reputation.

The Cost of Bad Data

Let's say you're paying $0.001 per email sent (pretty standard for transactional email at scale).

Send 100,000 emails with a 15% invalid rate = 15,000 bounces = $15 wasted directly, plus:

  • Damage to sender reputation (unmeasurable but significant)
  • Lost legitimate emails that land in spam
  • Time debugging why engagement dropped

Validating those 100,000 emails upfront at 1 credit each costs... let's call it $10 on APIVerve's pricing. You're paying $10 to save $15+ and protect your reputation.

The math gets more dramatic at scale.

Conversion Rates

This is the hidden cost nobody talks about.

User signs up with john@gmial.com. You send them a welcome email. It bounces. They never come back because they think you ghosted them.

That's not a bad email address. That's a typo. The user wanted to sign up. The hasTypo check catches this and lets you prompt for correction instead of losing the customer.

I don't have exact numbers—nobody does—but fixing typos at signup almost certainly moves your conversion rate by meaningful percentage points.

Caching Validation Results

You don't need to re-validate the same email every time.

const emailCache = new Map();

async function validateEmailCached(email) {
  const normalized = email.toLowerCase().trim();

  if (emailCache.has(normalized)) {
    const cached = emailCache.get(normalized);
    if (Date.now() < cached.expiresAt) {
      return cached.result;
    }
  }

  const result = await validateEmail(normalized);

  // Cache for 24 hours
  emailCache.set(normalized, {
    result,
    expiresAt: Date.now() + (24 * 60 * 60 * 1000)
  });

  return result;
}
Enter fullscreen mode Exit fullscreen mode

Email validity doesn't change every second. Caching for a day is fine. Caching for a week is probably fine. An email that was valid yesterday is almost certainly still valid today.

When Not to Block

A few situations where you might want to accept questionable emails anyway:

Password reset flows. If someone's trying to reset their password, you want them to get the email even if it looks sketchy. Don't lock people out of their accounts because their email domain is weird.

Transactional receipts. They bought something, they get a receipt. Even if it bounces, you tried.

Account recovery. Similar to password reset. Be lenient when users are already frustrated.

Validation is for new data coming in. Existing users who've proven they receive email shouldn't be re-challenged.

What I'd Actually Build

If I were starting a SaaS today, here's my email validation setup:

  1. Basic regex on the frontend to catch obvious garbage
  2. Email Validator API call on blur or submit
  3. Typo correction — prompt users to fix instead of rejecting
  4. Disposable Email Checker to block throwaway signups
  5. isCompanyEmail flag piped to CRM for sales prioritization
  6. 24-hour caching of validation results
  7. Monitoring of bounce rates to catch issues early

That's maybe 50 lines of code and completely transforms your data quality.


Email validation isn't glamorous. Nobody brags about it at conferences. But it's one of those quiet infrastructure decisions that pays dividends forever.

The Email Validator API and Disposable Email Checker are both available on all APIVerve plans, including free. You can have this running in your app today.

Stop letting fake emails through. Your sender reputation will thank you.


Originally published at APIVerve Blog

Top comments (0)