Email validation with regex, syntax check, MX verification, and disposable domain detection
Comprehensive email validation covering syntax, RFC 5322 regex, DNS MX record lookups, SMTP mailbox verification, disposable/temp email detection, and common domain typo suggestions. Zero external dependencies.
npm install @chaisser/email-validator
# or
yarn add @chaisser/email-validator
# or
pnpm add @chaisser/email-validatorimport {
isValid,
validate,
isDisposable,
hasTypo,
suggestCorrection,
checkSMTP,
validateDetailed
} from '@chaisser/email-validator';
// Basic check
isValid('user@example.com'); // true
// Detailed reason
validate('user@.com');
// { valid: false, reason: 'Domain starts with dot' }
// Disposable email check
isDisposable('user@mailinator.com'); // true
// Typo detection
hasTypo('user@gmal.com'); // true
suggestCorrection('user@gmal.com'); // 'user@gmail.com'
// SMTP mailbox verification (checks if inbox really exists)
const result = await checkSMTP('test@gmail.com');
// { reachable: true, mailboxExists: true/false/null, response: '...', mxHost: 'gmail-smtp-in.l.google.com' }
// Full validation
const detailed = await validateDetailed('user@gmail.com', { checkMX: true });
// { valid, syntax, regex, mx, disposable, typo, normalized, domain, localPart, reasons }| Function | Returns | Description |
|---|---|---|
isValid(email) |
boolean |
Quick format check |
validate(email) |
{ valid, reason? } |
Validate with failure reason |
isValidRegex(email) |
boolean |
RFC 5322 regex check |
isValidStrict(email) |
boolean |
Strict allowed chars check |
isValidLength(email) |
boolean |
Max 254 chars |
isValidLocalPart(email) |
boolean |
Local part max 64 chars |
isValidDomain(email) |
boolean |
Domain format check |
| Function | Description |
|---|---|
normalize(email) |
Trim + lowercase |
normalizeGmail(email) |
Remove dots and +tags for Gmail addresses |
| Function | Returns |
|---|---|
parse(email) |
{ localPart, domain, tld } or null |
getDomain(email) |
Domain string |
getTLD(email) |
TLD string |
getLocalPart(email) |
Local part string |
| Function | Description |
|---|---|
isDisposable(email) |
Check if email uses disposable domain |
isDisposableDomain(domain) |
Check domain directly |
getDisposableDomains() |
Get all known disposable domains |
addDisposableDomain(domain) |
Add a domain to the list |
removeDisposableDomain(domain) |
Remove a domain from the list |
| Function | Description |
|---|---|
hasTypo(email) |
Check if domain looks like a typo |
suggestCorrection(email) |
Suggest corrected email or null |
getSuggestions(domain) |
Get matching correct domains |
Detects typos for: gmail.com, yahoo.com, hotmail.com, outlook.com, live.com, icloud.com, protonmail.com, aol.com, mail.com, zoho.com, yandex.com, qq.com, and more.
| Function | Description |
|---|---|
isFreeProvider(email) |
Gmail, Yahoo, Outlook, etc. |
isBusinessEmail(email) |
Not free provider, not disposable |
| Function | Description |
|---|---|
hasMXRecords(domain) |
Check if domain has MX records |
getMXRecords(domain) |
Get sorted list of MX hosts |
getMXRecordsWithPriority(domain) |
Get MX records with priority values |
All async. Uses Node.js built-in dns module.
| Function | Description |
|---|---|
checkSMTP(email, options?) |
Connect to MX server and verify mailbox exists |
Options: { timeout?: number, from?: string } (default timeout 10s)
Returns { reachable, mailboxExists, response, mxHost }:
reachable: Server was reachablemailboxExists:true/false/null(null = couldn't determine)
| Function | Description |
|---|---|
validateDetailed(email, options?) |
Complete validation with all checks |
Options: { checkMX?: boolean, checkSMTP?: boolean, smtpTimeout?: number }
Returns:
{
valid, syntax, regex, mx, disposable, typo,
normalized, domain, localPart, reasons[]
}
import { validate, isDisposable, hasTypo, suggestCorrection } from '@chaisser/email-validator';
function validateSignupEmail(email: string) {
const { valid, reason } = validate(email);
if (!valid) return { error: reason };
if (isDisposable(email)) return { error: 'Disposable emails not allowed' };
if (hasTypo(email)) {
return { warning: `Did you mean ${suggestCorrection(email)}?` };
}
return { valid: true, email };
}import { validateDetailed } from '@chaisser/email-validator';
async function verifyBeforeSend(email: string) {
const result = await validateDetailed(email, { checkMX: true, checkSMTP: true });
if (!result.valid) return { canSend: false, reasons: result.reasons };
if (result.mx === false) return { canSend: false, reasons: ['Domain has no mail server'] };
if (result.disposable) return { canSend: false, reasons: ['Disposable email'] };
return { canSend: true };
}import { normalizeGmail } from '@chaisser/email-validator';
// All these resolve to the same normalized address
normalizeGmail('john.doe@gmail.com'); // 'johndoe@gmail.com'
normalizeGmail('johndoe+newsletter@gmail.com'); // 'johndoe@gmail.com'
normalizeGmail('JOHN.DOE@GOOGLEMAIL.COM'); // 'johndoe@gmail.com'import { getMXRecords } from '@chaisser/email-validator';
const domains = ['gmail.com', 'company.com', 'fake-domain.invalid'];
for (const domain of domains) {
const mx = await getMXRecords(domain);
console.log(`${domain}: ${mx.length > 0 ? mx.join(', ') : 'NO MX RECORDS'}`);
}MIT