mail-validatr
Advanced tools
Comparing version
#!/usr/bin/env node | ||
var __defProp = Object.defineProperty; | ||
var __getOwnPropNames = Object.getOwnPropertyNames; | ||
var __esm = (fn, res) => function __init() { | ||
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res; | ||
}; | ||
var __export = (target, all) => { | ||
for (var name in all) | ||
__defProp(target, name, { get: all[name], enumerable: true }); | ||
}; | ||
import { | ||
validateEmail | ||
} from "../chunk-UQ256RS5.js"; | ||
// src/core/dns.ts | ||
var dns_exports = {}; | ||
__export(dns_exports, { | ||
validateDomain: () => validateDomain | ||
}); | ||
async function validateDomain(domain) { | ||
if (typeof window !== "undefined") { | ||
return null; | ||
} | ||
const dns = await import("dns").then((mod) => mod.promises); | ||
let hasMxRecords = false; | ||
let hasValidDomain = false; | ||
try { | ||
const mxRecords = await dns.resolveMx(domain); | ||
hasMxRecords = mxRecords.length > 0; | ||
hasValidDomain = true; | ||
} catch { | ||
try { | ||
await dns.resolve(domain); | ||
hasValidDomain = true; | ||
} catch { | ||
hasValidDomain = false; | ||
} | ||
} | ||
return { hasValidDomain, hasMxRecords }; | ||
} | ||
var init_dns = __esm({ | ||
"src/core/dns.ts"() { | ||
"use strict"; | ||
} | ||
}); | ||
// src/cli/cli.ts | ||
import minimist from "minimist"; | ||
// src/core/syntax.ts | ||
function testSyntax(email) { | ||
return /^(?:[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+)*|"[^\r\n"]*")@(?:[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*|\[?(?:[0-9]{1,3}\.){3}[0-9]{1,3}\]?)$/.test( | ||
); | ||
} | ||
// src/core/warnings.ts | ||
var customRules = []; | ||
function addCustomWarningRule(rule) { | ||
customRules.push(rule); | ||
} | ||
function getWarnings(email) { | ||
const warnings = []; | ||
const [localPart, domainPart] = email.split("@"); | ||
if (/^".+"$/.test(localPart)) { | ||
warnings.push({ | ||
code: "quoted_local_part", | ||
message: "Quoted local part \u2013 technically valid, but rarely supported." | ||
}); | ||
} | ||
if (/^\[[^\]]+\]$/.test(domainPart)) { | ||
warnings.push({ | ||
code: "ip_address_domain", | ||
message: "Domain is an IP address \u2013 valid, but very uncommon." | ||
}); | ||
} | ||
if (/^[a-zA-Z0-9\-]+\.[a-zA-Z]{1,2}$/.test(email) || /^[a-zA-Z0-9\-]+@[a-zA-Z]{2}$/.test(email)) { | ||
warnings.push({ | ||
code: "short_tld", | ||
message: "Very short or missing TLD \u2013 may not be a real domain." | ||
}); | ||
} | ||
if (/\.\./.test(localPart) || /\.\./.test(domainPart)) { | ||
warnings.push({ | ||
code: "consecutive_dots", | ||
message: "Consecutive dots \u2013 may be rejected by some servers." | ||
}); | ||
} | ||
if (/[^a-zA-Z0-9._]/.test(localPart)) { | ||
warnings.push({ | ||
code: "uncommon_characters", | ||
message: "Local part contains uncommon or special characters." | ||
}); | ||
} | ||
if (domainPart === "localhost") { | ||
warnings.push({ | ||
code: "localhost_domain", | ||
message: "Domain is 'localhost' \u2013 typically only used in testing environments." | ||
}); | ||
} | ||
for (const rule of customRules) { | ||
const customWarning = rule(email); | ||
if (customWarning) { | ||
warnings.push(customWarning); | ||
} | ||
} | ||
return warnings; | ||
} | ||
// src/core/disposable.ts | ||
var disposableDomains = [ | ||
"mailinator.com", | ||
"tempmail.com", | ||
"10minutemail.com", | ||
"guerrillamail.com", | ||
"yopmail.com", | ||
"trashmail.com", | ||
"getnada.com" | ||
]; | ||
function isDisposableEmail(domain, customList = []) { | ||
const combinedList = [...disposableDomains, ...customList]; | ||
return combinedList.includes(domain); | ||
} | ||
// src/index.ts | ||
async function validateEmail(email, options = {}) { | ||
const warnings = []; | ||
const isValidSyntax = testSyntax(email); | ||
if (!isValidSyntax) { | ||
warnings.push({ | ||
code: "invalid_syntax", | ||
message: "Email does not match basic syntax (missing '@' or domain part)." | ||
}); | ||
return { | ||
isValidSyntax: false, | ||
warnings, | ||
recommended: false | ||
}; | ||
} | ||
const domain = email.split("@")[1]; | ||
const customWarningRules = options.customWarningRules || []; | ||
customWarningRules.forEach((rule) => addCustomWarningRule(rule)); | ||
warnings.push(...getWarnings(email)); | ||
if (isDisposableEmail(domain, options.customDisposableList || [])) { | ||
warnings.push({ | ||
code: "disposable_email", | ||
message: "Email domain belongs to a disposable email provider." | ||
}); | ||
} | ||
let hasMxRecords = void 0; | ||
let hasValidDomain = void 0; | ||
if (!options.skipDnsCheck && typeof window === "undefined") { | ||
try { | ||
const { validateDomain: validateDomain2 } = await Promise.resolve().then(() => (init_dns(), dns_exports)); | ||
const dnsResult = await validateDomain2(domain); | ||
if (dnsResult) { | ||
hasValidDomain = dnsResult.hasValidDomain; | ||
hasMxRecords = dnsResult.hasMxRecords; | ||
} | ||
} catch (e) { | ||
} | ||
} | ||
const recommended = isValidSyntax && warnings.length === 0 && hasValidDomain !== false && hasMxRecords !== false; | ||
return { | ||
isValidSyntax, | ||
...hasValidDomain !== void 0 && { hasValidDomain }, | ||
...hasMxRecords !== void 0 && { hasMxRecords }, | ||
warnings, | ||
recommended | ||
}; | ||
} | ||
// src/cli/cli.ts | ||
var argv = minimist(process.argv.slice(2), { | ||
@@ -172,0 +9,0 @@ boolean: ["skip-dns", "verbose"], |
@@ -1,167 +0,6 @@ | ||
var __defProp = Object.defineProperty; | ||
var __getOwnPropNames = Object.getOwnPropertyNames; | ||
var __esm = (fn, res) => function __init() { | ||
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res; | ||
}; | ||
var __export = (target, all) => { | ||
for (var name in all) | ||
__defProp(target, name, { get: all[name], enumerable: true }); | ||
}; | ||
// src/core/dns.ts | ||
var dns_exports = {}; | ||
__export(dns_exports, { | ||
validateDomain: () => validateDomain | ||
}); | ||
async function validateDomain(domain) { | ||
if (typeof window !== "undefined") { | ||
return null; | ||
} | ||
const dns = await import("dns").then((mod) => mod.promises); | ||
let hasMxRecords = false; | ||
let hasValidDomain = false; | ||
try { | ||
const mxRecords = await dns.resolveMx(domain); | ||
hasMxRecords = mxRecords.length > 0; | ||
hasValidDomain = true; | ||
} catch { | ||
try { | ||
await dns.resolve(domain); | ||
hasValidDomain = true; | ||
} catch { | ||
hasValidDomain = false; | ||
} | ||
} | ||
return { hasValidDomain, hasMxRecords }; | ||
} | ||
var init_dns = __esm({ | ||
"src/core/dns.ts"() { | ||
"use strict"; | ||
} | ||
}); | ||
// src/core/syntax.ts | ||
function testSyntax(email) { | ||
return /^(?:[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+)*|"[^\r\n"]*")@(?:[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*|\[?(?:[0-9]{1,3}\.){3}[0-9]{1,3}\]?)$/.test( | ||
); | ||
} | ||
// src/core/warnings.ts | ||
var customRules = []; | ||
function addCustomWarningRule(rule) { | ||
customRules.push(rule); | ||
} | ||
function getWarnings(email) { | ||
const warnings = []; | ||
const [localPart, domainPart] = email.split("@"); | ||
if (/^".+"$/.test(localPart)) { | ||
warnings.push({ | ||
code: "quoted_local_part", | ||
message: "Quoted local part \u2013 technically valid, but rarely supported." | ||
}); | ||
} | ||
if (/^\[[^\]]+\]$/.test(domainPart)) { | ||
warnings.push({ | ||
code: "ip_address_domain", | ||
message: "Domain is an IP address \u2013 valid, but very uncommon." | ||
}); | ||
} | ||
if (/^[a-zA-Z0-9\-]+\.[a-zA-Z]{1,2}$/.test(email) || /^[a-zA-Z0-9\-]+@[a-zA-Z]{2}$/.test(email)) { | ||
warnings.push({ | ||
code: "short_tld", | ||
message: "Very short or missing TLD \u2013 may not be a real domain." | ||
}); | ||
} | ||
if (/\.\./.test(localPart) || /\.\./.test(domainPart)) { | ||
warnings.push({ | ||
code: "consecutive_dots", | ||
message: "Consecutive dots \u2013 may be rejected by some servers." | ||
}); | ||
} | ||
if (/[^a-zA-Z0-9._]/.test(localPart)) { | ||
warnings.push({ | ||
code: "uncommon_characters", | ||
message: "Local part contains uncommon or special characters." | ||
}); | ||
} | ||
if (domainPart === "localhost") { | ||
warnings.push({ | ||
code: "localhost_domain", | ||
message: "Domain is 'localhost' \u2013 typically only used in testing environments." | ||
}); | ||
} | ||
for (const rule of customRules) { | ||
const customWarning = rule(email); | ||
if (customWarning) { | ||
warnings.push(customWarning); | ||
} | ||
} | ||
return warnings; | ||
} | ||
// src/core/disposable.ts | ||
var disposableDomains = [ | ||
"mailinator.com", | ||
"tempmail.com", | ||
"10minutemail.com", | ||
"guerrillamail.com", | ||
"yopmail.com", | ||
"trashmail.com", | ||
"getnada.com" | ||
]; | ||
function isDisposableEmail(domain, customList = []) { | ||
const combinedList = [...disposableDomains, ...customList]; | ||
return combinedList.includes(domain); | ||
} | ||
// src/index.ts | ||
async function validateEmail(email, options = {}) { | ||
const warnings = []; | ||
const isValidSyntax = testSyntax(email); | ||
if (!isValidSyntax) { | ||
warnings.push({ | ||
code: "invalid_syntax", | ||
message: "Email does not match basic syntax (missing '@' or domain part)." | ||
}); | ||
return { | ||
isValidSyntax: false, | ||
warnings, | ||
recommended: false | ||
}; | ||
} | ||
const domain = email.split("@")[1]; | ||
const customWarningRules = options.customWarningRules || []; | ||
customWarningRules.forEach((rule) => addCustomWarningRule(rule)); | ||
warnings.push(...getWarnings(email)); | ||
if (isDisposableEmail(domain, options.customDisposableList || [])) { | ||
warnings.push({ | ||
code: "disposable_email", | ||
message: "Email domain belongs to a disposable email provider." | ||
}); | ||
} | ||
let hasMxRecords = void 0; | ||
let hasValidDomain = void 0; | ||
if (!options.skipDnsCheck && typeof window === "undefined") { | ||
try { | ||
const { validateDomain: validateDomain2 } = await Promise.resolve().then(() => (init_dns(), dns_exports)); | ||
const dnsResult = await validateDomain2(domain); | ||
if (dnsResult) { | ||
hasValidDomain = dnsResult.hasValidDomain; | ||
hasMxRecords = dnsResult.hasMxRecords; | ||
} | ||
} catch (e) { | ||
} | ||
} | ||
const recommended = isValidSyntax && warnings.length === 0 && hasValidDomain !== false && hasMxRecords !== false; | ||
return { | ||
isValidSyntax, | ||
...hasValidDomain !== void 0 && { hasValidDomain }, | ||
...hasMxRecords !== void 0 && { hasMxRecords }, | ||
warnings, | ||
recommended | ||
}; | ||
} | ||
import { | ||
validateEmail | ||
} from "./chunk-UQ256RS5.js"; | ||
export { | ||
validateEmail | ||
}; |
{ | ||
"name": "mail-validatr", | ||
"version": "1.0.5", | ||
"version": "1.0.6", | ||
"description": "Email validation CLI and library with DNS, MX, and warning checks.", | ||
@@ -34,3 +34,3 @@ "license": "MIT", | ||
"scripts": { | ||
"build": "tsup", | ||
"build": "tsup src/index.ts src/cli/cli.ts --format esm,cjs --dts", | ||
"dev": "tsup src/index.ts src/cli/cli.ts --format esm,cjs --dts --watch", | ||
@@ -37,0 +37,0 @@ "test:watch": "vitest watch", |
13
18.18%28086
-15.19%635
-20.72%