Giggal.ai

Developer Hub / Email validation in JavaScript

Email Validation in JavaScript: Regex, HTML5 and MX Checks

How to validate an email address in JavaScript, step by step. We tested three common email regex patterns on 18 real addresses, so you can see exactly what each one accepts and rejects. Then we add the HTML5 email input, a server-side MX lookup in Node.js, and the point where a regex is no longer enough.

Tested with Node.js 26 on 21 October 2026. Every code sample on this page runs as shown.

On this page
  1. The three layers of email validation
  2. Three email regex patterns for JavaScript
  3. Test results: 18 addresses, 3 patterns
  4. Validate email with the HTML5 input
  5. A complete form validation example
  6. Check the domain's MX records in Node.js
  7. When a regex is not enough
  8. FAQ

The three layers of email validation

"Validate an email address" can mean three different checks. Each one catches different problems:

  1. Format. Does the text look like an email address? A regex or the HTML5 email input does this. It catches typing mistakes like name@gmailcom.
  2. Domain. Can the domain receive email? A DNS lookup of the domain's MX records does this. It catches domains that do not exist.
  3. Mailbox. Does this exact mailbox exist? Only an SMTP check against the mail server can answer this. It catches addresses like old.employee@realcompany.com, which pass the first two checks and still bounce.

JavaScript in the browser can only do layer 1. Node.js on a server can do layers 1 and 2. Layer 3 needs outbound connections on port 25, which most cloud hosts block, so it is usually done through an email verification API.

Three email regex patterns for JavaScript

Below are three patterns you can use for email validation with regex in JavaScript, from the shortest to the strictest. All three work with pattern.test(email).

Pattern 1: the short pattern

This is the pattern you will see in most answers online. It checks for one @, no spaces, and a dot after the @.

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

Pattern 2: the HTML standard pattern

The HTML standard defines the pattern that browsers use for <input type="email">. It is stricter about which characters are allowed and checks each part of the domain.

const html5 = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/;

Pattern 3: the practical pattern

This version starts from the HTML standard pattern and adds four rules that real mail servers apply: no dot at the start or end of the local part, no two dots in a row, at least one dot in the domain, and a top-level domain of at least two letters.

const practical = /^(?!\.)(?!.*\.\.)[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+(?<!\.)@(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,63}$/;

function isValidEmailFormat(email) {
  return practical.test(email.trim());
}

The (?<!\.) part is a lookbehind. It works in every current browser and in Node.js.

Test results: 18 addresses, 3 patterns

We ran each pattern on the same 18 addresses. A green "yes" means the pattern accepts the address.

AddressShortHTML5PracticalShould it pass?
jane.smith@example.comyesyesyesYes
o'brien@example.co.ukyesyesyesYes, apostrophes are allowed
name+news@gmail.comyesyesyesYes, plus tags are allowed
user@sub.example.ioyesyesyesYes
plainaddressnononoNo
name@gmailcomnoyesnoNo, missing dot
name@@gmail.comnononoNo
name @gmail.comnononoNo, contains a space
.jane@example.comyesyesnoNo, starts with a dot
jane.@example.comyesyesnoNo, dot before the @
jane..smith@example.comyesyesnoNo, two dots in a row
jane@example..comyesnonoNo
jane@-example.comyesnonoNo, domain starts with a hyphen
user@localhostnoyesnoNot for a public signup form
jane@example.cyesyesnoNo, one-letter ending
jane@exa_mple.comyesnonoNo, underscore in domain
"quoted name"@example.comnononoValid in the email standard, but rare
jürgen@example.deyesnonoValid only on servers that support international addresses

What the results show:

Validate email with the HTML5 input

The simplest browser check needs no JavaScript at all:

<input type="email" name="email" required autocomplete="email">

The browser blocks the form and shows a message if the format is wrong. In JavaScript you can ask the input directly with input.checkValidity(), or read input.validity.typeMismatch.

Two things to know. First, the browser uses the HTML standard pattern, so it accepts name@gmailcom, as the table shows. Add a pattern attribute if you want the stricter rule. Second, anyone can bypass browser checks by sending the request directly, so always validate again on the server.

A complete form validation example

This example combines the HTML5 input with the practical pattern, trims spaces, and shows a clear message:

<form id="signup" novalidate>
  <label for="email">Email</label>
  <input id="email" type="email" name="email" required autocomplete="email">
  <p id="email-error" role="alert"></p>
  <button type="submit">Sign up</button>
</form>

<script>
const practical = /^(?!\.)(?!.*\.\.)[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+(?<!\.)@(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,63}$/;

document.getElementById('signup').addEventListener('submit', (event) => {
  const input = document.getElementById('email');
  const error = document.getElementById('email-error');
  const email = input.value.trim();

  if (!email) {
    error.textContent = 'Please enter your email address.';
  } else if (!practical.test(email)) {
    error.textContent = 'Please check your email address. It looks incomplete.';
  } else {
    error.textContent = '';
    return; // format is fine: let the form submit, and verify again on the server
  }
  event.preventDefault();
});
</script>

Check the domain's MX records in Node.js

On the server, Node.js can look up the domain's mail servers with the built-in dns module. No package is needed.

import { promises as dns } from 'node:dns';

async function domainAcceptsMail(email) {
  const domain = email.split('@').pop().toLowerCase();
  try {
    const records = await dns.resolveMx(domain);
    // A "null MX" (RFC 7505) means the domain accepts no mail at all.
    const usable = records.filter(r => r.exchange && r.exchange !== '.');
    return usable.length > 0;
  } catch (err) {
    if (err.code === 'ENOTFOUND' || err.code === 'ENODATA') return false;
    throw err; // timeouts and server errors: treat as unknown, not invalid
  }
}

Our test results:

AddressResultWhy
jane@gmail.comtruegmail.com has MX records
jane@gmial.comfalseThe typo domain has no MX records
jane@example.comfalseexample.com publishes a null MX: it accepts no mail
jane@this-domain-does-not-exist-91827.comfalseThe domain does not exist

One detail: the email standard (RFC 5321) lets a sending server fall back to a domain's A record when there are no MX records. This function treats "no MX" as invalid, which is stricter than the standard but catches typo domains like gmial.com. That domain has a website address record but no mail servers.

When a regex is not enough

A perfect format and a working domain still do not prove the mailbox exists. These addresses pass every check on this page and can still bounce:

To confirm the mailbox itself, call an email verification API from your server after the format check passes. It runs the SMTP check and handles catch-all domains. The free email verification API on this hub includes 1,000 credits, and the call takes a few lines:

const res = await fetch('https://api.giggal.ai/v1/verify', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${process.env.GIGGAL_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ email }),
});
const { data } = await res.json();
// data.status: deliverable, undeliverable or unknown

Want to check a single address by hand first? Paste it into the free email verifier.

Frequently asked questions

What is the best regex for email validation in JavaScript?

For most forms, use the pattern from the HTML standard, which is what browsers use for type="email", and add a check for a dot in the domain. The practical pattern above does this and passed every case in our test. A regex can only check format. It cannot tell you whether the mailbox exists.

Can JavaScript check if an email address really exists?

Not in the browser. Server-side JavaScript can look up the domain's MX records, but confirming a mailbox needs an SMTP check, which most hosting networks block on port 25. An email verification API runs that check for you.

Does input type="email" validate email addresses?

It checks the format in the browser using the HTML standard's pattern. It accepts addresses without a dot in the domain, such as user@localhost, and it can be bypassed, so always validate again on the server.

Should I validate email on the client or the server?

Both. Validate in the browser to give people instant feedback, and validate again on the server, because browser checks can be skipped.

Why does my regex reject valid addresses?

Common causes are rejecting the plus sign, apostrophes or long top-level domains such as .technology. Test your pattern against real customer addresses before you ship it.