Developer resources

How to validate emails in a JavaScript signup form (properly)

Most signup forms use a regex check that catches typos but misses 90% of bad emails. Here is the real validation pattern with code.

AD

Admin

May 30, 2026 · 3 min read

Almost every signup form on the web does the same thing: it runs a regex against the email field, accepts if it matches, rejects if not. That catches typos but lets through disposable, role-based, and non-existent addresses. Here is how to do real validation in a JavaScript signup form.

Why regex is not enough

The classic regex check looks like this:

const isValid = /^[\w\.-]+@[\w\.-]+\.\w+$/.test(email);

It passes fake@mailinator.com. It passes doesntexist@acme.com. It passes any catch-all. All you have confirmed is that the user typed an at-sign and a dot.

The three-step pattern

Real validation runs in three stages:

  1. Frontend regex on blur or keystroke. Catches typos as the user types.
  2. Frontend disposable-domain quick check (optional, gives instant feedback for obvious bad domains).
  3. Backend full verification on form submit before account creation.

Step 1: The frontend pattern

const emailInput = document.querySelector('input[name=email]');
const submit = document.querySelector('button[type=submit]');
const errorEl = document.querySelector('.email-error');

emailInput.addEventListener('blur', () => {
    const value = emailInput.value.trim().toLowerCase();
    const re = /^[a-zA-Z0-9._+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
    if (!re.test(value)) {
        errorEl.textContent = 'Please enter a valid email address.';
        return;
    }
    errorEl.textContent = '';
});

This handles the obvious bad inputs without any network call. Fast, free, blocks typos in real time.

Step 2: The backend verification

When the user submits, your backend calls the verification API before creating the account.

// server-side, Node.js example
app.post('/signup', async (req, res) => {
    const email = req.body.email.trim().toLowerCase();

    const verifyRes = await fetch('https://mailoclean.com/api/v1/verify', {
        method: 'POST',
        headers: {
            'Authorization': `Bearer ${process.env.MAILOCLEAN_KEY}`,
            'Content-Type': 'application/json',
        },
        body: JSON.stringify({ email }),
    });

    const data = await verifyRes.json();

    if (data.status === 'invalid' || data.status === 'disposable') {
        return res.status(422).json({
            error: 'Please use a valid, permanent email address.'
        });
    }

    // Create the account
    const user = await createUser({ email, ...req.body });
    return res.json({ user });
});

What to do with each status

  • valid: create the account.
  • invalid: reject with a clear error message.
  • disposable: reject and ask for a permanent email.
  • catch_all: accept but flag for engagement monitoring.
  • role_based: accept, optionally with a soft warning ("we recommend using a personal email").
  • unknown: accept by default. The verifier could not reach the server; do not lock real users out for a network blip.

UX tips

  • Show the spinner on the submit button while verification runs. It typically takes 1 to 2 seconds.
  • Never validate on every keystroke. Validate on blur (frontend) and on submit (backend).
  • Always show a friendly error, not a technical one. "Please use a different email" beats "verifier returned status: disposable".
  • Let users override. If they insist their address is real, accept with a flag, and chase deliverability with engagement data.

FAQ

Can I do verification entirely in the browser?

No. The API key would be exposed to anyone viewing the page. Always proxy through your backend.

How fast is the verification call?

Median 1.4 seconds. Add an obvious loading state and users will not notice.

What if MailoClean is down?

The MailoClean API has 99.9%+ uptime, but build for the rare exception: timeout the verification at 5 seconds and accept the signup with a "needs reverify" flag, then reverify in a background job within the hour.

Ship validation that actually works

Grab an API key and copy the snippet above. Five minutes from copy to production.

Ready to try MailoClean?

Clean your list and start sending with confidence.

Free verifications included with every account. Credits never expire.

AD

Admin

Email deliverability writer at MailoClean

Back to all posts

Keep reading

Related posts

Developer resources

Validate emails in Python, Flask, and Django

Python has good built-in tools for email validation, but none of them actually verify the mailbox. Here is the upgrade with Flask and Django examples.

Jun 1, 2026 · 3 min read