@emailcheck/email-validator-js 3.4.4 → 4.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/index.esm.js CHANGED
@@ -2,6 +2,7 @@ import { lru } from 'tiny-lru';
2
2
  import { isValid, parse } from 'psl';
3
3
  import { stringSimilarity } from 'string-similarity-js';
4
4
  import { promises } from 'node:dns';
5
+ import { randomBytes } from 'node:crypto';
5
6
  import * as net$1 from 'node:net';
6
7
  import * as tls from 'node:tls';
7
8
 
@@ -658,9 +659,9 @@ function parseCompositeNamePart(part) {
658
659
  cleaned = pureAlpha;
659
660
  confidence = 0.6;
660
661
  } else {
661
- const baseMatch2 = part.match(/^([a-zA-Z]+)\d*$/);
662
- if (baseMatch2) {
663
- cleaned = baseMatch2[1];
662
+ const baseMatch = part.match(/^([a-zA-Z]+)\d*$/);
663
+ if (baseMatch) {
664
+ cleaned = baseMatch[1];
664
665
  confidence = 0.75;
665
666
  } else {
666
667
  cleaned = part;
@@ -674,9 +675,7 @@ function parseCompositeNamePart(part) {
674
675
  confidence = Math.min(1, confidence + 0.2);
675
676
  }
676
677
  }
677
- const baseMatch = part.match(/^([a-zA-Z]+[a-zA-Z0-9]*?)\d*$/);
678
- const base = baseMatch ? baseMatch[1] : part;
679
- return { base, hasNumbers, cleaned, confidence };
678
+ return { hasNumbers, cleaned, confidence };
680
679
  }
681
680
  function isLikelyName(str, allowNumbers = false, allowSingleLetter = false) {
682
681
  if (!str)
@@ -967,6 +966,9 @@ function parseDsn(reply) {
967
966
  return null;
968
967
  return { class: Number(match[1]), subject: Number(match[2]), detail: Number(match[3]) };
969
968
  }
969
+ function dsnToString(dsn) {
970
+ return `${dsn.class}.${dsn.subject}.${dsn.detail}`;
971
+ }
970
972
  function isPolicyBlock(reply) {
971
973
  const dsn = parseDsn(reply);
972
974
  return (dsn === null || dsn === void 0 ? void 0 : dsn.class) === 5 && (dsn === null || dsn === void 0 ? void 0 : dsn.subject) === 7;
@@ -987,8 +989,11 @@ function isInvalidMailboxError(reply) {
987
989
  return false;
988
990
  return true;
989
991
  }
992
+ function defaultProbeLocal() {
993
+ return `${randomBytes(8).toString("hex")}-noexist`;
994
+ }
990
995
  async function verifyMailboxSMTP(params) {
991
- var _a, _b, _c, _d, _e, _f, _g;
996
+ var _a, _b, _c, _d, _e, _f, _g, _h;
992
997
  const { local, domain, options = {} } = params;
993
998
  const mxRecords = (_a = params.mxRecords) !== null && _a !== void 0 ? _a : [];
994
999
  const ports = ((_b = options.ports) !== null && _b !== void 0 ? _b : DEFAULT_PORTS).filter((port) => Number.isInteger(port) && port > 0 && port < 65536);
@@ -1001,16 +1006,29 @@ async function verifyMailboxSMTP(params) {
1001
1006
  const cache = options.cache;
1002
1007
  const log = debug ? (...args) => console.log("[SMTP]", ...args) : () => {
1003
1008
  };
1004
- const mxHost = mxRecords[0];
1005
- if (!mxHost) {
1009
+ const startedAtMs = Date.now();
1010
+ const primaryMx = mxRecords[0];
1011
+ if (!primaryMx) {
1006
1012
  log("No MX records found");
1007
- return { smtpResult: failureResult("No MX records found"), cached: false, port: 0, portCached: false };
1013
+ const metrics2 = makeMetrics([], 0, 0, void 0, startedAtMs);
1014
+ return { smtpResult: failureResult("no_mx_records", metrics2), cached: false, port: 0, portCached: false };
1008
1015
  }
1009
- log(`Verifying ${local}@${domain} via ${mxHost}`);
1016
+ log(`Verifying ${local}@${domain} via ${primaryMx} (mx count=${mxRecords.length})`);
1010
1017
  const transcript = [];
1011
1018
  const commands = [];
1019
+ const probeOptions = {
1020
+ local,
1021
+ domain,
1022
+ timeout,
1023
+ tlsConfig,
1024
+ hostname,
1025
+ sequence,
1026
+ log,
1027
+ catchAllProbeLocal: options.catchAllProbeLocal,
1028
+ pipelining: (_h = options.pipelining) !== null && _h !== void 0 ? _h : "auto"
1029
+ };
1012
1030
  const verdictCache = cache ? getCacheStore(cache, "smtp") : null;
1013
- const verdictKey = `${mxHost}:${local}@${domain}`;
1031
+ const verdictKey = `${primaryMx}:${local}@${domain}`;
1014
1032
  if (verdictCache) {
1015
1033
  const cachedResult = await safeCacheGet(verdictCache, verdictKey);
1016
1034
  if (cachedResult) {
@@ -1019,81 +1037,99 @@ async function verifyMailboxSMTP(params) {
1019
1037
  }
1020
1038
  }
1021
1039
  const portCache = cache ? getCacheStore(cache, "smtpPort") : null;
1022
- if (portCache) {
1023
- const cachedPort = await safeCacheGet(portCache, mxHost);
1024
- if (cachedPort) {
1025
- log(`Using cached port: ${cachedPort}`);
1026
- const probe = await runProbe({
1027
- mxHost,
1028
- port: cachedPort,
1029
- local,
1030
- domain,
1031
- timeout,
1032
- tlsConfig,
1033
- hostname,
1034
- sequence,
1035
- log
1036
- });
1037
- collectTranscript(transcript, commands, probe, cachedPort);
1038
- const smtpResult = toSmtpVerificationResult(probe.result, captureTranscript ? { transcript, commands } : void 0);
1039
- await safeCacheSet(verdictCache, verdictKey, smtpResult);
1040
- return { smtpResult, cached: false, port: cachedPort, portCached: true };
1041
- }
1042
- }
1043
- for (const port of ports) {
1044
- log(`Testing port ${port}`);
1045
- const probe = await runProbe({ mxHost, port, local, domain, timeout, tlsConfig, hostname, sequence, log });
1046
- collectTranscript(transcript, commands, probe, port);
1047
- const smtpResult = toSmtpVerificationResult(probe.result, captureTranscript ? { transcript, commands } : void 0);
1048
- await safeCacheSet(verdictCache, verdictKey, smtpResult);
1049
- if (probe.result !== null) {
1050
- await safeCacheSet(portCache, mxHost, port);
1051
- return { smtpResult, cached: false, port, portCached: false };
1040
+ const cachedPort = portCache ? await safeCacheGet(portCache, primaryMx) : null;
1041
+ const mxHostsTried = [];
1042
+ let mxAttempts = 0;
1043
+ let portAttempts = 0;
1044
+ let lastReason = "all_attempts_failed";
1045
+ let lastEnhancedStatus;
1046
+ let lastResponseCode;
1047
+ for (const mxHost of mxRecords) {
1048
+ mxHostsTried.push(mxHost);
1049
+ mxAttempts++;
1050
+ const portsForThisMx = mxHost === primaryMx && cachedPort ? [cachedPort, ...ports.filter((p) => p !== cachedPort)] : ports;
1051
+ for (const port of portsForThisMx) {
1052
+ portAttempts++;
1053
+ log(`Testing ${mxHost}:${port}`);
1054
+ const probe = await runProbe({ ...probeOptions, mxHost, port });
1055
+ collectTranscript(transcript, commands, probe, mxHost, port);
1056
+ lastReason = probe.reason;
1057
+ if (probe.enhancedStatus !== void 0)
1058
+ lastEnhancedStatus = probe.enhancedStatus;
1059
+ if (probe.responseCode !== void 0)
1060
+ lastResponseCode = probe.responseCode;
1061
+ if (probe.result !== null) {
1062
+ const metrics2 = makeMetrics(mxHostsTried, mxAttempts, portAttempts, mxHost, startedAtMs);
1063
+ const smtpResult2 = toSmtpVerificationResult(probe, {
1064
+ transcript: captureTranscript ? transcript : void 0,
1065
+ commands: captureTranscript ? commands : void 0,
1066
+ metrics: metrics2
1067
+ });
1068
+ await safeCacheSet(verdictCache, verdictKey, smtpResult2);
1069
+ if (mxHost === primaryMx)
1070
+ await safeCacheSet(portCache, primaryMx, port);
1071
+ return { smtpResult: smtpResult2, cached: false, port, portCached: cachedPort === port };
1072
+ }
1052
1073
  }
1053
1074
  }
1054
- log("All ports failed");
1075
+ log(`All MX\xD7port attempts failed (mx=${mxAttempts}, port=${portAttempts})`);
1076
+ const metrics = makeMetrics(mxHostsTried, mxAttempts, portAttempts, void 0, startedAtMs);
1077
+ const smtpResult = {
1078
+ ...failureResult(lastReason, metrics),
1079
+ ...lastEnhancedStatus !== void 0 ? { enhancedStatus: lastEnhancedStatus } : {},
1080
+ ...lastResponseCode !== void 0 ? { responseCode: lastResponseCode } : {},
1081
+ ...captureTranscript ? { transcript: [...transcript], commands: [...commands] } : {}
1082
+ };
1083
+ return { smtpResult, cached: false, port: 0, portCached: false };
1084
+ }
1085
+ function makeMetrics(mxHostsTried, mxAttempts, portAttempts, mxHostUsed, startedAtMs) {
1055
1086
  return {
1056
- smtpResult: {
1057
- ...failureResult("All SMTP connection attempts failed"),
1058
- ...captureTranscript ? { transcript: [...transcript], commands: [...commands] } : {}
1059
- },
1060
- cached: false,
1061
- port: 0,
1062
- portCached: false
1087
+ mxAttempts,
1088
+ portAttempts,
1089
+ mxHostsTried: [...mxHostsTried],
1090
+ ...mxHostUsed !== void 0 ? { mxHostUsed } : {},
1091
+ totalDurationMs: Date.now() - startedAtMs
1063
1092
  };
1064
1093
  }
1065
- function collectTranscript(transcript, commands, probe, port) {
1094
+ function collectTranscript(transcript, commands, probe, mxHost, port) {
1095
+ const prefix = `${mxHost}:${port}`;
1066
1096
  for (const line of probe.transcript)
1067
- transcript.push(`${port}|s| ${line}`);
1097
+ transcript.push(`${prefix}|s| ${line}`);
1068
1098
  for (const cmd of probe.commands)
1069
- commands.push(`${port}|c| ${cmd}`);
1099
+ commands.push(`${prefix}|c| ${cmd}`);
1070
1100
  }
1071
- function failureResult(error) {
1101
+ function failureResult(reason, metrics) {
1072
1102
  return {
1073
1103
  canConnectSmtp: false,
1074
1104
  hasFullInbox: false,
1075
1105
  isCatchAll: false,
1076
1106
  isDeliverable: false,
1077
1107
  isDisabled: false,
1078
- error,
1079
- providerUsed: EmailProvider.everythingElse,
1080
- checkedAt: Date.now()
1108
+ error: reason,
1109
+ checkedAt: Date.now(),
1110
+ metrics
1081
1111
  };
1082
1112
  }
1083
- function toSmtpVerificationResult(result, capture) {
1084
- const base = {
1113
+ function toSmtpVerificationResult(probe, extras) {
1114
+ var _a;
1115
+ const result = probe.result;
1116
+ const out = {
1085
1117
  canConnectSmtp: result !== null,
1086
- hasFullInbox: false,
1087
- isCatchAll: false,
1118
+ hasFullInbox: probe.reason === "over_quota",
1119
+ isCatchAll: (_a = probe.isCatchAll) !== null && _a !== void 0 ? _a : false,
1088
1120
  isDeliverable: result === true,
1089
1121
  isDisabled: result === false,
1090
- error: result === true ? void 0 : result === null ? "ambiguous" : "not_found",
1091
- providerUsed: EmailProvider.everythingElse,
1092
- checkedAt: Date.now()
1122
+ error: result === true ? void 0 : probe.reason,
1123
+ checkedAt: Date.now(),
1124
+ metrics: extras.metrics,
1125
+ ...probe.enhancedStatus !== void 0 ? { enhancedStatus: probe.enhancedStatus } : {},
1126
+ ...probe.responseCode !== void 0 ? { responseCode: probe.responseCode } : {}
1093
1127
  };
1094
- if (!capture)
1095
- return base;
1096
- return { ...base, transcript: [...capture.transcript], commands: [...capture.commands] };
1128
+ if (extras.transcript)
1129
+ out.transcript = [...extras.transcript];
1130
+ if (extras.commands)
1131
+ out.commands = [...extras.commands];
1132
+ return out;
1097
1133
  }
1098
1134
  async function safeCacheGet(store, key) {
1099
1135
  if (!store)
@@ -1125,6 +1161,12 @@ class SMTPProbeConnection {
1125
1161
  this.currentStepIndex = 0;
1126
1162
  this.transcript = [];
1127
1163
  this.commands = [];
1164
+ this.supportsPipelining = false;
1165
+ this.dualPhase = "idle";
1166
+ this.realOutcome = "pending";
1167
+ this.probeOutcome = "pending";
1168
+ this.dualPipelined = false;
1169
+ this.pendingDecision = null;
1128
1170
  this.onData = (data) => {
1129
1171
  if (this.resolved)
1130
1172
  return;
@@ -1148,6 +1190,7 @@ class SMTPProbeConnection {
1148
1190
  minVersion: "TLSv1.2",
1149
1191
  ...typeof p.tlsConfig === "object" ? p.tlsConfig : {}
1150
1192
  };
1193
+ this.probeLocal = p.catchAllProbeLocal ? p.catchAllProbeLocal(p.local, p.domain) : defaultProbeLocal();
1151
1194
  }
1152
1195
  run() {
1153
1196
  return new Promise((resolve) => {
@@ -1208,6 +1251,7 @@ class SMTPProbeConnection {
1208
1251
  switch (step) {
1209
1252
  case SMTPStep.greeting:
1210
1253
  return;
1254
+ // server-driven; nothing to send
1211
1255
  case SMTPStep.ehlo:
1212
1256
  this.send(`EHLO ${this.p.hostname}`);
1213
1257
  return;
@@ -1220,39 +1264,87 @@ class SMTPProbeConnection {
1220
1264
  return;
1221
1265
  }
1222
1266
  case SMTPStep.rcptTo:
1223
- this.send(`RCPT TO:<${this.p.local}@${this.p.domain}>`);
1267
+ this.executeEnvelope();
1224
1268
  return;
1225
1269
  }
1226
1270
  }
1271
+ /**
1272
+ * Send the dual-probe envelope (real RCPT + probe RCPT + RSET). Pipelined
1273
+ * when the MX advertised PIPELINING (or `pipelining: 'force'`); sequential
1274
+ * otherwise.
1275
+ */
1276
+ executeEnvelope() {
1277
+ var _a;
1278
+ const wantsPipelining = this.p.pipelining === "force" || this.p.pipelining === "auto" && this.supportsPipelining;
1279
+ const realCmd = `RCPT TO:<${this.p.local}@${this.p.domain}>`;
1280
+ if (wantsPipelining) {
1281
+ this.dualPipelined = true;
1282
+ const probeCmd = `RCPT TO:<${this.probeLocal}@${this.p.domain}>`;
1283
+ const rsetCmd = "RSET";
1284
+ this.commands.push(realCmd, probeCmd, rsetCmd);
1285
+ this.p.log(`\u2192 ${realCmd}`);
1286
+ this.p.log(`\u2192 ${probeCmd}`);
1287
+ this.p.log(`\u2192 ${rsetCmd}`);
1288
+ (_a = this.socket) === null || _a === void 0 ? void 0 : _a.write(`${realCmd}\r
1289
+ ${probeCmd}\r
1290
+ ${rsetCmd}\r
1291
+ `);
1292
+ this.dualPhase = "rcpt_real";
1293
+ return;
1294
+ }
1295
+ this.dualPipelined = false;
1296
+ this.send(realCmd);
1297
+ this.dualPhase = "rcpt_real";
1298
+ }
1227
1299
  processLine(line) {
1228
1300
  if (this.resolved)
1229
1301
  return;
1230
1302
  this.transcript.push(line);
1231
1303
  this.p.log(`\u2190 ${line}`);
1232
- if (isHighVolume(line)) {
1233
- this.finish(true, "high_volume");
1234
- return;
1235
- }
1236
- if (isOverQuota(line)) {
1237
- this.finish(false, "over_quota");
1238
- return;
1304
+ const codeStr = line.slice(0, 3);
1305
+ const numericCode = /^\d{3}$/.test(codeStr) ? parseInt(codeStr, 10) : null;
1306
+ if (numericCode !== null)
1307
+ this.lastResponseCode = numericCode;
1308
+ const dsn = parseDsn(line);
1309
+ if (dsn)
1310
+ this.lastEnhancedStatus = dsnToString(dsn);
1311
+ if (this.dualPhase === "idle" || this.dualPhase === "rcpt_real") {
1312
+ if (isHighVolume(line)) {
1313
+ this.finish(true, "high_volume");
1314
+ return;
1315
+ }
1316
+ if (isOverQuota(line)) {
1317
+ this.isCatchAllFlag = false;
1318
+ this.finish(false, "over_quota");
1319
+ return;
1320
+ }
1321
+ if (isInvalidMailboxError(line)) {
1322
+ this.isCatchAllFlag = false;
1323
+ this.finish(false, "not_found");
1324
+ return;
1325
+ }
1239
1326
  }
1240
- if (isInvalidMailboxError(line)) {
1241
- this.finish(false, "not_found");
1327
+ if (MULTILINE_RE.test(line)) {
1328
+ const step = this.steps[this.currentStepIndex];
1329
+ if ((step === SMTPStep.ehlo || step === SMTPStep.helo) && line.startsWith("250-")) {
1330
+ const upper = line.toUpperCase();
1331
+ if (upper.includes("PIPELINING"))
1332
+ this.supportsPipelining = true;
1333
+ }
1242
1334
  return;
1243
1335
  }
1244
- if (MULTILINE_RE.test(line))
1245
- return;
1246
- const code = line.slice(0, 3);
1247
- const numericCode = /^\d{3}$/.test(code) ? parseInt(code, 10) : null;
1248
1336
  if (numericCode === null) {
1249
1337
  this.finish(null, "unrecognized_response");
1250
1338
  return;
1251
1339
  }
1252
- this.dispatch(numericCode);
1340
+ this.dispatch(numericCode, line);
1253
1341
  }
1254
- dispatch(code) {
1342
+ dispatch(code, line) {
1255
1343
  const step = this.steps[this.currentStepIndex];
1344
+ if (this.dualPhase !== "idle" && step === SMTPStep.rcptTo) {
1345
+ this.handleEnvelopeReply(code, line);
1346
+ return;
1347
+ }
1256
1348
  switch (step) {
1257
1349
  case SMTPStep.greeting:
1258
1350
  if (code === 220)
@@ -1279,17 +1371,93 @@ class SMTPProbeConnection {
1279
1371
  this.finish(null, "mail_from_rejected");
1280
1372
  return;
1281
1373
  case SMTPStep.rcptTo:
1282
- if (code === 250 || code === 251)
1283
- this.finish(true, "valid");
1284
- else if (code === 552 || code === 452)
1285
- this.finish(false, "over_quota");
1286
- else if (code >= 400 && code < 500)
1287
- this.finish(null, "temporary_failure");
1288
- else
1289
- this.finish(null, "ambiguous");
1374
+ this.handleEnvelopeReply(code, line);
1290
1375
  return;
1291
1376
  }
1292
1377
  }
1378
+ /**
1379
+ * Dual-probe / pipelined-envelope reply router. Demuxes server replies for
1380
+ * the three queued commands (real RCPT, probe RCPT, RSET) and resolves
1381
+ * with the catch-all-aware verdict.
1382
+ */
1383
+ handleEnvelopeReply(code, line) {
1384
+ if (this.dualPhase === "rcpt_real") {
1385
+ this.realOutcome = classifyRcpt(code);
1386
+ if (code === 552 || code === 452 || isOverQuota(line)) {
1387
+ this.isCatchAllFlag = false;
1388
+ if (this.dualPipelined) {
1389
+ this.pendingDecision = { result: false, reason: "over_quota" };
1390
+ this.dualPhase = "rcpt_probe";
1391
+ return;
1392
+ }
1393
+ this.finish(false, "over_quota");
1394
+ return;
1395
+ }
1396
+ if (this.realOutcome === "soft_reject") {
1397
+ if (this.dualPipelined) {
1398
+ this.pendingDecision = { result: null, reason: "temporary_failure" };
1399
+ this.dualPhase = "rcpt_probe";
1400
+ return;
1401
+ }
1402
+ this.finish(null, "temporary_failure");
1403
+ return;
1404
+ }
1405
+ if (this.realOutcome === "hard_reject") {
1406
+ const reason = isInvalidMailboxError(line) ? "not_found" : "ambiguous";
1407
+ const result = reason === "not_found" ? false : null;
1408
+ this.isCatchAllFlag = false;
1409
+ if (this.dualPipelined) {
1410
+ this.pendingDecision = { result, reason };
1411
+ this.dualPhase = "rcpt_probe";
1412
+ return;
1413
+ }
1414
+ this.finish(result, reason);
1415
+ return;
1416
+ }
1417
+ if (this.dualPipelined) {
1418
+ this.dualPhase = "rcpt_probe";
1419
+ } else {
1420
+ this.send(`RCPT TO:<${this.probeLocal}@${this.p.domain}>`);
1421
+ this.dualPhase = "rcpt_probe";
1422
+ }
1423
+ return;
1424
+ }
1425
+ if (this.dualPhase === "rcpt_probe") {
1426
+ this.probeOutcome = classifyRcpt(code);
1427
+ if (this.dualPipelined) {
1428
+ this.dualPhase = "rset";
1429
+ } else {
1430
+ this.send("RSET");
1431
+ this.dualPhase = "rset";
1432
+ }
1433
+ return;
1434
+ }
1435
+ if (this.dualPhase === "rset") {
1436
+ if (this.pendingDecision) {
1437
+ this.finish(this.pendingDecision.result, this.pendingDecision.reason);
1438
+ return;
1439
+ }
1440
+ this.decideDualProbe();
1441
+ return;
1442
+ }
1443
+ }
1444
+ /** Final decision after both RCPT outcomes are known. Catch-all only when both 250. */
1445
+ decideDualProbe() {
1446
+ if (this.realOutcome === "accept" && this.probeOutcome === "accept") {
1447
+ this.isCatchAllFlag = true;
1448
+ this.finish(true, "valid");
1449
+ } else if (this.realOutcome === "accept") {
1450
+ this.isCatchAllFlag = false;
1451
+ this.finish(true, "valid");
1452
+ } else if (this.realOutcome === "hard_reject") {
1453
+ this.isCatchAllFlag = false;
1454
+ this.finish(false, "not_found");
1455
+ } else if (this.realOutcome === "soft_reject") {
1456
+ this.finish(null, "temporary_failure");
1457
+ } else {
1458
+ this.finish(null, "ambiguous");
1459
+ }
1460
+ }
1293
1461
  finish(result, reason) {
1294
1462
  var _a, _b, _c;
1295
1463
  if (this.resolved)
@@ -1313,9 +1481,24 @@ class SMTPProbeConnection {
1313
1481
  return (_a2 = this.socket) === null || _a2 === void 0 ? void 0 : _a2.destroy();
1314
1482
  }, QUIT_DRAIN_MS);
1315
1483
  (_c = drain.unref) === null || _c === void 0 ? void 0 : _c.call(drain);
1316
- this.resolveFn({ result, transcript: this.transcript, commands: this.commands });
1484
+ this.resolveFn({
1485
+ result,
1486
+ reason,
1487
+ ...this.lastEnhancedStatus !== void 0 ? { enhancedStatus: this.lastEnhancedStatus } : {},
1488
+ ...this.lastResponseCode !== void 0 ? { responseCode: this.lastResponseCode } : {},
1489
+ ...this.isCatchAllFlag !== void 0 ? { isCatchAll: this.isCatchAllFlag } : {},
1490
+ transcript: this.transcript,
1491
+ commands: this.commands
1492
+ });
1317
1493
  }
1318
1494
  }
1495
+ function classifyRcpt(code) {
1496
+ if (code === 250 || code === 251)
1497
+ return "accept";
1498
+ if (code >= 400 && code < 500)
1499
+ return "soft_reject";
1500
+ return "hard_reject";
1501
+ }
1319
1502
 
1320
1503
  class ArrayTranscriptCollector {
1321
1504
  constructor() {
@@ -1988,12 +2171,11 @@ async function verifyEmail(params) {
1988
2171
  const skipMx = ((_f = params.skipMxForDisposable) !== null && _f !== void 0 ? _f : false) && result.isDisposable;
1989
2172
  const skipWhois = ((_g = params.skipDomainWhoisForDisposable) !== null && _g !== void 0 ? _g : false) && result.isDisposable;
1990
2173
  await runWhoisChecks(domain, params, result, skipWhois, log, collector);
1991
- if (((_h = params.verifyMx) !== null && _h !== void 0 ? _h : true) || ((_j = params.verifySmtp) !== null && _j !== void 0 ? _j : false)) {
1992
- if (skipMx) {
1993
- log(`[verifyEmail] skipping MX/SMTP for disposable: ${params.emailAddress}`);
1994
- } else {
1995
- await runMxAndSmtp(local, domain, params, result, log, collector);
1996
- }
2174
+ const wantsMxOrSmtp = ((_h = params.verifyMx) !== null && _h !== void 0 ? _h : true) || ((_j = params.verifySmtp) !== null && _j !== void 0 ? _j : false);
2175
+ if (wantsMxOrSmtp && skipMx) {
2176
+ log(`[verifyEmail] skipping MX/SMTP for disposable: ${params.emailAddress}`);
2177
+ } else if (wantsMxOrSmtp) {
2178
+ await runMxAndSmtp(local, domain, params, result, log, collector);
1997
2179
  }
1998
2180
  result.metadata.verificationTime = Date.now() - startTime;
1999
2181
  if (captureTranscript)