@emailcheck/email-validator-js 4.0.0 → 5.0.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/index.js +60 -20
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.ts +8 -1
- package/dist/index.esm.js +70 -24
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +74 -23
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +242 -33
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1014,19 +1014,25 @@ function defaultProbeLocal() {
|
|
|
1014
1014
|
return `${node_crypto.randomBytes(8).toString("hex")}-noexist`;
|
|
1015
1015
|
}
|
|
1016
1016
|
async function verifyMailboxSMTP(params) {
|
|
1017
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
1017
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q;
|
|
1018
1018
|
const { local, domain, options = {} } = params;
|
|
1019
1019
|
const mxRecords = (_a = params.mxRecords) !== null && _a !== void 0 ? _a : [];
|
|
1020
1020
|
const ports = ((_b = options.ports) !== null && _b !== void 0 ? _b : DEFAULT_PORTS).filter((port) => Number.isInteger(port) && port > 0 && port < 65536);
|
|
1021
|
-
const
|
|
1022
|
-
const tlsConfig = (_d = options.
|
|
1023
|
-
const
|
|
1021
|
+
const perAttemptTimeoutMs = (_c = options.perAttemptTimeoutMs) !== null && _c !== void 0 ? _c : DEFAULT_TIMEOUT_MS;
|
|
1022
|
+
const tlsConfig = (_d = options.tlsConfig) !== null && _d !== void 0 ? _d : true;
|
|
1023
|
+
const heloHostname = (_e = options.heloHostname) !== null && _e !== void 0 ? _e : "localhost";
|
|
1024
1024
|
const debug = (_f = options.debug) !== null && _f !== void 0 ? _f : false;
|
|
1025
1025
|
const captureTranscript = (_g = options.captureTranscript) !== null && _g !== void 0 ? _g : false;
|
|
1026
1026
|
const sequence = options.sequence;
|
|
1027
1027
|
const cache = options.cache;
|
|
1028
1028
|
const log = debug ? (...args) => console.log("[SMTP]", ...args) : () => {
|
|
1029
1029
|
};
|
|
1030
|
+
const totalDeadlineMs = options.totalDeadlineMs;
|
|
1031
|
+
const maxConsecutiveFailures = options.maxConsecutiveFailures;
|
|
1032
|
+
const maxMxHosts = options.maxMxHosts;
|
|
1033
|
+
const retryAttempts = (_j = (_h = options.retry) === null || _h === void 0 ? void 0 : _h.attempts) !== null && _j !== void 0 ? _j : 0;
|
|
1034
|
+
const retryDelayMs = (_l = (_k = options.retry) === null || _k === void 0 ? void 0 : _k.delayMs) !== null && _l !== void 0 ? _l : 200;
|
|
1035
|
+
const retryBackoff = (_o = (_m = options.retry) === null || _m === void 0 ? void 0 : _m.backoff) !== null && _o !== void 0 ? _o : "exponential";
|
|
1030
1036
|
const startedAtMs = Date.now();
|
|
1031
1037
|
const primaryMx = mxRecords[0];
|
|
1032
1038
|
if (!primaryMx) {
|
|
@@ -1040,14 +1046,14 @@ async function verifyMailboxSMTP(params) {
|
|
|
1040
1046
|
const probeOptions = {
|
|
1041
1047
|
local,
|
|
1042
1048
|
domain,
|
|
1043
|
-
|
|
1049
|
+
perAttemptTimeoutMs,
|
|
1044
1050
|
tlsConfig,
|
|
1045
|
-
|
|
1051
|
+
heloHostname,
|
|
1046
1052
|
sequence,
|
|
1047
1053
|
log,
|
|
1048
1054
|
catchAllProbeLocal: options.catchAllProbeLocal,
|
|
1049
|
-
pipelining: (
|
|
1050
|
-
startTls: (
|
|
1055
|
+
pipelining: (_p = options.pipelining) !== null && _p !== void 0 ? _p : "auto",
|
|
1056
|
+
startTls: (_q = options.startTls) !== null && _q !== void 0 ? _q : "auto"
|
|
1051
1057
|
};
|
|
1052
1058
|
const verdictCache = cache ? getCacheStore(cache, "smtp") : null;
|
|
1053
1059
|
const verdictKey = `${primaryMx}:${local}@${domain}`;
|
|
@@ -1063,17 +1069,42 @@ async function verifyMailboxSMTP(params) {
|
|
|
1063
1069
|
const mxHostsTried = [];
|
|
1064
1070
|
let mxAttempts = 0;
|
|
1065
1071
|
let portAttempts = 0;
|
|
1072
|
+
let consecutiveFailures = 0;
|
|
1066
1073
|
let lastReason = "all_attempts_failed";
|
|
1067
1074
|
let lastEnhancedStatus;
|
|
1068
1075
|
let lastResponseCode;
|
|
1069
|
-
|
|
1076
|
+
let stoppedEarly = null;
|
|
1077
|
+
const isConnectionFailure = (reason) => reason === "connection_error" || reason === "connection_timeout" || reason === "connection_closed" || reason === "socket_timeout";
|
|
1078
|
+
const retryDelayFor = (attemptIndex) => retryBackoff === "exponential" ? retryDelayMs * 2 ** (attemptIndex - 1) : retryDelayMs;
|
|
1079
|
+
const probeWithRetry = async (mxHost, port) => {
|
|
1080
|
+
let lastProbe = await runProbe({ ...probeOptions, mxHost, port });
|
|
1081
|
+
for (let i = 1; i <= retryAttempts; i++) {
|
|
1082
|
+
if (lastProbe.result !== null || !isConnectionFailure(lastProbe.reason))
|
|
1083
|
+
break;
|
|
1084
|
+
const delay = retryDelayFor(i);
|
|
1085
|
+
log(`retry ${i}/${retryAttempts} on ${mxHost}:${port} after ${delay}ms (last: ${lastProbe.reason})`);
|
|
1086
|
+
await new Promise((r) => setTimeout(r, delay));
|
|
1087
|
+
portAttempts++;
|
|
1088
|
+
lastProbe = await runProbe({ ...probeOptions, mxHost, port });
|
|
1089
|
+
}
|
|
1090
|
+
return lastProbe;
|
|
1091
|
+
};
|
|
1092
|
+
outer: for (const mxHost of mxRecords) {
|
|
1093
|
+
if (maxMxHosts !== void 0 && mxAttempts >= maxMxHosts) {
|
|
1094
|
+
stoppedEarly = "max_mx_hosts";
|
|
1095
|
+
break;
|
|
1096
|
+
}
|
|
1070
1097
|
mxHostsTried.push(mxHost);
|
|
1071
1098
|
mxAttempts++;
|
|
1072
1099
|
const portsForThisMx = mxHost === primaryMx && cachedPort ? [cachedPort, ...ports.filter((p) => p !== cachedPort)] : ports;
|
|
1073
1100
|
for (const port of portsForThisMx) {
|
|
1101
|
+
if (totalDeadlineMs !== void 0 && Date.now() - startedAtMs >= totalDeadlineMs) {
|
|
1102
|
+
stoppedEarly = "deadline";
|
|
1103
|
+
break outer;
|
|
1104
|
+
}
|
|
1074
1105
|
portAttempts++;
|
|
1075
1106
|
log(`Testing ${mxHost}:${port}`);
|
|
1076
|
-
const probe = await
|
|
1107
|
+
const probe = await probeWithRetry(mxHost, port);
|
|
1077
1108
|
collectTranscript(transcript, commands, probe, mxHost, port);
|
|
1078
1109
|
lastReason = probe.reason;
|
|
1079
1110
|
if (probe.enhancedStatus !== void 0)
|
|
@@ -1092,8 +1123,15 @@ async function verifyMailboxSMTP(params) {
|
|
|
1092
1123
|
await safeCacheSet(portCache, primaryMx, port);
|
|
1093
1124
|
return { smtpResult: smtpResult2, cached: false, port, portCached: cachedPort === port };
|
|
1094
1125
|
}
|
|
1126
|
+
consecutiveFailures = isConnectionFailure(probe.reason) ? consecutiveFailures + 1 : 0;
|
|
1127
|
+
if (maxConsecutiveFailures !== void 0 && consecutiveFailures >= maxConsecutiveFailures) {
|
|
1128
|
+
stoppedEarly = "consecutive_failures";
|
|
1129
|
+
break outer;
|
|
1130
|
+
}
|
|
1095
1131
|
}
|
|
1096
1132
|
}
|
|
1133
|
+
if (stoppedEarly)
|
|
1134
|
+
log(`Stopped early: ${stoppedEarly}`);
|
|
1097
1135
|
log(`All MX\xD7port attempts failed (mx=${mxAttempts}, port=${portAttempts})`);
|
|
1098
1136
|
const metrics = makeMetrics(mxHostsTried, mxAttempts, portAttempts, void 0, startedAtMs);
|
|
1099
1137
|
const smtpResult = {
|
|
@@ -1240,17 +1278,17 @@ class SMTPProbeConnection {
|
|
|
1240
1278
|
} else {
|
|
1241
1279
|
this.socket = net__namespace.connect({ host: this.p.mxHost, port: this.p.port }, onConnect);
|
|
1242
1280
|
}
|
|
1243
|
-
this.socket.setTimeout(this.p.
|
|
1281
|
+
this.socket.setTimeout(this.p.perAttemptTimeoutMs, () => this.finish(null, "socket_timeout"));
|
|
1244
1282
|
this.socket.on("error", () => this.finish(null, "connection_error"));
|
|
1245
1283
|
this.socket.on("close", () => this.finish(null, "connection_closed"));
|
|
1246
1284
|
}
|
|
1247
1285
|
armConnectionTimer() {
|
|
1248
|
-
this.connectionTimer = setTimeout(() => this.finish(null, "connection_timeout"), this.p.
|
|
1286
|
+
this.connectionTimer = setTimeout(() => this.finish(null, "connection_timeout"), this.p.perAttemptTimeoutMs);
|
|
1249
1287
|
}
|
|
1250
1288
|
resetStepTimer() {
|
|
1251
1289
|
if (this.stepTimer)
|
|
1252
1290
|
clearTimeout(this.stepTimer);
|
|
1253
|
-
this.stepTimer = setTimeout(() => this.finish(null, "step_timeout"), this.p.
|
|
1291
|
+
this.stepTimer = setTimeout(() => this.finish(null, "step_timeout"), this.p.perAttemptTimeoutMs);
|
|
1254
1292
|
}
|
|
1255
1293
|
send(cmd) {
|
|
1256
1294
|
var _a;
|
|
@@ -1279,10 +1317,10 @@ class SMTPProbeConnection {
|
|
|
1279
1317
|
return;
|
|
1280
1318
|
// server-driven; nothing to send
|
|
1281
1319
|
case exports.SMTPStep.ehlo:
|
|
1282
|
-
this.send(`EHLO ${this.p.
|
|
1320
|
+
this.send(`EHLO ${this.p.heloHostname}`);
|
|
1283
1321
|
return;
|
|
1284
1322
|
case exports.SMTPStep.helo:
|
|
1285
|
-
this.send(`HELO ${this.p.
|
|
1323
|
+
this.send(`HELO ${this.p.heloHostname}`);
|
|
1286
1324
|
return;
|
|
1287
1325
|
case exports.SMTPStep.startTls:
|
|
1288
1326
|
this.executeStartTls();
|
|
@@ -1354,7 +1392,7 @@ class SMTPProbeConnection {
|
|
|
1354
1392
|
this.supportsStartTls = false;
|
|
1355
1393
|
this.supportsPipelining = false;
|
|
1356
1394
|
this.postUpgradeReEhlo = true;
|
|
1357
|
-
this.send(`EHLO ${this.p.
|
|
1395
|
+
this.send(`EHLO ${this.p.heloHostname}`);
|
|
1358
1396
|
});
|
|
1359
1397
|
this.socket = tlsSocket;
|
|
1360
1398
|
this.socket.on("data", this.onData);
|
|
@@ -1362,7 +1400,7 @@ class SMTPProbeConnection {
|
|
|
1362
1400
|
this.finish(null, this.tlsUpgrading ? "tls_handshake_failed" : "connection_error");
|
|
1363
1401
|
});
|
|
1364
1402
|
this.socket.on("close", () => this.finish(null, "connection_closed"));
|
|
1365
|
-
this.socket.setTimeout(this.p.
|
|
1403
|
+
this.socket.setTimeout(this.p.perAttemptTimeoutMs, () => this.finish(null, "socket_timeout"));
|
|
1366
1404
|
}
|
|
1367
1405
|
/**
|
|
1368
1406
|
* Send the dual-probe envelope (real RCPT + probe RCPT + RSET). Pipelined
|
|
@@ -2331,11 +2369,11 @@ async function runWhoisChecks(domain, params, result, skipWhois, log, collector)
|
|
|
2331
2369
|
log(`[verifyEmail] WHOIS checks skipped for disposable: ${domain}`);
|
|
2332
2370
|
return;
|
|
2333
2371
|
}
|
|
2334
|
-
const
|
|
2372
|
+
const whoisTimeoutMs = (_a = params.whoisTimeoutMs) !== null && _a !== void 0 ? _a : 5e3;
|
|
2335
2373
|
const debug = (_b = params.debug) !== null && _b !== void 0 ? _b : false;
|
|
2336
2374
|
if (params.checkDomainAge) {
|
|
2337
2375
|
try {
|
|
2338
|
-
result.domainAge = await collector.record("whois-age", () => getDomainAge(domain,
|
|
2376
|
+
result.domainAge = await collector.record("whois-age", () => getDomainAge(domain, whoisTimeoutMs, debug, params.cache), (info) => {
|
|
2339
2377
|
var _a2, _b2, _c2, _d2, _e, _f;
|
|
2340
2378
|
return {
|
|
2341
2379
|
domain,
|
|
@@ -2354,7 +2392,7 @@ async function runWhoisChecks(domain, params, result, skipWhois, log, collector)
|
|
|
2354
2392
|
}
|
|
2355
2393
|
if (params.checkDomainRegistration) {
|
|
2356
2394
|
try {
|
|
2357
|
-
result.domainRegistration = await collector.record("whois-registration", () => getDomainRegistrationStatus(domain,
|
|
2395
|
+
result.domainRegistration = await collector.record("whois-registration", () => getDomainRegistrationStatus(domain, whoisTimeoutMs, debug, params.cache), (info) => {
|
|
2358
2396
|
var _a2, _b2, _c2, _d2, _e, _f;
|
|
2359
2397
|
return {
|
|
2360
2398
|
domain,
|
|
@@ -2425,7 +2463,11 @@ async function runSmtp(local, domain, mxRecords, params, result, log, collector)
|
|
|
2425
2463
|
options: {
|
|
2426
2464
|
cache: params.cache,
|
|
2427
2465
|
ports: resolveSmtpPorts(params.smtpPort, mxRecords[0]),
|
|
2428
|
-
|
|
2466
|
+
perAttemptTimeoutMs: (_a = params.smtpPerAttemptTimeoutMs) !== null && _a !== void 0 ? _a : 4e3,
|
|
2467
|
+
totalDeadlineMs: params.smtpTotalDeadlineMs,
|
|
2468
|
+
maxConsecutiveFailures: params.smtpMaxConsecutiveFailures,
|
|
2469
|
+
maxMxHosts: params.smtpMaxMxHosts,
|
|
2470
|
+
retry: params.smtpRetry,
|
|
2429
2471
|
debug: (_b = params.debug) !== null && _b !== void 0 ? _b : false,
|
|
2430
2472
|
// Forward transcript capture so the SMTP step's details include
|
|
2431
2473
|
// the full per-port transcript when the caller asked for it.
|
|
@@ -2466,7 +2508,7 @@ function smtpVerdictFor(validSmtp) {
|
|
|
2466
2508
|
}
|
|
2467
2509
|
|
|
2468
2510
|
async function verifyEmailBatch(params) {
|
|
2469
|
-
const { emailAddresses, concurrency = 5,
|
|
2511
|
+
const { emailAddresses, concurrency = 5, smtpPerAttemptTimeoutMs = 4e3, smtpTotalDeadlineMs, smtpMaxConsecutiveFailures, smtpMaxMxHosts, smtpRetry, verifyMx = true, verifySmtp = false, checkDisposable = true, checkFree = true, detectName = false, nameDetectionMethod, suggestDomain = false, domainSuggestionMethod, commonDomains, skipMxForDisposable = false, skipDomainWhoisForDisposable = false, cache } = params;
|
|
2470
2512
|
const startTime = Date.now();
|
|
2471
2513
|
const results = /* @__PURE__ */ new Map();
|
|
2472
2514
|
const batches = [];
|
|
@@ -2481,7 +2523,11 @@ async function verifyEmailBatch(params) {
|
|
|
2481
2523
|
try {
|
|
2482
2524
|
const result = await verifyEmail({
|
|
2483
2525
|
emailAddress: email,
|
|
2484
|
-
|
|
2526
|
+
smtpPerAttemptTimeoutMs,
|
|
2527
|
+
smtpTotalDeadlineMs,
|
|
2528
|
+
smtpMaxConsecutiveFailures,
|
|
2529
|
+
smtpMaxMxHosts,
|
|
2530
|
+
smtpRetry,
|
|
2485
2531
|
verifyMx,
|
|
2486
2532
|
verifySmtp,
|
|
2487
2533
|
checkDisposable,
|
|
@@ -2781,6 +2827,7 @@ exports.cleanNameForAlgorithm = cleanNameForAlgorithm;
|
|
|
2781
2827
|
exports.clearDefaultCache = clearDefaultCache;
|
|
2782
2828
|
exports.commonEmailDomains = commonEmailDomains;
|
|
2783
2829
|
exports.defaultDomainSuggestionMethod = defaultDomainSuggestionMethod;
|
|
2830
|
+
exports.defaultDomainSuggestionMethodAsync = defaultDomainSuggestionMethodAsync;
|
|
2784
2831
|
exports.defaultNameDetectionMethod = defaultNameDetectionMethod;
|
|
2785
2832
|
exports.detectName = detectName;
|
|
2786
2833
|
exports.detectNameForAlgorithm = detectNameForAlgorithm;
|
|
@@ -2798,10 +2845,14 @@ exports.isSpamEmail = isSpamEmail;
|
|
|
2798
2845
|
exports.isSpamName = isSpamName;
|
|
2799
2846
|
exports.isValidEmail = isValidEmail;
|
|
2800
2847
|
exports.isValidEmailDomain = isValidEmailDomain;
|
|
2848
|
+
exports.parseDsn = parseDsn;
|
|
2801
2849
|
exports.parseSmtpError = parseSmtpError;
|
|
2850
|
+
exports.parseWhoisData = parseWhoisData;
|
|
2802
2851
|
exports.refineReasonByEnhancedStatus = refineReasonByEnhancedStatus;
|
|
2852
|
+
exports.resolveMxRecords = resolveMxRecords;
|
|
2803
2853
|
exports.suggestDomain = suggestDomain;
|
|
2804
2854
|
exports.suggestEmailDomain = suggestEmailDomain;
|
|
2805
2855
|
exports.verifyEmail = verifyEmail;
|
|
2806
2856
|
exports.verifyEmailBatch = verifyEmailBatch;
|
|
2857
|
+
exports.verifyMailboxSMTP = verifyMailboxSMTP;
|
|
2807
2858
|
//# sourceMappingURL=index.js.map
|