MX records tell sending servers which mail servers accept email for your domain and the order in which they should be tried. There...
Key Takeaways
- Client-side JavaScript, whether HTML5 attributes, regex, or libraries, can only confirm email format. It cannot verify that a mailbox exists or that an address is deliverable.
- For JavaScript email validation, the strongest approach is layering methods: HTML5 attribute as baseline, regex for immediate feedback, and an API call to confirm mailbox existence before the form submits.
- An email validation API catches what no client-side method can: typos in real-looking domains, disposable addresses, catch-all domains, role-based accounts, and spam traps.
Around 30% of email addresses in a list go bad within a single year, and if more than 10% of your list is invalid, fewer than 44% of your emails get delivered. Many of those bad addresses enter databases through forms with weak validation.
Email validation in JavaScript works in layers. Checking whether an address is properly formatted is relatively simple. Confirming that the domain can receive mail is more advanced but still possible. The difficult part is verifying that the mailbox itself actually exists and can accept messages, and browser-only JavaScript cannot do that on its own.
Validation usually happens across three levels: syntax, domain, and mailbox. JavaScript handles syntax checks well, while libraries and APIs can help verify domains. Mailbox verification, however, requires a server-side API request because the browser cannot directly confirm if an inbox is real.
Methods to Validate Email in JavaScript
Each method below adds a layer to your validation stack. They’re ordered from simplest to most thorough. Most production applications use at least two, while security-critical signup flows use all four.
1. The HTML5 type=”email” attribute
The simplest JavaScript email validation starting point is the HTML5 type=”email” attribute on your input element. Browsers enforce basic format validation automatically when the form is submitted.
<form>
<label for=”email”>Email address</label>
<input type=”email” id=”email” name=”email” required />
<button type=”submit”>Submit</button>
</form>
The browser checks that the field contains an @ symbol and a domain-like string before allowing submission. The validation runs on submit by default.
However, the HTML5 check is very basic. It accepts addresses like a@b or user@domain, even though they would never receive real emails. It also does not provide live feedback while someone is typing. So, use it as a starting point: always include it, but never rely on it as your only check.
2. Validating with a Regex pattern
Regex (regular expressions) is the most common JavaScript email validation method. It gives you format enforcement that runs on demand, before form submission, and produces immediate feedback.
Here’s a basic regex that covers the most common valid formats:
function isValidEmail(email) {
const regex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return regex.test(email);
}
// Usage
console.log(isValidEmail(“[email protected]”)); // true
console.log(isValidEmail(“notanemail”)); // false
Understanding the pattern:
- ^ — start of string
- [^\s@]+ — one or more characters that are not whitespace or @
- @ — the literal @ symbol
- [^\s@]+ — one or more characters after @ (the domain)
- \. — a literal dot
- [^\s@]+$ — one or more characters after the dot (the TLD)
For stricter RFC 5322-aligned validation, you can use a more specific pattern:
function isValidEmail(email) {
const regex = /^[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])?)*\.[a-zA-Z]{2,}$/;
return regex.test(email);
}
Wrapping the regex in a reusable function like isValidEmail() keeps your validation logic in one place and makes it easy to update.
The biggest limitation is that regex only checks the format. It cannot tell if a domain exists or if a mailbox is real. An address like [email protected] will still pass because the format looks valid, even though the domain is a typo and the email will likely never be delivered.
3. Using a JavaScript validation library
Established libraries like validator.js handle many cases that basic regex patterns miss, including international domains, unusual but valid email formats, and newer domain extensions. If your application already uses a validation framework, a library is the cleaner choice over maintaining custom regex patterns.
Install validator.js:
npm install validator
Use it in your code:
import validator from ‘validator’;
function isValidEmail(email) {
return validator.isEmail(email);
}
// Usage
console.log(isValidEmail(“[email protected]”)); // true
console.log(isValidEmail(“[email protected]”)); // false
console.log(isValidEmail(“user@example”)); // false
The validator.isEmail() method performs a more complete format check than a simple regex and catches many common formatting problems.
The limitation is the same, though: libraries only validate structure, not deliverability. An address like [email protected] still passes because the format is technically correct. For production signup flows where list quality matters, this method needs an API call alongside it.
4. Validating with an email validation API
An API-based approach is the only method that can confirm a mailbox actually exists. The methods covered so far only validate the format of an email address. An API checks whether the address can really receive mail.
The DeBounce Email Validation API checks syntax, domain MX records, mailbox existence, disposable address status, role accounts, and catch-all domain behavior, all in a single API call. Here’s an example using fetch() in JavaScript:
async function validateEmailWithAPI(email) {
const apiKey = ‘YOUR_DEBOUNCE_API_KEY’;
const url = `https://api.debounce.io/v1/?api=${apiKey}&email=${encodeURIComponent(email)}`;
try {
const response = await fetch(url);
const data = await response.json();
return {
result: data.debounce?.result,
reason: data.debounce?.reason,
free_email: data.debounce?.free_email === “true” || data.debounce?.free_email === true,
did_you_mean: data.debounce?.did_you_mean,
role: data.debounce?.role === “true” || data.debounce?.role === true
};
} catch (error) {
console.error(‘Validation error:’, error);
return null;
}
}
Response fields developers care about most:
- result — the top-level verdict: “Safe to Send,” “Risky,” or “Invalid”
- reason — the specific finding: deliverable, disposable, catch-all, syntax error, etc.
- did_you_mean — a corrected address if the API detects a common typo (e.g., gmial.com → gmail.com)
- free_email — whether the address belongs to a free provider like Gmail or Yahoo
For client-side disposable email detection specifically, DeBounce also offers a free disposable email API that you can call directly from the browser without exposing your main API key.
If you’d rather not write any code at all, the JavaScript validation widget installs with a single script tag and handles validation directly on your forms without custom integration work.
Implementing Real-Time Email Validation
Real-time email validation improves both user experience and data quality because users can fix mistakes immediately instead of waiting until form submission. The important part is choosing the right event for the type of validation you’re running.
oninput fires on every keystroke, which makes it useful for fast checks like regex validation. onchange fires after the field loses focus, making it a better fit for API validation since it waits until the user finishes typing before sending a request.
Here’s a simple real-time setup using oninput and a regex check:
const emailInput = document.getElementById(’email’);
const feedbackEl = document.getElementById(’email-feedback’);
emailInput.addEventListener(‘input’, function () {
const email = this.value;
if (email.length === 0) {
feedbackEl.textContent = ”;
this.classList.remove(‘valid’, ‘invalid’);
return;
}
if (isValidEmail(email)) {
this.classList.add(‘valid’);
this.classList.remove(‘invalid’);
feedbackEl.textContent = ‘✓ Looks good’;
} else {
this.classList.add(‘invalid’);
this.classList.remove(‘valid’);
feedbackEl.textContent = ‘Please enter a valid email address’;
}
});
When using an API method, debounce the call, waiting until the user has paused typing for 300–500ms before firing the request. This avoids sending an API call for every partial keystroke:
let debounceTimer;
emailInput.addEventListener(‘input’, function () {
clearTimeout(debounceTimer);
debounceTimer = setTimeout(() => {
validateEmailWithAPI(this.value).then(result => {
if (result?.did_you_mean) {
feedbackEl.textContent = `Did you mean ${result.did_you_mean}?`;
}
});
}, 400);
});
Good real-time feedback is clear and specific. “Did you mean [email protected]?” is useful, while generic messages like “Invalid email” frustrate users and increase form abandonment.
Email Validation in Popular JavaScript Frameworks
Framework-level form libraries handle state management, error display, and submission logic, so plugging in validation usually means specifying a rule instead of wiring up events manually.
React with React Hook Form:
import { useForm } from ‘react-hook-form’;
export default function SignupForm() {
const { register, handleSubmit, formState: { errors } } = useForm();
return (
<form onSubmit={handleSubmit(data => console.log(data))}>
<input
{…register(’email’, {
required: ‘Email is required’,
pattern: {
value: /^[^\s@]+@[^\s@]+\.[^\s@]+$/,
message: ‘Enter a valid email address’
}
})}
/>
{errors.email && <span>{errors.email.message}</span>}
<button type=”submit”>Sign up</button>
</form>
);
}
Vue with VeeValidate:
import { useField, useForm } from ‘vee-validate’;
export default {
setup() {
const { handleSubmit } = useForm();
const { value: email, errorMessage } = useField(’email’, (val) => {
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(val) || ‘Enter a valid email address’;
});
const onSubmit = handleSubmit(values => console.log(values));
return { email, errorMessage, onSubmit };
}
};
Schema validation with Zod or Yup (useful when you want to share validation logic between client and server):
import { z } from ‘zod’;
const emailSchema = z.string().email(‘Enter a valid email address’);
function validateEmail(email) {
const result = emailSchema.safeParse(email);
return result.success ? null : result.error.issues[0].message;
}
In all three cases, the framework handles the setup while you provide the validation rule. If you later replace the regex with an API call, the overall structure stays mostly the same.
The Limitations of Client-Side Email Validation
Client-side validation can check if an email address looks valid, but it cannot tell if the address actually works. Here are some problems JavaScript alone cannot catch.
- Typos in real-looking domains: Addresses like [email protected], [email protected], or [email protected] pass format validation even though the domains are misspelled. The email never reaches the user, and the address stays on your list, generating bounces.
- Disposable and temporary email addresses: Services like 10minutemail.com and guerrillamail.com create temporary inboxes that pass validation checks. Users often enter them to bypass signup forms, then the address disappears shortly afterward.
- Catch-all domains: Some domains are configured to accept every email sent to them, regardless of whether the specific mailbox exists. An address on a catch-all domain will pass format validation, MX checks, and even some SMTP checks while still being undeliverable in practice.
- Role-based addresses: Addresses like info@, sales@, admin@, and support@ are usually managed by teams instead of individuals. They generate higher complaint rates and are usually poor choices for marketing lists. A regex pattern cannot reliably identify them.
- Spam traps: These are email addresses used by deliverability organizations to identify senders with poor list hygiene. They look completely normal and pass client-side validation, but sending to them can damage your sender reputation.
The DeBounce Email Validation API catches all five issues through real-time mailbox-level checks and continuously updated validation data. To maintain long-term list quality, email verification tools can also re-check older contacts in bulk, helping remove addresses that become invalid over time.
Best Practices for Email Validation in JavaScript
Good email validation uses multiple checks together to improve data quality, user experience, and deliverability.
- Layer your validation: Start with the HTML5 email attribute, add a regex or validation library, then use an API call for mailbox-level verification. Each layer catches problems the previous one misses, while the earlier checks provide instant feedback without waiting for a network request.
- Never rely on client-side validation alone for security-critical flows: Browser-based validation can be bypassed, so email addresses should always be validated again on the server before processing signups, purchases, or account creation.
- Use a battle-tested library or API rather than maintaining custom regex long-term: Email address formats evolve. A library or API that’s actively maintained handles new edge cases without requiring you to update your own patterns.
- Debounce API calls and provide clear visual feedback: A loading indicator while the API runs, a green checkmark on success, and a specific error message on failure (“Did you mean [email protected]?”) keep the form responsive and reduce drop-off.
- Log validation outcomes during development: Disposable email providers, repeated typos, and suspicious domains become obvious once you review the logs, making it easier to tighten validation rules over time.
- Validate at the list level as well: Real-time validation catches bad addresses during signup, while Email List Validation helps remove addresses that later become inactive.
The Bottom Line
HTML5 validation gives you basic format checks for free. Regex and validation libraries improve the user experience with fast client-side feedback, while APIs verify whether a mailbox actually exists and can receive email.
That last step matters most. Client-side validation alone cannot confirm that an address is real, active, or safe to send to. For production signup forms where deliverability and list quality matter, API validation is what prevents disposable emails, typo domains, catch-all addresses, and other bad contacts from entering your database.
The DeBounce Email Validation API adds that mailbox-level verification directly to your signup flow, helping block bad addresses before they affect your sender reputation. If you want a faster setup, the JavaScript validation widget provides a no-code way to add real-time email validation directly to your forms.