Tutorial · HTML forms

HTML email validator: what type="email" accepts and rejects

Every browser ships an email validator: <input type="email">. Here is the exact rule it applies, what it lets through, how to tighten it with pattern, and why the server still has to check.

Updated October 10, 2026 · 8 min read

HTML email validation: type="email" accepts jane@example, and a pattern that requires a dot in the domain rejects it

The HTML email validator you already have is <input type="email">: the browser checks the value against one rule from the HTML standard before it submits the form. That rule is deliberately loose. It catches typing mistakes and nothing else, so the useful questions are what exactly it accepts, how to tighten it, and what your server has to do anyway.

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

The rule behind type="email"

The HTML standard defines a valid email address with this ABNF:

email         = 1*( atext / "." ) "@" label *( "." label )
label         = let-dig [ [ ldh-str ] let-dig ]  ; limited to a length of 63 characters by RFC 1034 section 3.5
atext         = < as defined in RFC 5322 section 3.2.3 >
let-dig       = < as defined in RFC 1034 section 3.5 >
ldh-str       = < as defined in RFC 1034 section 3.5 >

and gives a JavaScript regular expression that implements it:

/^[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])?)*$/

The standard calls this “a willful violation of RFC 5322”, whose syntax is “simultaneously too strict (before the “@” character), too vague (after the “@” character), and too lax (allowing comments, whitespace characters, and quoted strings in manners unfamiliar to most users) to be of practical use here.”

Read the ABNF closely and three consequences follow:

The value is also cleaned before it is checked: the browser strips line breaks and leading and trailing whitespace (the “value sanitization algorithm”). An empty value is valid unless the input is required.

HTML email validator test: 23 addresses

We set each address as the value of an <input type="email"> in Chromium 141 and called checkValidity(). The same addresses through the standard’s regex in Node.js, after trimming, gave identical results.

AddressValid?Why
jane@example.com✓
jane.doe@example.com✓
jane+news@example.com✓+ is atext
o'brien@example.ie✓' is atext
JANE@EXAMPLE.COM✓
jane@example✓No dot needed in the domain
.jane@example.com✓Dots anywhere in the local part
jane.@example.com✓Same
jane..doe@example.com✓Same
jane@example.c✓One-letter labels are allowed
65 characters before the @✓No length limit on the local part
jane@example.com✓Whitespace is stripped first
jane@example.com + line break✓Line break is stripped first
jane@-example.com✗Label can’t start with a hyphen
jane@example..com✗Empty domain label
jane@exa_mple.com✗_ not allowed after the @
jane doe@example.com✗Space
jane@doe@example.com✗Second @
"jane doe"@example.com✗No quoted local parts
jane@[192.0.2.10]✗No IP address literals
josé@example.com✗Non-ASCII local part
jane@bücher.example (set by script)✗Non-ASCII domain in value
64-character domain label✗Labels are limited to 63

Two of these depend on how the value gets in. When we typed jane@bücher.example into the field instead, Chromium stored jane@xn--bcher-kva.example and the field was valid: the standard says browsers “should convert punycode in the domain labels of the value to IDN in the display and vice versa”. And the error messages are the browser’s own. For jane@exa_mple.com, Chromium said: “A part following ‘@’ should not contain the symbol ‘_’.”

To see each format rule spelled out for a single address, use the email syntax checker; the email address format guide explains where the rules come from.

Validate email in HTML5: required, multiple and pattern

Three attributes change what the email validator accepts.

required makes an empty field invalid (validity.valueMissing). Without it, an empty email field submits.

multiple accepts a comma-separated list. Each address must pass on its own, and whitespace around each one is stripped:

Value with multipleValid?value after sanitizing
jane@example.com, bob@example.org✓jane@example.com,bob@example.org
jane@example.com ,bob@example.org✓jane@example.com,bob@example.org
jane@example.com,,bob@example.org✗(unchanged)
jane@example.com;bob@example.org✗(unchanged)

Semicolons, which many mail programs use as separators, are not accepted.

pattern adds your own regular expression on top of the type check. The browser anchors it for you (it wraps it in ^(?: and )$), and with multiple it applies to each address. To require a dot and a top-level domain of at least two characters:

<input type="email" name="email" required
       pattern=".+@.+\.[^.]{2,}"
       title="An email address with a domain such as example.com">

In our run, the pattern rejected jane@example and jane@example.c (both patternMismatch), and accepted jane@mail.example.co.uk, JANE@EXAMPLE.COM and jane@example.xn--p1ai. The standard asks for a title that describes the pattern, since browsers may show it in the error message.

The pattern that silently does nothing

Browsers compile pattern with the JavaScript v flag, as the pattern attribute section of the standard specifies. In v mode, a hyphen at the end of a character class is a syntax error, and a pattern that doesn’t compile is simply ignored. This common copy-paste pattern is one of them:

<!-- ignored in current browsers: the "-" at the end of each class is invalid in v mode -->
<input type="email" pattern="[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}">

Chromium logged this to the console and then accepted jane@example:

Invalid regular expression: /[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}/v: Invalid character in character class

Escaped as [a-z0-9._%+\-] and [a-z0-9.\-], the pattern works, but note that it is case-sensitive and rejected Jane@Example.com in the same run. Check the console whenever you add a pattern.

Custom error messages with the constraint validation API

The browser’s messages differ between browsers and languages. To show your own, turn off the built-in bubbles with novalidate and read the constraint validation API yourself:

<form id="signup" action="/signup" method="post" novalidate>
  <label for="email">Email</label>
  <input id="email" name="email" type="email" required autocomplete="email"
         pattern=".+@.+\.[^.]{2,}" aria-describedby="email-error">
  <p id="email-error" role="alert"></p>
  <button>Sign up</button>
</form>

<script>
  const form = document.getElementById("signup");
  const email = document.getElementById("email");
  const error = document.getElementById("email-error");

  function messageFor(input) {
    if (input.validity.valueMissing) return "Please enter your email address.";
    if (input.validity.typeMismatch) return "That doesn't look like an email address.";
    if (input.validity.patternMismatch) return "Please check the part after the @, e.g. example.com.";
    return "";
  }

  email.addEventListener("input", () => { error.textContent = ""; });

  form.addEventListener("submit", (event) => {
    if (!email.checkValidity()) {
      event.preventDefault();
      error.textContent = messageFor(email);
      email.focus();
    }
  });
</script>

In Chromium, an empty field, jane doe@example.com and jane@example each stopped the form with the matching message, and jane@example.com was submitted as email=jane%40example.com, already trimmed.

The other tools of the API: setCustomValidity("…") marks a field invalid with your own message (for example after a server answer) and setCustomValidity("") clears it; reportValidity() checks and shows the browser’s message; validity.typeMismatch is the flag for a value that fails the email rule.

Why the browser check is not enough

The HTML email validator runs in a program you don’t control. Three reasons to check again on the server:

  1. It can be skipped. A form with novalidate, a disabled script, a bot or a plain HTTP request sends whatever it likes.
  2. It’s loose by design. jane@example and jane..doe@example.com pass, as the table shows.
  3. It knows nothing about the mailbox. jane.doe@example.com passes every format rule and still bounces, because example.com accepts no mail. The same goes for typos in real domains, mailboxes that were deleted, and disposable inboxes.

On the server, repeat the format rule and then ask the recipient’s mail server. A Node.js handler for the form above:

// The browser's rule from the HTML standard, plus "the domain needs a dot".
const HTML_EMAIL = /^[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])?)*$/;

export async function checkEmailField(raw) {
  const email = String(raw ?? "").trim();
  if (!HTML_EMAIL.test(email) || !email.split("@")[1].includes(".")) {
    return { ok: false, message: "Please enter a valid email address." };
  }
  try {
    const url = `https://api.emailvalidation.io/v1/info?email=${encodeURIComponent(email)}`;
    const res = await fetch(url, {
      headers: { apikey: process.env.EMAILVALIDATION_API_KEY },
      signal: AbortSignal.timeout(10_000),
    });
    if (res.ok) {
      const result = await res.json();
      if (result.state === "undeliverable") {
        return { ok: false, message: "This mailbox doesn't exist. Please check the address." };
      }
    }
  } catch {
    // network error or timeout: don't block the form
  }
  return { ok: true, email };
}

Against a local mock of the email validation API with its documented response format, this accepted a deliverable address, rejected one reported as undeliverable, and accepted the address when the API was unreachable. The result also carries disposable, role and did_you_mean if you want to warn about throwaway inboxes or suggest a correction. Keep the API key on the server; a key in front-end code can be read by anyone.

For a stricter format rule than the standard’s, the tested pattern in the email regex guide works in JavaScript, Python, PHP, Java, Go and Ruby. To try a single address by hand, use the free email validator.

  1. type="email", required and autocomplete="email" on the input: right keyboard on phones, instant feedback.
  2. A pattern that requires a top-level domain, with a title, and a look at the console to make sure it compiles.
  3. Your own messages via novalidate and validity if the browser’s wording doesn’t fit.
  4. The same format check on the server, then the mailbox check. Typo hints in the browser are in the JavaScript email validation guide.

Sources

All checked October 10, 2026:

Validate email in other languages

Frequently asked questions

Does <input type="email"> validate email addresses?

It checks the format only. The browser compares the value with the HTML standard’s definition of a valid email address and blocks the form if it doesn’t match. It accepts jane@example without a top-level domain, and it can’t tell whether the address exists.

What regex does the browser use for type="email"?

The HTML standard gives this one: /^[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])?)*$/. The standard calls it a “willful violation” of RFC 5322, chosen to be practical.

How do I require a dot in the domain with HTML validation?

Add a pattern to the email input, for example pattern=".+@.+\.[^.]{2,}". The browser applies it on top of the type="email" rule, so jane@example and jane@example.c are rejected. Add a title that describes the rule.

Why is my pattern attribute ignored on an email input?

Browsers compile pattern with the regular expression v flag, and in that mode a pattern such as [a-z0-9._%+-] with an unescaped hyphen at the end of a character class is a syntax error. An invalid pattern is ignored and only logged in the console. Escape the hyphen as \-.

Is HTML5 email validation enough?

No. Anyone can send the form without the browser’s checks, and a well-formed address can still bounce. Repeat the format check on the server and verify the mailbox, for example with an email validation API.

Email validation API

Validate emails in your app

emailvalidation.io checks syntax, MX records and the mailbox over SMTP, flags disposable, role and free addresses and returns a quality score, in one request.

/v1/info Email validation API Read the documentation

100 free validations every month. No credit card required.

GET https://api.emailvalidation.io/v1/info?email=support@emailvalidation.io

{
  "email": "support@emailvalidation.io",
  "user": "support",
  "tag": "",
  "domain": "emailvalidation.io",
  "format_valid": true,
  "mx_found": true,
  "smtp_check": true,
  "catch_all": null,
  "role": true,
  "disposable": false,
  "free": false,
  "score": 0.64,
  "state": "deliverable",
  "reason": "valid_mailbox",
  "did_you_mean": ""
}

Keep reading

Start using our email validation software today!

Get 100 validations per month for free