@emailcheck/email-validator-js 3.0.1-beta.0 → 3.0.1-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.
Files changed (40) hide show
  1. package/README.md +176 -24
  2. package/dist/adapters/lru-adapter.d.ts +2 -2
  3. package/dist/adapters/redis-adapter.d.ts +4 -4
  4. package/dist/batch-verifier.d.ts +5 -0
  5. package/dist/cache-interface.d.ts +23 -16
  6. package/dist/cache.d.ts +5 -5
  7. package/dist/check-if-email-exists.d.ts +205 -0
  8. package/dist/domain-suggester.d.ts +6 -6
  9. package/dist/{validator.d.ts → email-validator.d.ts} +2 -2
  10. package/dist/email-verifier-types.d.ts +225 -0
  11. package/dist/index.d.ts +8 -8
  12. package/dist/index.esm.js +457 -236
  13. package/dist/index.esm.js.map +1 -1
  14. package/dist/index.js +460 -238
  15. package/dist/index.js.map +1 -1
  16. package/dist/mx-resolver.d.ts +2 -0
  17. package/dist/name-detector.d.ts +6 -6
  18. package/dist/serverless/adapters/aws-lambda.cjs.js.map +1 -1
  19. package/dist/serverless/adapters/aws-lambda.esm.js.map +1 -1
  20. package/dist/serverless/adapters/cloudflare.cjs.js.map +1 -1
  21. package/dist/serverless/adapters/cloudflare.esm.js.map +1 -1
  22. package/dist/serverless/adapters/vercel.cjs.js.map +1 -1
  23. package/dist/serverless/adapters/vercel.esm.js.map +1 -1
  24. package/dist/serverless/index.cjs.js.map +1 -1
  25. package/dist/serverless/index.d.ts +1 -1
  26. package/dist/serverless/index.esm.js.map +1 -1
  27. package/dist/serverless/{core.cjs.js → verifier.cjs.js} +1 -1
  28. package/dist/serverless/verifier.cjs.js.map +1 -0
  29. package/dist/serverless/{core.esm.js → verifier.esm.js} +1 -1
  30. package/dist/serverless/verifier.esm.js.map +1 -0
  31. package/dist/{smtp.d.ts → smtp-verifier.d.ts} +2 -2
  32. package/dist/types.d.ts +128 -34
  33. package/dist/whois.d.ts +3 -3
  34. package/package.json +19 -19
  35. package/dist/batch.d.ts +0 -5
  36. package/dist/dns.d.ts +0 -2
  37. package/dist/serverless/core.cjs.js.map +0 -1
  38. package/dist/serverless/core.esm.js.map +0 -1
  39. /package/dist/serverless/{core.d.ts → verifier.d.ts} +0 -0
  40. /package/dist/serverless/{core.min.js → verifier.min.js} +0 -0
package/dist/index.js CHANGED
@@ -2,8 +2,8 @@
2
2
 
3
3
  var psl = require('psl');
4
4
  var tinyLru = require('tiny-lru');
5
- var node_dns = require('node:dns');
6
5
  var stringSimilarityJs = require('string-similarity-js');
6
+ var node_dns = require('node:dns');
7
7
  var net = require('node:net');
8
8
  var tls = require('node:tls');
9
9
 
@@ -66,31 +66,23 @@ class LRUAdapter {
66
66
  const DEFAULT_CACHE_OPTIONS = {
67
67
  ttl: {
68
68
  mx: 36e5,
69
- // 1 hour
70
69
  disposable: 864e5,
71
- // 24 hours
72
70
  free: 864e5,
73
- // 24 hours
74
71
  domainValid: 864e5,
75
- // 24 hours
76
72
  smtp: 18e5,
77
- // 30 minutes
78
- smtpPort: 36e5,
79
- // 1 hour
73
+ smtpPort: 864e5,
80
74
  domainSuggestion: 864e5,
81
- // 24 hours
82
75
  whois: 36e5
83
- // 1 hour
84
76
  },
85
77
  maxSize: {
86
- mx: 500,
87
- disposable: 1e3,
88
- free: 1e3,
89
- domainValid: 1e3,
90
- smtp: 500,
91
- smtpPort: 500,
92
- domainSuggestion: 1e3,
93
- whois: 200
78
+ mx: 1e4,
79
+ disposable: 1e4,
80
+ free: 1e4,
81
+ domainValid: 1e4,
82
+ smtp: 1e4,
83
+ smtpPort: 1e4,
84
+ domainSuggestion: 1e4,
85
+ whois: 1e4
94
86
  }
95
87
  };
96
88
  let defaultCacheInstance = null;
@@ -128,41 +120,7 @@ function resetDefaultCache() {
128
120
  defaultCacheInstance = null;
129
121
  }
130
122
 
131
- async function resolveMxRecords(params) {
132
- const { domain, cache, logger } = params;
133
- const log = logger || (() => {
134
- });
135
- const cacheStore = getCacheStore(cache, "mx");
136
- const cached = await cacheStore.get(domain);
137
- if (cached !== null && cached !== void 0) {
138
- log(`[resolveMxRecords] Cache hit for ${domain}: ${cached.length} MX records`);
139
- return cached;
140
- }
141
- log(`[resolveMxRecords] Performing DNS MX lookup for ${domain}`);
142
- try {
143
- const records = await node_dns.promises.resolveMx(domain);
144
- records.sort((a, b) => {
145
- if (a.priority < b.priority) {
146
- return -1;
147
- }
148
- if (a.priority > b.priority) {
149
- return 1;
150
- }
151
- return 0;
152
- });
153
- const exchanges = records.map((record) => record.exchange);
154
- log(`[resolveMxRecords] Found ${exchanges.length} MX records for ${domain}: [${exchanges.join(", ")}]`);
155
- await cacheStore.set(domain, exchanges);
156
- log(`[resolveMxRecords] Cached ${exchanges.length} MX records for ${domain}`);
157
- return exchanges;
158
- } catch (error) {
159
- log(`[resolveMxRecords] MX lookup failed for ${domain}, caching empty result`);
160
- await cacheStore.set(domain, []);
161
- throw error;
162
- }
163
- }
164
-
165
- const COMMON_EMAIL_DOMAINS = [
123
+ const commonEmailDomains = [
166
124
  // Popular free email providers
167
125
  "gmail.com",
168
126
  "yahoo.com",
@@ -247,7 +205,7 @@ function getSimilarityThreshold(domain) {
247
205
  return 0.75;
248
206
  }
249
207
  function defaultDomainSuggestionMethod(domain, commonDomains) {
250
- const domainsToCheck = commonDomains || COMMON_EMAIL_DOMAINS;
208
+ const domainsToCheck = commonDomains || commonEmailDomains;
251
209
  const lowerDomain = domain.toLowerCase();
252
210
  if (domainsToCheck.includes(lowerDomain)) {
253
211
  return null;
@@ -303,7 +261,7 @@ async function defaultDomainSuggestionMethodImpl(domain, commonDomains, cache) {
303
261
  if (!domain || domain.length < 3) {
304
262
  return null;
305
263
  }
306
- const domainsToCheck = commonDomains || COMMON_EMAIL_DOMAINS;
264
+ const domainsToCheck = commonDomains || commonEmailDomains;
307
265
  const lowerDomain = domain.toLowerCase();
308
266
  const cacheKey = `${lowerDomain}:${domainsToCheck.length}`;
309
267
  const cacheStore = getCacheStore(cache, "domainSuggestion");
@@ -399,15 +357,107 @@ async function suggestEmailDomain(email, commonDomains, cache) {
399
357
  return null;
400
358
  }
401
359
  function isCommonDomain(domain, commonDomains) {
402
- const domainsToCheck = commonDomains || COMMON_EMAIL_DOMAINS;
360
+ const domainsToCheck = commonDomains || commonEmailDomains;
403
361
  return domainsToCheck.includes(domain.toLowerCase());
404
362
  }
405
363
  function getDomainSimilarity(domain1, domain2) {
406
364
  return stringSimilarityJs.stringSimilarity(domain1.toLowerCase(), domain2.toLowerCase());
407
365
  }
408
366
 
409
- const NAME_SEPARATORS = [".", "_", "-"];
410
- const COMMON_NAME_SUFFIXES = [
367
+ async function isValidEmailDomain(emailOrDomain, cache) {
368
+ let [localPart, emailDomain] = (emailOrDomain === null || emailOrDomain === void 0 ? void 0 : emailOrDomain.split("@")) || [];
369
+ if (!emailDomain) {
370
+ emailDomain = localPart;
371
+ }
372
+ if (!emailDomain) {
373
+ return false;
374
+ }
375
+ const cacheStore = getCacheStore(cache, "domainValid");
376
+ const cached = await cacheStore.get(emailDomain);
377
+ if (cached !== null && cached !== void 0) {
378
+ return cached.isValid;
379
+ }
380
+ try {
381
+ const isValidResult = psl.isValid(emailDomain) || false;
382
+ const richResult = {
383
+ isValid: isValidResult,
384
+ hasMX: false,
385
+ // MX not checked in this function
386
+ checkedAt: Date.now()
387
+ };
388
+ await cacheStore.set(emailDomain, richResult);
389
+ return isValidResult;
390
+ } catch (validationError) {
391
+ const errorResult = {
392
+ isValid: false,
393
+ hasMX: false,
394
+ checkedAt: Date.now()
395
+ };
396
+ await cacheStore.set(emailDomain, errorResult);
397
+ return false;
398
+ }
399
+ }
400
+ function isValidEmail(emailAddress) {
401
+ if (!emailAddress || typeof emailAddress !== "string") {
402
+ return false;
403
+ }
404
+ const re = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
405
+ const emailLower = emailAddress.toLowerCase();
406
+ if (emailLower.indexOf(".+") !== -1)
407
+ return false;
408
+ if (emailLower.indexOf("..") !== -1)
409
+ return false;
410
+ if (emailLower.startsWith(".") || emailLower.endsWith("."))
411
+ return false;
412
+ const parts = emailAddress.split("@");
413
+ if (parts.length !== 2)
414
+ return false;
415
+ const [localPart, domain] = parts;
416
+ if (!localPart || !domain)
417
+ return false;
418
+ if (localPart.length > 64)
419
+ return false;
420
+ if (domain.length > 253)
421
+ return false;
422
+ return re.test(emailLower);
423
+ }
424
+
425
+ async function resolveMxRecords(params) {
426
+ const { domain, cache, logger } = params;
427
+ const log = logger || (() => {
428
+ });
429
+ const cacheStore = getCacheStore(cache, "mx");
430
+ const cached = await cacheStore.get(domain);
431
+ if (cached !== null && cached !== void 0) {
432
+ log(`[resolveMxRecords] Cache hit for ${domain}: ${cached === null || cached === void 0 ? void 0 : cached.length} MX records`);
433
+ return cached;
434
+ }
435
+ log(`[resolveMxRecords] Performing DNS MX lookup for ${domain}`);
436
+ try {
437
+ const records = await node_dns.promises.resolveMx(domain);
438
+ records === null || records === void 0 ? void 0 : records.sort((a, b) => {
439
+ if (a.priority < b.priority) {
440
+ return -1;
441
+ }
442
+ if (a.priority > b.priority) {
443
+ return 1;
444
+ }
445
+ return 0;
446
+ });
447
+ const exchanges = records === null || records === void 0 ? void 0 : records.map((record) => record.exchange);
448
+ log(`[resolveMxRecords] Found ${exchanges === null || exchanges === void 0 ? void 0 : exchanges.length} MX records for ${domain}: [${exchanges === null || exchanges === void 0 ? void 0 : exchanges.join(", ")}]`);
449
+ await cacheStore.set(domain, exchanges);
450
+ log(`[resolveMxRecords] Cached ${exchanges === null || exchanges === void 0 ? void 0 : exchanges.length} MX records for ${domain}`);
451
+ return exchanges;
452
+ } catch (error) {
453
+ log(`[resolveMxRecords] MX lookup failed for ${domain}, caching empty result`);
454
+ await cacheStore.set(domain, []);
455
+ throw error;
456
+ }
457
+ }
458
+
459
+ const nameSeparator = [".", "_", "-"];
460
+ const commonNameSuffixes = [
411
461
  "mail",
412
462
  "email",
413
463
  "contact",
@@ -422,7 +472,7 @@ const COMMON_NAME_SUFFIXES = [
422
472
  "notifications",
423
473
  "alerts"
424
474
  ];
425
- const CONTEXTUAL_SUFFIXES = [
475
+ const contextualSuffixes = [
426
476
  "dev",
427
477
  "company",
428
478
  "team",
@@ -454,7 +504,7 @@ const COMMON_TITLES = [
454
504
  "father",
455
505
  "sister"
456
506
  ];
457
- const COMMON_FIRST_NAMES = /* @__PURE__ */ new Set([
507
+ const commonFirstName = /* @__PURE__ */ new Set([
458
508
  // English names
459
509
  "james",
460
510
  "john",
@@ -632,7 +682,7 @@ const COMMON_FIRST_NAMES = /* @__PURE__ */ new Set([
632
682
  "sekou",
633
683
  "mariama"
634
684
  ]);
635
- const COMMON_LAST_NAMES = /* @__PURE__ */ new Set([
685
+ const commonLastName = /* @__PURE__ */ new Set([
636
686
  // English surnames
637
687
  "smith",
638
688
  "johnson",
@@ -752,19 +802,19 @@ function isYearLike(str) {
752
802
  return /^(19|20)\d{2}$/.test(str);
753
803
  }
754
804
  function isKnownFirstName(str) {
755
- return COMMON_FIRST_NAMES.has(str.toLowerCase());
805
+ return commonFirstName.has(str.toLowerCase());
756
806
  }
757
807
  function isKnownLastName(str) {
758
- return COMMON_LAST_NAMES.has(str.toLowerCase());
808
+ return commonLastName.has(str.toLowerCase());
759
809
  }
760
810
  function isTitle(str) {
761
811
  return COMMON_TITLES.includes(str.toLowerCase().replace(".", ""));
762
812
  }
763
813
  function getFirstNameScore(str) {
764
814
  const lower = str.toLowerCase();
765
- if (COMMON_FIRST_NAMES.has(lower))
815
+ if (commonFirstName.has(lower))
766
816
  return 1;
767
- if (COMMON_LAST_NAMES.has(lower))
817
+ if (commonLastName.has(lower))
768
818
  return 0.3;
769
819
  if (str.length >= 2 && str.length <= 15 && /^[a-zA-Z]+$/.test(str))
770
820
  return 0.5;
@@ -772,9 +822,9 @@ function getFirstNameScore(str) {
772
822
  }
773
823
  function getLastNameScore(str) {
774
824
  const lower = str.toLowerCase();
775
- if (COMMON_LAST_NAMES.has(lower))
825
+ if (commonLastName.has(lower))
776
826
  return 1;
777
- if (COMMON_FIRST_NAMES.has(lower))
827
+ if (commonFirstName.has(lower))
778
828
  return 0.3;
779
829
  if (str.length >= 2 && str.length <= 20 && /^[a-zA-Z]+$/.test(str))
780
830
  return 0.5;
@@ -883,7 +933,7 @@ function isLikelyName(str, allowNumbers = false, allowSingleLetter = false) {
883
933
  return false;
884
934
  if (str.length === 1 && allowSingleLetter && /^[a-zA-Z]$/.test(str))
885
935
  return true;
886
- if (COMMON_NAME_SUFFIXES.includes(str.toLowerCase()))
936
+ if (commonNameSuffixes.includes(str.toLowerCase()))
887
937
  return false;
888
938
  if (allowNumbers) {
889
939
  if (/^\d+$/.test(str))
@@ -945,7 +995,7 @@ function defaultNameDetectionMethod(email) {
945
995
  }
946
996
  }
947
997
  if (!firstName && !lastName) {
948
- for (const separator of NAME_SEPARATORS) {
998
+ for (const separator of nameSeparator) {
949
999
  if (cleanedLocal.includes(separator)) {
950
1000
  const parts = cleanedLocal.split(separator).filter((p) => p.length > 0);
951
1001
  if (parts.length === 2) {
@@ -1007,7 +1057,7 @@ function defaultNameDetectionMethod(email) {
1007
1057
  const firstParsed = parseCompositeNamePart(first);
1008
1058
  const middleParsed = parseCompositeNamePart(middle);
1009
1059
  const lastParsed = parseCompositeNamePart(last);
1010
- const isLastSuffix = COMMON_NAME_SUFFIXES.includes(last.toLowerCase()) || CONTEXTUAL_SUFFIXES.includes(last.toLowerCase()) || isYearLike(last);
1060
+ const isLastSuffix = commonNameSuffixes.includes(last.toLowerCase()) || contextualSuffixes.includes(last.toLowerCase()) || isYearLike(last);
1011
1061
  if (isLastSuffix) {
1012
1062
  if (isLikelyName(first, true, true) && isLikelyName(middle, true, true)) {
1013
1063
  const cleanedFirst = firstParsed.hasNumbers ? firstParsed.cleaned : first;
@@ -1040,7 +1090,7 @@ function defaultNameDetectionMethod(email) {
1040
1090
  } else if (parts.length > 3) {
1041
1091
  const firstPart = parts[0];
1042
1092
  const lastPartLower = parts[parts.length - 1].toLowerCase();
1043
- const isLastPartSuffix = COMMON_NAME_SUFFIXES.includes(lastPartLower) || CONTEXTUAL_SUFFIXES.includes(lastPartLower) || isYearLike(parts[parts.length - 1]);
1093
+ const isLastPartSuffix = commonNameSuffixes.includes(lastPartLower) || contextualSuffixes.includes(lastPartLower) || isYearLike(parts[parts.length - 1]);
1044
1094
  const effectiveLastIndex = isLastPartSuffix ? parts.length - 2 : parts.length - 1;
1045
1095
  const lastToUse = effectiveLastIndex >= 0 ? parts[effectiveLastIndex] : null;
1046
1096
  if (lastToUse && isLikelyName(firstPart, true, true) && isLikelyName(lastToUse, true, true)) {
@@ -1123,7 +1173,7 @@ function detectNameFromEmail(params) {
1123
1173
  }
1124
1174
  return defaultNameDetectionMethod(email);
1125
1175
  }
1126
- function cleanNameForAlgrothin(name) {
1176
+ function cleanNameForAlgorithm(name) {
1127
1177
  if (!name)
1128
1178
  return "";
1129
1179
  let cleaned = name.replace(/[._*]/g, "");
@@ -1133,13 +1183,13 @@ function cleanNameForAlgrothin(name) {
1133
1183
  }
1134
1184
  return cleaned;
1135
1185
  }
1136
- function detectNameForAlgrothin(email) {
1186
+ function detectNameForAlgorithm(email) {
1137
1187
  const detectedName = detectName(email);
1138
1188
  if (!detectedName) {
1139
1189
  return null;
1140
1190
  }
1141
- const cleanedFirstName = detectedName.firstName ? cleanNameForAlgrothin(detectedName.firstName) : void 0;
1142
- const cleanedLastName = detectedName.lastName ? cleanNameForAlgrothin(detectedName.lastName) : void 0;
1191
+ const cleanedFirstName = detectedName.firstName ? cleanNameForAlgorithm(detectedName.firstName) : void 0;
1192
+ const cleanedLastName = detectedName.lastName ? cleanNameForAlgorithm(detectedName.lastName) : void 0;
1143
1193
  if (!cleanedFirstName && !cleanedLastName) {
1144
1194
  return null;
1145
1195
  }
@@ -1156,27 +1206,143 @@ function detectName(email) {
1156
1206
 
1157
1207
  exports.VerificationErrorCode = void 0;
1158
1208
  (function(VerificationErrorCode2) {
1159
- VerificationErrorCode2["INVALID_FORMAT"] = "INVALID_FORMAT";
1160
- VerificationErrorCode2["INVALID_DOMAIN"] = "INVALID_DOMAIN";
1161
- VerificationErrorCode2["NO_MX_RECORDS"] = "NO_MX_RECORDS";
1162
- VerificationErrorCode2["SMTP_CONNECTION_FAILED"] = "SMTP_CONNECTION_FAILED";
1163
- VerificationErrorCode2["SMTP_TIMEOUT"] = "SMTP_TIMEOUT";
1164
- VerificationErrorCode2["MAILBOX_NOT_FOUND"] = "MAILBOX_NOT_FOUND";
1165
- VerificationErrorCode2["MAILBOX_FULL"] = "MAILBOX_FULL";
1166
- VerificationErrorCode2["NETWORK_ERROR"] = "NETWORK_ERROR";
1167
- VerificationErrorCode2["DISPOSABLE_EMAIL"] = "DISPOSABLE_EMAIL";
1168
- VerificationErrorCode2["FREE_EMAIL_PROVIDER"] = "FREE_EMAIL_PROVIDER";
1209
+ VerificationErrorCode2["invalidFormat"] = "INVALID_FORMAT";
1210
+ VerificationErrorCode2["invalidDomain"] = "INVALID_DOMAIN";
1211
+ VerificationErrorCode2["noMxRecords"] = "NO_MX_RECORDS";
1212
+ VerificationErrorCode2["smtpConnectionFailed"] = "SMTP_CONNECTION_FAILED";
1213
+ VerificationErrorCode2["smtpTimeout"] = "SMTP_TIMEOUT";
1214
+ VerificationErrorCode2["mailboxNotFound"] = "MAILBOX_NOT_FOUND";
1215
+ VerificationErrorCode2["mailboxFull"] = "MAILBOX_FULL";
1216
+ VerificationErrorCode2["networkError"] = "NETWORK_ERROR";
1217
+ VerificationErrorCode2["disposableEmail"] = "DISPOSABLE_EMAIL";
1218
+ VerificationErrorCode2["freeEmailProvider"] = "FREE_EMAIL_PROVIDER";
1169
1219
  })(exports.VerificationErrorCode || (exports.VerificationErrorCode = {}));
1220
+ exports.EmailProvider = void 0;
1221
+ (function(EmailProvider2) {
1222
+ EmailProvider2["gmail"] = "gmail";
1223
+ EmailProvider2["hotmailB2b"] = "hotmail_b2b";
1224
+ EmailProvider2["hotmailB2c"] = "hotmail_b2c";
1225
+ EmailProvider2["proofpoint"] = "proofpoint";
1226
+ EmailProvider2["mimecast"] = "mimecast";
1227
+ EmailProvider2["yahoo"] = "yahoo";
1228
+ EmailProvider2["everythingElse"] = "everything_else";
1229
+ })(exports.EmailProvider || (exports.EmailProvider = {}));
1230
+ function parseSmtpError(errorMessage) {
1231
+ const lowerError = errorMessage.toLowerCase();
1232
+ const networkErrorPatterns = [
1233
+ "etimedout",
1234
+ "econnrefused",
1235
+ "enotfound",
1236
+ "econnreset",
1237
+ "socket hang up",
1238
+ "connection_timeout",
1239
+ "socket_timeout",
1240
+ "connection_error",
1241
+ "connection_closed"
1242
+ ];
1243
+ const isNetworkError = networkErrorPatterns.some((pattern) => lowerError.includes(pattern));
1244
+ if (isNetworkError) {
1245
+ return {
1246
+ isDisabled: false,
1247
+ hasFullInbox: false,
1248
+ isInvalid: true,
1249
+ isCatchAll: false
1250
+ };
1251
+ }
1252
+ const disabledPatterns = [
1253
+ "account disabled",
1254
+ "account is disabled",
1255
+ "user disabled",
1256
+ "user is disabled",
1257
+ "account locked",
1258
+ "account is locked",
1259
+ "user blocked",
1260
+ "user is blocked",
1261
+ "mailbox disabled",
1262
+ "delivery not authorized",
1263
+ "message rejected",
1264
+ "access denied",
1265
+ "permission denied",
1266
+ "recipient unknown",
1267
+ "recipient address rejected",
1268
+ "user unknown",
1269
+ "address unknown",
1270
+ "invalid recipient",
1271
+ "not a valid recipient",
1272
+ "recipient does not exist",
1273
+ "no such user",
1274
+ "user does not exist",
1275
+ "mailbox unavailable",
1276
+ "recipient unavailable",
1277
+ "address rejected",
1278
+ "550",
1279
+ "551",
1280
+ "553",
1281
+ "not_found",
1282
+ "ambiguous"
1283
+ ];
1284
+ const fullInboxPatterns = [
1285
+ "mailbox full",
1286
+ "inbox full",
1287
+ "quota exceeded",
1288
+ "over quota",
1289
+ "storage limit exceeded",
1290
+ "message too large",
1291
+ "insufficient storage",
1292
+ "mailbox over quota",
1293
+ "over the quota",
1294
+ "mailbox size limit exceeded",
1295
+ "account over quota",
1296
+ "storage space",
1297
+ "overquota",
1298
+ "452",
1299
+ "552",
1300
+ "over_quota"
1301
+ ];
1302
+ const catchAllPatterns = [
1303
+ "accept all mail",
1304
+ "catch-all",
1305
+ "catchall",
1306
+ "wildcard",
1307
+ "accepts any recipient",
1308
+ "recipient address accepted"
1309
+ ];
1310
+ const rateLimitPatterns = [
1311
+ "receiving mail at a rate that",
1312
+ "rate limit",
1313
+ "too many messages",
1314
+ "temporarily rejected",
1315
+ "try again later",
1316
+ "greylisted",
1317
+ "greylist",
1318
+ "deferring",
1319
+ "temporarily deferred",
1320
+ "421",
1321
+ "450",
1322
+ "451",
1323
+ "temporary_failure"
1324
+ ];
1325
+ const isDisabled = disabledPatterns.some((pattern) => lowerError.includes(pattern)) || lowerError.startsWith("550") || lowerError.startsWith("551") || lowerError.startsWith("553");
1326
+ const hasFullInbox = fullInboxPatterns.some((pattern) => lowerError.includes(pattern)) || lowerError.startsWith("452") || lowerError.startsWith("552");
1327
+ const isCatchAll = catchAllPatterns.some((pattern) => lowerError.includes(pattern));
1328
+ const isInvalid = !isDisabled && !hasFullInbox && !isCatchAll && !rateLimitPatterns.some((pattern) => lowerError.includes(pattern)) && !lowerError.startsWith("421") && !lowerError.startsWith("450") && !lowerError.startsWith("451");
1329
+ return {
1330
+ isDisabled,
1331
+ hasFullInbox,
1332
+ isInvalid,
1333
+ isCatchAll
1334
+ };
1335
+ }
1170
1336
  exports.SMTPStep = void 0;
1171
1337
  (function(SMTPStep2) {
1172
- SMTPStep2["GREETING"] = "GREETING";
1173
- SMTPStep2["EHLO"] = "EHLO";
1174
- SMTPStep2["HELO"] = "HELO";
1175
- SMTPStep2["STARTTLS"] = "STARTTLS";
1176
- SMTPStep2["MAIL_FROM"] = "MAIL_FROM";
1177
- SMTPStep2["RCPT_TO"] = "RCPT_TO";
1178
- SMTPStep2["VRFY"] = "VRFY";
1179
- SMTPStep2["QUIT"] = "QUIT";
1338
+ SMTPStep2["greeting"] = "GREETING";
1339
+ SMTPStep2["ehlo"] = "EHLO";
1340
+ SMTPStep2["helo"] = "HELO";
1341
+ SMTPStep2["startTls"] = "STARTTLS";
1342
+ SMTPStep2["mailFrom"] = "MAIL_FROM";
1343
+ SMTPStep2["rcptTo"] = "RCPT_TO";
1344
+ SMTPStep2["vrfy"] = "VRFY";
1345
+ SMTPStep2["quit"] = "QUIT";
1180
1346
  })(exports.SMTPStep || (exports.SMTPStep = {}));
1181
1347
 
1182
1348
  function isIPAddress(host) {
@@ -1210,9 +1376,38 @@ async function verifyMailboxSMTP(params) {
1210
1376
  const { ports = DEFAULT_PORTS, timeout = DEFAULT_TIMEOUT, maxRetries = DEFAULT_MAX_RETRIES, tls: tlsConfig = true, hostname = "localhost", useVRFY = true, cache, debug = false, sequence } = options;
1211
1377
  const log = debug ? (...args) => console.log("[SMTP]", ...args) : () => {
1212
1378
  };
1379
+ const createSmtpResult = (result, port, tlsUsed, mxHost2) => {
1380
+ const reason = result === true ? "valid" : result === null ? "ambiguous" : "not_found";
1381
+ const parsedError = parseSmtpError(reason);
1382
+ return {
1383
+ canConnectSmtp: result !== null,
1384
+ hasFullInbox: parsedError.hasFullInbox,
1385
+ isCatchAll: parsedError.isCatchAll,
1386
+ isDeliverable: result === true,
1387
+ isDisabled: result === false && parsedError.isDisabled,
1388
+ error: result === null ? reason : result === false ? reason : void 0,
1389
+ providerUsed: exports.EmailProvider.everythingElse,
1390
+ checkedAt: Date.now()
1391
+ };
1392
+ };
1393
+ const createFailureResult = (error) => ({
1394
+ canConnectSmtp: false,
1395
+ hasFullInbox: false,
1396
+ isCatchAll: false,
1397
+ isDeliverable: false,
1398
+ isDisabled: false,
1399
+ error,
1400
+ providerUsed: exports.EmailProvider.everythingElse,
1401
+ checkedAt: Date.now()
1402
+ });
1213
1403
  if (!mxRecords || mxRecords.length === 0) {
1214
1404
  log("No MX records found");
1215
- return { result: false, cached: false, port: 0, portCached: false };
1405
+ return {
1406
+ smtpResult: createFailureResult("No MX records found"),
1407
+ cached: false,
1408
+ port: 0,
1409
+ portCached: false
1410
+ };
1216
1411
  }
1217
1412
  const mxHost = mxRecords[0];
1218
1413
  log(`Verifying ${local}@${domain} via ${mxHost}`);
@@ -1221,16 +1416,16 @@ async function verifyMailboxSMTP(params) {
1221
1416
  let cachedResult;
1222
1417
  try {
1223
1418
  cachedResult = await smtpCacheStore.get(`${mxHost}:${local}@${domain}`);
1224
- if (cachedResult !== void 0) {
1225
- log(`Using cached SMTP result: ${cachedResult}`);
1419
+ if (cachedResult !== void 0 && cachedResult !== null) {
1420
+ log(`Using cached SMTP result: ${cachedResult.isDeliverable}`);
1226
1421
  return {
1227
- result: typeof cachedResult === "boolean" ? cachedResult : null,
1422
+ smtpResult: cachedResult,
1228
1423
  cached: true,
1229
1424
  port: 0,
1230
1425
  portCached: false
1231
1426
  };
1232
1427
  }
1233
- } catch (_error) {
1428
+ } catch (ignoredError) {
1234
1429
  cachedResult = void 0;
1235
1430
  }
1236
1431
  }
@@ -1239,7 +1434,7 @@ async function verifyMailboxSMTP(params) {
1239
1434
  let cachedPort;
1240
1435
  try {
1241
1436
  cachedPort = await smtpPortCacheStore.get(mxHost);
1242
- } catch (_error) {
1437
+ } catch (ignoredError) {
1243
1438
  cachedPort = null;
1244
1439
  }
1245
1440
  if (cachedPort) {
@@ -1256,21 +1451,22 @@ async function verifyMailboxSMTP(params) {
1256
1451
  sequence,
1257
1452
  log
1258
1453
  });
1259
- if (smtpCacheStore && result !== void 0) {
1454
+ const smtpResult = createSmtpResult(result);
1455
+ if (smtpCacheStore) {
1260
1456
  try {
1261
- await smtpCacheStore.set(`${mxHost}:${local}@${domain}`, result);
1457
+ await smtpCacheStore.set(`${mxHost}:${local}@${domain}`, smtpResult);
1262
1458
  log(`Cached SMTP result ${result} for ${local}@${domain} via ${mxHost}`);
1263
- } catch (_error) {
1459
+ } catch (ignoredError) {
1264
1460
  }
1265
1461
  }
1266
- return { result, cached: false, port: cachedPort, portCached: true };
1462
+ return { smtpResult, cached: false, port: cachedPort, portCached: true };
1267
1463
  }
1268
1464
  }
1269
1465
  for (const port of ports) {
1270
1466
  log(`Testing port ${port}`);
1271
1467
  for (let attempt = 0; attempt < maxRetries; attempt++) {
1272
1468
  if (attempt > 0) {
1273
- const delay = Math.min(1e3 * 2 ** (attempt - 1), 5e3);
1469
+ const delay = Math.min(200 * 2 ** (attempt - 1), 800);
1274
1470
  log(`Retry ${attempt + 1}, waiting ${delay}ms`);
1275
1471
  await new Promise((resolve) => setTimeout(resolve, delay));
1276
1472
  }
@@ -1286,11 +1482,12 @@ async function verifyMailboxSMTP(params) {
1286
1482
  sequence,
1287
1483
  log
1288
1484
  });
1289
- if (smtpCacheStore && result !== void 0) {
1485
+ const smtpResult = createSmtpResult(result);
1486
+ if (smtpCacheStore) {
1290
1487
  try {
1291
- await smtpCacheStore.set(`${mxHost}:${local}@${domain}`, result);
1488
+ await smtpCacheStore.set(`${mxHost}:${local}@${domain}`, smtpResult);
1292
1489
  log(`Cached SMTP result ${result} for ${local}@${domain} via ${mxHost}`);
1293
- } catch (_error) {
1490
+ } catch (ignoredError) {
1294
1491
  }
1295
1492
  }
1296
1493
  if (result !== null) {
@@ -1298,15 +1495,20 @@ async function verifyMailboxSMTP(params) {
1298
1495
  try {
1299
1496
  await smtpPortCacheStore.set(mxHost, port);
1300
1497
  log(`Cached port ${port} for ${mxHost}`);
1301
- } catch (_error) {
1498
+ } catch (ignoredError) {
1302
1499
  }
1303
1500
  }
1304
- return { result, cached: false, port, portCached: false };
1501
+ return { smtpResult, cached: false, port, portCached: false };
1305
1502
  }
1306
1503
  }
1307
1504
  }
1308
1505
  log("All ports failed");
1309
- return { result: null, cached: false, port: 0, portCached: false };
1506
+ return {
1507
+ smtpResult: createFailureResult("All SMTP connection attempts failed"),
1508
+ cached: false,
1509
+ port: 0,
1510
+ portCached: false
1511
+ };
1310
1512
  }
1311
1513
  async function testSMTPConnection(params) {
1312
1514
  const { mxHost, port, local, domain, timeout, tlsConfig, hostname, useVRFY, sequence, log } = params;
@@ -1314,11 +1516,11 @@ async function testSMTPConnection(params) {
1314
1516
  const useTLS = tlsConfig !== false && (portConfig.tls || portConfig.starttls);
1315
1517
  const implicitTLS = portConfig.tls;
1316
1518
  const defaultSequence = {
1317
- steps: [exports.SMTPStep.GREETING, exports.SMTPStep.EHLO, exports.SMTPStep.MAIL_FROM, exports.SMTPStep.RCPT_TO]
1519
+ steps: [exports.SMTPStep.greeting, exports.SMTPStep.ehlo, exports.SMTPStep.mailFrom, exports.SMTPStep.rcptTo]
1318
1520
  };
1319
1521
  const activeSequence = sequence || defaultSequence;
1320
1522
  if (port === 25) {
1321
- activeSequence.steps = activeSequence.steps.map((step) => step === exports.SMTPStep.EHLO ? exports.SMTPStep.HELO : step);
1523
+ activeSequence.steps = activeSequence.steps.map((step) => step === exports.SMTPStep.ehlo ? exports.SMTPStep.helo : step);
1322
1524
  }
1323
1525
  const tlsOptions = {
1324
1526
  host: mxHost,
@@ -1336,7 +1538,7 @@ async function testSMTPConnection(params) {
1336
1538
  let resolved = false;
1337
1539
  let supportsSTARTTLS = false;
1338
1540
  let supportsVRFY = false;
1339
- const cleanup = () => {
1541
+ let cleanup = () => {
1340
1542
  if (resolved)
1341
1543
  return;
1342
1544
  resolved = true;
@@ -1372,31 +1574,31 @@ async function testSMTPConnection(params) {
1372
1574
  if (resolved)
1373
1575
  return;
1374
1576
  switch (step) {
1375
- case exports.SMTPStep.EHLO:
1577
+ case exports.SMTPStep.ehlo:
1376
1578
  sendCommand(`EHLO ${hostname}`);
1377
1579
  break;
1378
- case exports.SMTPStep.HELO:
1580
+ case exports.SMTPStep.helo:
1379
1581
  sendCommand(`HELO ${domain}`);
1380
1582
  break;
1381
- case exports.SMTPStep.GREETING:
1583
+ case exports.SMTPStep.greeting:
1382
1584
  break;
1383
- case exports.SMTPStep.STARTTLS:
1585
+ case exports.SMTPStep.startTls:
1384
1586
  sendCommand("STARTTLS");
1385
1587
  break;
1386
- case exports.SMTPStep.MAIL_FROM: {
1588
+ case exports.SMTPStep.mailFrom: {
1387
1589
  const from = activeSequence.from || "<>";
1388
1590
  sendCommand(`MAIL FROM:${from}`);
1389
1591
  break;
1390
1592
  }
1391
- case exports.SMTPStep.RCPT_TO:
1593
+ case exports.SMTPStep.rcptTo:
1392
1594
  sendCommand(`RCPT TO:<${local}@${domain}>`);
1393
1595
  break;
1394
- case exports.SMTPStep.VRFY: {
1596
+ case exports.SMTPStep.vrfy: {
1395
1597
  const vrfyTarget = activeSequence.vrfyTarget || local;
1396
1598
  sendCommand(`VRFY ${vrfyTarget}`);
1397
1599
  break;
1398
1600
  }
1399
- case exports.SMTPStep.QUIT:
1601
+ case exports.SMTPStep.quit:
1400
1602
  sendCommand("QUIT");
1401
1603
  break;
1402
1604
  }
@@ -1420,14 +1622,14 @@ async function testSMTPConnection(params) {
1420
1622
  }
1421
1623
  if (isMultiline) {
1422
1624
  const currentStep2 = activeSequence.steps[currentStepIndex];
1423
- if (currentStep2 === exports.SMTPStep.EHLO && code === "250") {
1625
+ if (currentStep2 === exports.SMTPStep.ehlo && code === "250") {
1424
1626
  const upper = response.toUpperCase();
1425
1627
  if (upper.includes("STARTTLS"))
1426
1628
  supportsSTARTTLS = true;
1427
1629
  if (upper.includes("VRFY"))
1428
1630
  supportsVRFY = true;
1429
1631
  }
1430
- if (currentStep2 === exports.SMTPStep.HELO && code === "250") {
1632
+ if (currentStep2 === exports.SMTPStep.helo && code === "250") {
1431
1633
  const upper = response.toUpperCase();
1432
1634
  if (upper.includes("VRFY"))
1433
1635
  supportsVRFY = true;
@@ -1440,19 +1642,19 @@ async function testSMTPConnection(params) {
1440
1642
  }
1441
1643
  const currentStep = activeSequence.steps[currentStepIndex];
1442
1644
  switch (currentStep) {
1443
- case exports.SMTPStep.GREETING:
1645
+ case exports.SMTPStep.greeting:
1444
1646
  if (code.startsWith("220")) {
1445
1647
  nextStep();
1446
1648
  } else {
1447
1649
  finish(null, "no_greeting");
1448
1650
  }
1449
1651
  break;
1450
- case exports.SMTPStep.EHLO:
1652
+ case exports.SMTPStep.ehlo:
1451
1653
  if (code.startsWith("250")) {
1452
- const hasSTARTTLS = activeSequence.steps.includes(exports.SMTPStep.STARTTLS);
1654
+ const hasSTARTTLS = activeSequence.steps.includes(exports.SMTPStep.startTls);
1453
1655
  if (!isTLS && useTLS && supportsSTARTTLS && !implicitTLS && hasSTARTTLS) {
1454
- currentStepIndex = activeSequence.steps.indexOf(exports.SMTPStep.STARTTLS);
1455
- executeStep(exports.SMTPStep.STARTTLS);
1656
+ currentStepIndex = activeSequence.steps.indexOf(exports.SMTPStep.startTls);
1657
+ executeStep(exports.SMTPStep.startTls);
1456
1658
  } else {
1457
1659
  nextStep();
1458
1660
  }
@@ -1460,14 +1662,14 @@ async function testSMTPConnection(params) {
1460
1662
  finish(null, "ehlo_failed");
1461
1663
  }
1462
1664
  break;
1463
- case exports.SMTPStep.HELO:
1665
+ case exports.SMTPStep.helo:
1464
1666
  if (code.startsWith("250")) {
1465
1667
  nextStep();
1466
1668
  } else {
1467
1669
  finish(null, "helo_failed");
1468
1670
  }
1469
1671
  break;
1470
- case exports.SMTPStep.STARTTLS:
1672
+ case exports.SMTPStep.startTls:
1471
1673
  if (code.startsWith("220")) {
1472
1674
  const plainSocket = socket;
1473
1675
  socket = tls__namespace.connect({
@@ -1478,7 +1680,7 @@ async function testSMTPConnection(params) {
1478
1680
  isTLS = true;
1479
1681
  log("TLS upgraded");
1480
1682
  buffer = "";
1481
- const starttlsIndex = activeSequence.steps.indexOf(exports.SMTPStep.STARTTLS);
1683
+ const starttlsIndex = activeSequence.steps.indexOf(exports.SMTPStep.startTls);
1482
1684
  currentStepIndex = starttlsIndex;
1483
1685
  nextStep();
1484
1686
  });
@@ -1488,28 +1690,28 @@ async function testSMTPConnection(params) {
1488
1690
  nextStep();
1489
1691
  }
1490
1692
  break;
1491
- case exports.SMTPStep.MAIL_FROM:
1693
+ case exports.SMTPStep.mailFrom:
1492
1694
  if (code.startsWith("250")) {
1493
1695
  nextStep();
1494
1696
  } else {
1495
1697
  finish(null, "mail_from_rejected");
1496
1698
  }
1497
1699
  break;
1498
- case exports.SMTPStep.RCPT_TO:
1700
+ case exports.SMTPStep.rcptTo:
1499
1701
  if (code.startsWith("250") || code.startsWith("251")) {
1500
1702
  finish(true, "valid");
1501
1703
  } else if (code.startsWith("552") || code.startsWith("452")) {
1502
1704
  finish(false, "over_quota");
1503
1705
  } else if (code.startsWith("4")) {
1504
1706
  finish(null, "temporary_failure");
1505
- } else if (useVRFY && supportsVRFY && code.startsWith("5") && activeSequence.steps.includes(exports.SMTPStep.VRFY)) {
1506
- currentStepIndex = activeSequence.steps.indexOf(exports.SMTPStep.VRFY);
1507
- executeStep(exports.SMTPStep.VRFY);
1707
+ } else if (useVRFY && supportsVRFY && code.startsWith("5") && activeSequence.steps.includes(exports.SMTPStep.vrfy)) {
1708
+ currentStepIndex = activeSequence.steps.indexOf(exports.SMTPStep.vrfy);
1709
+ executeStep(exports.SMTPStep.vrfy);
1508
1710
  } else {
1509
1711
  finish(null, "ambiguous");
1510
1712
  }
1511
1713
  break;
1512
- case exports.SMTPStep.VRFY:
1714
+ case exports.SMTPStep.vrfy:
1513
1715
  if (code.startsWith("250") || code.startsWith("252")) {
1514
1716
  finish(true, "vrfy_valid");
1515
1717
  } else if (code.startsWith("550")) {
@@ -1518,14 +1720,14 @@ async function testSMTPConnection(params) {
1518
1720
  finish(null, "vrfy_failed");
1519
1721
  }
1520
1722
  break;
1521
- case exports.SMTPStep.QUIT:
1723
+ case exports.SMTPStep.quit:
1522
1724
  if (code.startsWith("221")) {
1523
1725
  finish(null, "quit_received");
1524
1726
  }
1525
1727
  break;
1526
1728
  }
1527
1729
  };
1528
- const handleData = (data) => {
1730
+ let handleData = (data) => {
1529
1731
  if (resolved)
1530
1732
  return;
1531
1733
  buffer += data.toString();
@@ -1561,65 +1763,69 @@ async function testSMTPConnection(params) {
1561
1763
  return;
1562
1764
  }
1563
1765
  const firstStep = activeSequence.steps[0];
1564
- if (firstStep !== exports.SMTPStep.GREETING) {
1766
+ let connectionTimeout;
1767
+ let stepTimeout;
1768
+ const resetActivityTimeout = () => {
1769
+ if (stepTimeout) {
1770
+ clearTimeout(stepTimeout);
1771
+ }
1772
+ stepTimeout = setTimeout(() => {
1773
+ if (!resolved) {
1774
+ log(`Step timeout after ${timeout}ms of inactivity`);
1775
+ finish(null, "step_timeout");
1776
+ }
1777
+ }, timeout);
1778
+ };
1779
+ connectionTimeout = setTimeout(() => {
1780
+ if (!resolved) {
1781
+ log(`Connection timeout after ${timeout}ms`);
1782
+ finish(null, "connection_timeout");
1783
+ }
1784
+ }, timeout);
1785
+ if (firstStep !== exports.SMTPStep.greeting) {
1565
1786
  executeStep(firstStep);
1566
1787
  }
1567
- socket.setTimeout(timeout, () => finish(null, "timeout"));
1568
- socket.on("error", () => finish(null, "connection_error"));
1569
- socket.on("close", () => {
1788
+ socket.setTimeout(timeout, () => {
1789
+ if (!resolved) {
1790
+ log(`Socket timeout after ${timeout}ms`);
1791
+ finish(null, "socket_timeout");
1792
+ }
1793
+ });
1794
+ socket.on("error", (error) => {
1795
+ log(`Socket error: ${error.message}`);
1570
1796
  if (!resolved)
1797
+ finish(null, "connection_error");
1798
+ });
1799
+ socket.on("close", () => {
1800
+ if (!resolved) {
1801
+ log("Socket closed unexpectedly");
1571
1802
  finish(null, "connection_closed");
1803
+ }
1572
1804
  });
1805
+ const originalHandleData = handleData;
1806
+ handleData = (data) => {
1807
+ resetActivityTimeout();
1808
+ originalHandleData(data);
1809
+ };
1810
+ const enhancedCleanup = () => {
1811
+ if (resolved)
1812
+ return;
1813
+ resolved = true;
1814
+ if (connectionTimeout)
1815
+ clearTimeout(connectionTimeout);
1816
+ if (stepTimeout)
1817
+ clearTimeout(stepTimeout);
1818
+ socket.setTimeout(0);
1819
+ try {
1820
+ socket === null || socket === void 0 ? void 0 : socket.write("QUIT\r\n");
1821
+ } catch {
1822
+ }
1823
+ setTimeout(() => socket === null || socket === void 0 ? void 0 : socket.destroy(), 100);
1824
+ };
1825
+ cleanup = enhancedCleanup;
1573
1826
  });
1574
1827
  }
1575
1828
 
1576
- async function isValidEmailDomain(emailOrDomain, cache) {
1577
- let [_, emailDomain] = (emailOrDomain === null || emailOrDomain === void 0 ? void 0 : emailOrDomain.split("@")) || [];
1578
- if (!emailDomain) {
1579
- emailDomain = _;
1580
- }
1581
- if (!emailDomain) {
1582
- return false;
1583
- }
1584
- const cacheStore = getCacheStore(cache, "domainValid");
1585
- const cached = await cacheStore.get(emailDomain);
1586
- if (cached !== null && cached !== void 0) {
1587
- return cached;
1588
- }
1589
- try {
1590
- const result = psl.isValid(emailDomain) || false;
1591
- await cacheStore.set(emailDomain, result);
1592
- return result;
1593
- } catch (_e) {
1594
- await cacheStore.set(emailDomain, false);
1595
- return false;
1596
- }
1597
- }
1598
- function isValidEmail(emailAddress) {
1599
- if (!emailAddress || typeof emailAddress !== "string") {
1600
- return false;
1601
- }
1602
- const re = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
1603
- const emailLower = emailAddress.toLowerCase();
1604
- if (emailLower.indexOf(".+") !== -1)
1605
- return false;
1606
- if (emailLower.indexOf("..") !== -1)
1607
- return false;
1608
- if (emailLower.startsWith(".") || emailLower.endsWith("."))
1609
- return false;
1610
- const parts = emailAddress.split("@");
1611
- if (parts.length !== 2)
1612
- return false;
1613
- const [localPart, domain] = parts;
1614
- if (!localPart || !domain)
1615
- return false;
1616
- if (localPart.length > 64)
1617
- return false;
1618
- if (domain.length > 253)
1619
- return false;
1620
- return re.test(emailLower);
1621
- }
1622
-
1623
1829
  const defaultRegex = {
1624
1830
  domainName: "Domain Name: *([^\\s]+)",
1625
1831
  registrar: "Registrar: *(.+)",
@@ -2037,7 +2243,7 @@ function parseWhoisData({ rawData, domain }) {
2037
2243
  return result;
2038
2244
  }
2039
2245
 
2040
- const WHOIS_SERVERS = {
2246
+ const whoisServers = {
2041
2247
  com: "whois.verisign-grs.com",
2042
2248
  net: "whois.verisign-grs.com",
2043
2249
  org: "whois.pir.org",
@@ -2137,7 +2343,7 @@ async function getWhoisData(domain, timeout = 5e3, debug = false, cache) {
2137
2343
  throw new Error("Invalid domain");
2138
2344
  }
2139
2345
  log(`[whois] extracted TLD: ${tld} for domain: ${domain}`);
2140
- const whoisServer = WHOIS_SERVERS[tld];
2346
+ const whoisServer = whoisServers[tld];
2141
2347
  if (!whoisServer) {
2142
2348
  log(`[whois] no specific server for TLD ${tld}, trying IANA`);
2143
2349
  const defaultServer = "whois.iana.org";
@@ -2163,8 +2369,8 @@ async function getWhoisData(domain, timeout = 5e3, debug = false, cache) {
2163
2369
  await cacheStore.set(cacheKey, whoisData);
2164
2370
  log(`[whois] successfully retrieved and cached WHOIS data for ${domain}`);
2165
2371
  return whoisData;
2166
- } catch (_error) {
2167
- log(`[whois] failed to get WHOIS data for ${domain}: ${_error instanceof Error ? _error.message : "Unknown error"}`);
2372
+ } catch (ignoredError) {
2373
+ log(`[whois] failed to get WHOIS data for ${domain}: ${ignoredError instanceof Error ? ignoredError.message : "Unknown error"}`);
2168
2374
  return null;
2169
2375
  }
2170
2376
  }
@@ -2201,8 +2407,8 @@ async function getDomainAge(domain, timeout = 5e3, debug = false, cache) {
2201
2407
  expirationDate: whoisData.expirationDate ? new Date(whoisData.expirationDate) : null,
2202
2408
  updatedDate: whoisData.updatedDate ? new Date(whoisData.updatedDate) : null
2203
2409
  };
2204
- } catch (_error) {
2205
- log(`[whois] error getting domain age for ${domain}: ${_error instanceof Error ? _error.message : "Unknown error"}`);
2410
+ } catch (ignoredError) {
2411
+ log(`[whois] error getting domain age for ${domain}: ${ignoredError instanceof Error ? ignoredError.message : "Unknown error"}`);
2206
2412
  return null;
2207
2413
  }
2208
2414
  }
@@ -2273,8 +2479,8 @@ async function getDomainRegistrationStatus(domain, timeout = 5e3, debug = false,
2273
2479
  isPendingDelete,
2274
2480
  isLocked
2275
2481
  };
2276
- } catch (_error) {
2277
- log(`[whois] error getting domain registration status for ${domain}: ${_error instanceof Error ? _error.message : "Unknown error"}`);
2482
+ } catch (ignoredError) {
2483
+ log(`[whois] error getting domain registration status for ${domain}: ${ignoredError instanceof Error ? ignoredError.message : "Unknown error"}`);
2278
2484
  return null;
2279
2485
  }
2280
2486
  }
@@ -2450,7 +2656,7 @@ function createErrorResult(email, _error) {
2450
2656
  metadata: {
2451
2657
  verificationTime: 0,
2452
2658
  cached: false,
2453
- error: exports.VerificationErrorCode.SMTP_CONNECTION_FAILED
2659
+ error: exports.VerificationErrorCode.smtpConnectionFailed
2454
2660
  }
2455
2661
  };
2456
2662
  }
@@ -2470,25 +2676,31 @@ async function isDisposableEmail(params) {
2470
2676
  let cached;
2471
2677
  try {
2472
2678
  cached = await cacheStore.get(emailDomain);
2473
- } catch (_error) {
2679
+ } catch (ignoredError) {
2474
2680
  cached = null;
2475
2681
  }
2476
2682
  if (cached !== null && cached !== void 0) {
2477
- log(`[isDisposableEmail] Cache hit for ${emailDomain}: ${cached}`);
2478
- return cached;
2683
+ log(`[isDisposableEmail] Cache hit for ${emailDomain}: ${cached.isDisposable}`);
2684
+ return cached.isDisposable;
2479
2685
  }
2480
2686
  if (!disposableEmailProviders) {
2481
2687
  disposableEmailProviders = new Set(require("./disposable-email-providers.json"));
2482
2688
  }
2483
- const result = disposableEmailProviders.has(emailDomain);
2689
+ const isDisposable = disposableEmailProviders.has(emailDomain);
2690
+ const richResult = {
2691
+ isDisposable,
2692
+ source: "disposable-email-providers.json",
2693
+ category: isDisposable ? "disposable" : void 0,
2694
+ checkedAt: Date.now()
2695
+ };
2484
2696
  try {
2485
- await cacheStore.set(emailDomain, result);
2486
- log(`[isDisposableEmail] Cached result for ${emailDomain}: ${result}`);
2487
- } catch (_error) {
2697
+ await cacheStore.set(emailDomain, richResult);
2698
+ log(`[isDisposableEmail] Cached result for ${emailDomain}: ${isDisposable}`);
2699
+ } catch (ignoredError) {
2488
2700
  log(`[isDisposableEmail] Cache write error for ${emailDomain}`);
2489
2701
  }
2490
- log(`[isDisposableEmail] Check result for ${emailDomain}: ${result}`);
2491
- return result;
2702
+ log(`[isDisposableEmail] Check result for ${emailDomain}: ${isDisposable}`);
2703
+ return isDisposable;
2492
2704
  }
2493
2705
  async function isFreeEmail(params) {
2494
2706
  const { emailOrDomain, cache, logger } = params;
@@ -2503,25 +2715,30 @@ async function isFreeEmail(params) {
2503
2715
  let cached;
2504
2716
  try {
2505
2717
  cached = await cacheStore.get(emailDomain);
2506
- } catch (_error) {
2718
+ } catch (ignoredError) {
2507
2719
  cached = null;
2508
2720
  }
2509
2721
  if (cached !== null && cached !== void 0) {
2510
- log(`[isFreeEmail] Cache hit for ${emailDomain}: ${cached}`);
2511
- return cached;
2722
+ log(`[isFreeEmail] Cache hit for ${emailDomain}: ${cached.isFree}`);
2723
+ return cached.isFree;
2512
2724
  }
2513
2725
  if (!freeEmailProviders) {
2514
2726
  freeEmailProviders = new Set(require("./free-email-providers.json"));
2515
2727
  }
2516
- const result = freeEmailProviders.has(emailDomain);
2728
+ const isFree = freeEmailProviders.has(emailDomain);
2729
+ const richResult = {
2730
+ isFree,
2731
+ provider: isFree ? emailDomain : void 0,
2732
+ checkedAt: Date.now()
2733
+ };
2517
2734
  try {
2518
- await cacheStore.set(emailDomain, result);
2519
- log(`[isFreeEmail] Cached result for ${emailDomain}: ${result}`);
2520
- } catch (_error) {
2735
+ await cacheStore.set(emailDomain, richResult);
2736
+ log(`[isFreeEmail] Cached result for ${emailDomain}: ${isFree}`);
2737
+ } catch (ignoredError) {
2521
2738
  log(`[isFreeEmail] Cache write error for ${emailDomain}`);
2522
2739
  }
2523
- log(`[isFreeEmail] Check result for ${emailDomain}: ${result}`);
2524
- return result;
2740
+ log(`[isFreeEmail] Check result for ${emailDomain}: ${isFree}`);
2741
+ return isFree;
2525
2742
  }
2526
2743
  const domainPorts = {
2527
2744
  // 465 or 587
@@ -2529,7 +2746,7 @@ const domainPorts = {
2529
2746
  "ovh.net": 465
2530
2747
  };
2531
2748
  async function verifyEmail(params) {
2532
- var _a;
2749
+ var _a, _b;
2533
2750
  const { emailAddress, timeout = 4e3, verifyMx = true, verifySmtp = false, debug = false, checkDisposable = true, checkFree = true, detectName: detectName2 = false, nameDetectionMethod, suggestDomain: suggestDomain2 = true, domainSuggestionMethod, commonDomains, checkDomainAge = false, checkDomainRegistration = false, whoisTimeout = 5e3, skipMxForDisposable = false, skipDomainWhoisForDisposable = false } = params;
2534
2751
  const startTime = Date.now();
2535
2752
  const log = debug ? console.debug : (..._args) => {
@@ -2549,7 +2766,7 @@ async function verifyEmail(params) {
2549
2766
  if (!isValidEmail(emailAddress)) {
2550
2767
  if (result.metadata) {
2551
2768
  result.metadata.verificationTime = Date.now() - startTime;
2552
- result.metadata.error = exports.VerificationErrorCode.INVALID_FORMAT;
2769
+ result.metadata.error = exports.VerificationErrorCode.invalidFormat;
2553
2770
  }
2554
2771
  return result;
2555
2772
  }
@@ -2575,14 +2792,14 @@ async function verifyEmail(params) {
2575
2792
  if (!domain || !local) {
2576
2793
  if (result.metadata) {
2577
2794
  result.metadata.verificationTime = Date.now() - startTime;
2578
- result.metadata.error = exports.VerificationErrorCode.INVALID_FORMAT;
2795
+ result.metadata.error = exports.VerificationErrorCode.invalidFormat;
2579
2796
  }
2580
2797
  return result;
2581
2798
  }
2582
2799
  if (!await isValidEmailDomain(domain, params.cache)) {
2583
2800
  if (result.metadata) {
2584
2801
  result.metadata.verificationTime = Date.now() - startTime;
2585
- result.metadata.error = exports.VerificationErrorCode.INVALID_DOMAIN;
2802
+ result.metadata.error = exports.VerificationErrorCode.invalidDomain;
2586
2803
  }
2587
2804
  return result;
2588
2805
  }
@@ -2591,7 +2808,7 @@ async function verifyEmail(params) {
2591
2808
  result.isDisposable = await isDisposableEmail({ emailOrDomain: emailAddress, cache: params.cache, logger: log });
2592
2809
  log(`[verifyEmail] Disposable check result: ${result.isDisposable}`);
2593
2810
  if (result.isDisposable && result.metadata) {
2594
- result.metadata.error = exports.VerificationErrorCode.DISPOSABLE_EMAIL;
2811
+ result.metadata.error = exports.VerificationErrorCode.disposableEmail;
2595
2812
  }
2596
2813
  }
2597
2814
  if (checkFree) {
@@ -2612,8 +2829,8 @@ async function verifyEmail(params) {
2612
2829
  try {
2613
2830
  result.domainAge = await getDomainAge(domain, whoisTimeout, debug, params.cache);
2614
2831
  log(`[verifyEmail] Domain age result:`, result.domainAge ? `${result.domainAge.ageInDays} days` : "null");
2615
- } catch (err) {
2616
- log("[verifyEmail] Failed to get domain age", err);
2832
+ } catch (error) {
2833
+ log("[verifyEmail] Failed to get domain age", error);
2617
2834
  result.domainAge = null;
2618
2835
  }
2619
2836
  } else if (checkDomainAge && shouldSkipDomainWhois) {
@@ -2624,8 +2841,8 @@ async function verifyEmail(params) {
2624
2841
  try {
2625
2842
  result.domainRegistration = await getDomainRegistrationStatus(domain, whoisTimeout, debug, params.cache);
2626
2843
  log(`[verifyEmail] Domain registration result:`, ((_a = result.domainRegistration) === null || _a === void 0 ? void 0 : _a.isRegistered) ? "registered" : "not registered");
2627
- } catch (err) {
2628
- log("[verifyEmail] Failed to get domain registration status", err);
2844
+ } catch (error) {
2845
+ log("[verifyEmail] Failed to get domain registration status", error);
2629
2846
  result.domainRegistration = null;
2630
2847
  }
2631
2848
  } else if (checkDomainRegistration && shouldSkipDomainWhois) {
@@ -2638,14 +2855,14 @@ async function verifyEmail(params) {
2638
2855
  result.validMx = mxRecords.length > 0;
2639
2856
  log(`[verifyEmail] MX records found: ${mxRecords.length}, valid: ${result.validMx}`);
2640
2857
  if (!result.validMx && result.metadata) {
2641
- result.metadata.error = exports.VerificationErrorCode.NO_MX_RECORDS;
2858
+ result.metadata.error = exports.VerificationErrorCode.noMxRecords;
2642
2859
  }
2643
2860
  if (verifySmtp && mxRecords.length > 0) {
2644
2861
  const cacheKey = `${emailAddress}:smtp`;
2645
2862
  const smtpCacheInstance = getCacheStore(params.cache, "smtp");
2646
2863
  const cachedSmtp = await smtpCacheInstance.get(cacheKey);
2647
2864
  if (cachedSmtp !== null && cachedSmtp !== void 0) {
2648
- result.validSmtp = cachedSmtp;
2865
+ result.validSmtp = (_b = cachedSmtp.isDeliverable) !== null && _b !== void 0 ? _b : null;
2649
2866
  log(`[verifyEmail] SMTP result from cache: ${result.validSmtp} for ${emailAddress}`);
2650
2867
  if (result.metadata) {
2651
2868
  result.metadata.cached = true;
@@ -2665,7 +2882,7 @@ async function verifyEmail(params) {
2665
2882
  domainPort = domainPorts[mxDomain.domain];
2666
2883
  }
2667
2884
  }
2668
- const { result: smtpResult, cached, portCached, port } = await verifyMailboxSMTP({
2885
+ const { smtpResult, cached, port } = await verifyMailboxSMTP({
2669
2886
  local,
2670
2887
  domain,
2671
2888
  mxRecords,
@@ -2678,22 +2895,26 @@ async function verifyEmail(params) {
2678
2895
  }
2679
2896
  });
2680
2897
  await smtpCacheInstance.set(cacheKey, smtpResult);
2681
- result.validSmtp = smtpResult;
2898
+ if (!smtpResult.canConnectSmtp) {
2899
+ result.validSmtp = null;
2900
+ } else {
2901
+ result.validSmtp = smtpResult.isDeliverable;
2902
+ }
2682
2903
  if (result.metadata)
2683
2904
  result.metadata.cached = cached;
2684
2905
  log(`[verifyEmail] SMTP verification result: ${result.validSmtp} for ${emailAddress} (cached for future use)`);
2685
2906
  }
2686
2907
  if (result.validSmtp === false && result.metadata) {
2687
- result.metadata.error = exports.VerificationErrorCode.MAILBOX_NOT_FOUND;
2908
+ result.metadata.error = exports.VerificationErrorCode.mailboxNotFound;
2688
2909
  } else if (result.validSmtp === null && result.metadata) {
2689
- result.metadata.error = exports.VerificationErrorCode.SMTP_CONNECTION_FAILED;
2910
+ result.metadata.error = exports.VerificationErrorCode.smtpConnectionFailed;
2690
2911
  }
2691
2912
  }
2692
- } catch (err) {
2693
- log("[verifyEmail] Failed to resolve MX records", err);
2913
+ } catch (error) {
2914
+ log("[verifyEmail] Failed to resolve MX records", error);
2694
2915
  result.validMx = false;
2695
2916
  if (result.metadata) {
2696
- result.metadata.error = exports.VerificationErrorCode.NO_MX_RECORDS;
2917
+ result.metadata.error = exports.VerificationErrorCode.noMxRecords;
2697
2918
  }
2698
2919
  }
2699
2920
  } else if ((verifyMx || verifySmtp) && shouldSkipMx) {
@@ -2705,16 +2926,16 @@ async function verifyEmail(params) {
2705
2926
  return result;
2706
2927
  }
2707
2928
 
2708
- exports.COMMON_EMAIL_DOMAINS = COMMON_EMAIL_DOMAINS;
2709
2929
  exports.DEFAULT_CACHE_OPTIONS = DEFAULT_CACHE_OPTIONS;
2710
2930
  exports.LRUAdapter = LRUAdapter;
2711
2931
  exports.RedisAdapter = RedisAdapter;
2712
- exports.cleanNameForAlgrothin = cleanNameForAlgrothin;
2932
+ exports.cleanNameForAlgorithm = cleanNameForAlgorithm;
2713
2933
  exports.clearDefaultCache = clearDefaultCache;
2934
+ exports.commonEmailDomains = commonEmailDomains;
2714
2935
  exports.defaultDomainSuggestionMethod = defaultDomainSuggestionMethod;
2715
2936
  exports.defaultNameDetectionMethod = defaultNameDetectionMethod;
2716
2937
  exports.detectName = detectName;
2717
- exports.detectNameForAlgrothin = detectNameForAlgrothin;
2938
+ exports.detectNameForAlgorithm = detectNameForAlgorithm;
2718
2939
  exports.detectNameFromEmail = detectNameFromEmail;
2719
2940
  exports.domainPorts = domainPorts;
2720
2941
  exports.getCacheStore = getCacheStore;
@@ -2727,6 +2948,7 @@ exports.isDisposableEmail = isDisposableEmail;
2727
2948
  exports.isFreeEmail = isFreeEmail;
2728
2949
  exports.isValidEmail = isValidEmail;
2729
2950
  exports.isValidEmailDomain = isValidEmailDomain;
2951
+ exports.parseSmtpError = parseSmtpError;
2730
2952
  exports.resetDefaultCache = resetDefaultCache;
2731
2953
  exports.suggestDomain = suggestDomain;
2732
2954
  exports.suggestEmailDomain = suggestEmailDomain;