@emailcheck/email-validator-js 3.0.1-beta.0 → 3.0.1-beta.2

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 +471 -236
  13. package/dist/index.esm.js.map +1 -1
  14. package/dist/index.js +474 -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 +138 -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.esm.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { isValid, parse } from 'psl';
2
2
  import { lru } from 'tiny-lru';
3
- import { promises } from 'node:dns';
4
3
  import { stringSimilarity } from 'string-similarity-js';
4
+ import { promises } from 'node:dns';
5
5
  import * as net from 'node:net';
6
6
  import * as tls from 'node:tls';
7
7
 
@@ -44,31 +44,23 @@ class LRUAdapter {
44
44
  const DEFAULT_CACHE_OPTIONS = {
45
45
  ttl: {
46
46
  mx: 36e5,
47
- // 1 hour
48
47
  disposable: 864e5,
49
- // 24 hours
50
48
  free: 864e5,
51
- // 24 hours
52
49
  domainValid: 864e5,
53
- // 24 hours
54
50
  smtp: 18e5,
55
- // 30 minutes
56
- smtpPort: 36e5,
57
- // 1 hour
51
+ smtpPort: 864e5,
58
52
  domainSuggestion: 864e5,
59
- // 24 hours
60
53
  whois: 36e5
61
- // 1 hour
62
54
  },
63
55
  maxSize: {
64
- mx: 500,
65
- disposable: 1e3,
66
- free: 1e3,
67
- domainValid: 1e3,
68
- smtp: 500,
69
- smtpPort: 500,
70
- domainSuggestion: 1e3,
71
- whois: 200
56
+ mx: 1e4,
57
+ disposable: 1e4,
58
+ free: 1e4,
59
+ domainValid: 1e4,
60
+ smtp: 1e4,
61
+ smtpPort: 1e4,
62
+ domainSuggestion: 1e4,
63
+ whois: 1e4
72
64
  }
73
65
  };
74
66
  let defaultCacheInstance = null;
@@ -106,41 +98,7 @@ function resetDefaultCache() {
106
98
  defaultCacheInstance = null;
107
99
  }
108
100
 
109
- async function resolveMxRecords(params) {
110
- const { domain, cache, logger } = params;
111
- const log = logger || (() => {
112
- });
113
- const cacheStore = getCacheStore(cache, "mx");
114
- const cached = await cacheStore.get(domain);
115
- if (cached !== null && cached !== void 0) {
116
- log(`[resolveMxRecords] Cache hit for ${domain}: ${cached.length} MX records`);
117
- return cached;
118
- }
119
- log(`[resolveMxRecords] Performing DNS MX lookup for ${domain}`);
120
- try {
121
- const records = await promises.resolveMx(domain);
122
- records.sort((a, b) => {
123
- if (a.priority < b.priority) {
124
- return -1;
125
- }
126
- if (a.priority > b.priority) {
127
- return 1;
128
- }
129
- return 0;
130
- });
131
- const exchanges = records.map((record) => record.exchange);
132
- log(`[resolveMxRecords] Found ${exchanges.length} MX records for ${domain}: [${exchanges.join(", ")}]`);
133
- await cacheStore.set(domain, exchanges);
134
- log(`[resolveMxRecords] Cached ${exchanges.length} MX records for ${domain}`);
135
- return exchanges;
136
- } catch (error) {
137
- log(`[resolveMxRecords] MX lookup failed for ${domain}, caching empty result`);
138
- await cacheStore.set(domain, []);
139
- throw error;
140
- }
141
- }
142
-
143
- const COMMON_EMAIL_DOMAINS = [
101
+ const commonEmailDomains = [
144
102
  // Popular free email providers
145
103
  "gmail.com",
146
104
  "yahoo.com",
@@ -225,7 +183,7 @@ function getSimilarityThreshold(domain) {
225
183
  return 0.75;
226
184
  }
227
185
  function defaultDomainSuggestionMethod(domain, commonDomains) {
228
- const domainsToCheck = commonDomains || COMMON_EMAIL_DOMAINS;
186
+ const domainsToCheck = commonDomains || commonEmailDomains;
229
187
  const lowerDomain = domain.toLowerCase();
230
188
  if (domainsToCheck.includes(lowerDomain)) {
231
189
  return null;
@@ -281,7 +239,7 @@ async function defaultDomainSuggestionMethodImpl(domain, commonDomains, cache) {
281
239
  if (!domain || domain.length < 3) {
282
240
  return null;
283
241
  }
284
- const domainsToCheck = commonDomains || COMMON_EMAIL_DOMAINS;
242
+ const domainsToCheck = commonDomains || commonEmailDomains;
285
243
  const lowerDomain = domain.toLowerCase();
286
244
  const cacheKey = `${lowerDomain}:${domainsToCheck.length}`;
287
245
  const cacheStore = getCacheStore(cache, "domainSuggestion");
@@ -377,15 +335,107 @@ async function suggestEmailDomain(email, commonDomains, cache) {
377
335
  return null;
378
336
  }
379
337
  function isCommonDomain(domain, commonDomains) {
380
- const domainsToCheck = commonDomains || COMMON_EMAIL_DOMAINS;
338
+ const domainsToCheck = commonDomains || commonEmailDomains;
381
339
  return domainsToCheck.includes(domain.toLowerCase());
382
340
  }
383
341
  function getDomainSimilarity(domain1, domain2) {
384
342
  return stringSimilarity(domain1.toLowerCase(), domain2.toLowerCase());
385
343
  }
386
344
 
387
- const NAME_SEPARATORS = [".", "_", "-"];
388
- const COMMON_NAME_SUFFIXES = [
345
+ async function isValidEmailDomain(emailOrDomain, cache) {
346
+ let [localPart, emailDomain] = (emailOrDomain === null || emailOrDomain === void 0 ? void 0 : emailOrDomain.split("@")) || [];
347
+ if (!emailDomain) {
348
+ emailDomain = localPart;
349
+ }
350
+ if (!emailDomain) {
351
+ return false;
352
+ }
353
+ const cacheStore = getCacheStore(cache, "domainValid");
354
+ const cached = await cacheStore.get(emailDomain);
355
+ if (cached !== null && cached !== void 0) {
356
+ return cached.isValid;
357
+ }
358
+ try {
359
+ const isValidResult = isValid(emailDomain) || false;
360
+ const richResult = {
361
+ isValid: isValidResult,
362
+ hasMX: false,
363
+ // MX not checked in this function
364
+ checkedAt: Date.now()
365
+ };
366
+ await cacheStore.set(emailDomain, richResult);
367
+ return isValidResult;
368
+ } catch (validationError) {
369
+ const errorResult = {
370
+ isValid: false,
371
+ hasMX: false,
372
+ checkedAt: Date.now()
373
+ };
374
+ await cacheStore.set(emailDomain, errorResult);
375
+ return false;
376
+ }
377
+ }
378
+ function isValidEmail(emailAddress) {
379
+ if (!emailAddress || typeof emailAddress !== "string") {
380
+ return false;
381
+ }
382
+ 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,}))$/;
383
+ const emailLower = emailAddress.toLowerCase();
384
+ if (emailLower.indexOf(".+") !== -1)
385
+ return false;
386
+ if (emailLower.indexOf("..") !== -1)
387
+ return false;
388
+ if (emailLower.startsWith(".") || emailLower.endsWith("."))
389
+ return false;
390
+ const parts = emailAddress.split("@");
391
+ if (parts.length !== 2)
392
+ return false;
393
+ const [localPart, domain] = parts;
394
+ if (!localPart || !domain)
395
+ return false;
396
+ if (localPart.length > 64)
397
+ return false;
398
+ if (domain.length > 253)
399
+ return false;
400
+ return re.test(emailLower);
401
+ }
402
+
403
+ async function resolveMxRecords(params) {
404
+ const { domain, cache, logger } = params;
405
+ const log = logger || (() => {
406
+ });
407
+ const cacheStore = getCacheStore(cache, "mx");
408
+ const cached = await cacheStore.get(domain);
409
+ if (cached !== null && cached !== void 0) {
410
+ log(`[resolveMxRecords] Cache hit for ${domain}: ${cached === null || cached === void 0 ? void 0 : cached.length} MX records`);
411
+ return cached;
412
+ }
413
+ log(`[resolveMxRecords] Performing DNS MX lookup for ${domain}`);
414
+ try {
415
+ const records = await promises.resolveMx(domain);
416
+ records === null || records === void 0 ? void 0 : records.sort((a, b) => {
417
+ if (a.priority < b.priority) {
418
+ return -1;
419
+ }
420
+ if (a.priority > b.priority) {
421
+ return 1;
422
+ }
423
+ return 0;
424
+ });
425
+ const exchanges = records === null || records === void 0 ? void 0 : records.map((record) => record.exchange);
426
+ 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(", ")}]`);
427
+ await cacheStore.set(domain, exchanges);
428
+ log(`[resolveMxRecords] Cached ${exchanges === null || exchanges === void 0 ? void 0 : exchanges.length} MX records for ${domain}`);
429
+ return exchanges;
430
+ } catch (error) {
431
+ log(`[resolveMxRecords] MX lookup failed for ${domain}, caching empty result`);
432
+ await cacheStore.set(domain, []);
433
+ throw error;
434
+ }
435
+ }
436
+
437
+ const nameSeparator = [".", "_", "-"];
438
+ const commonNameSuffixes = [
389
439
  "mail",
390
440
  "email",
391
441
  "contact",
@@ -400,7 +450,7 @@ const COMMON_NAME_SUFFIXES = [
400
450
  "notifications",
401
451
  "alerts"
402
452
  ];
403
- const CONTEXTUAL_SUFFIXES = [
453
+ const contextualSuffixes = [
404
454
  "dev",
405
455
  "company",
406
456
  "team",
@@ -432,7 +482,7 @@ const COMMON_TITLES = [
432
482
  "father",
433
483
  "sister"
434
484
  ];
435
- const COMMON_FIRST_NAMES = /* @__PURE__ */ new Set([
485
+ const commonFirstName = /* @__PURE__ */ new Set([
436
486
  // English names
437
487
  "james",
438
488
  "john",
@@ -610,7 +660,7 @@ const COMMON_FIRST_NAMES = /* @__PURE__ */ new Set([
610
660
  "sekou",
611
661
  "mariama"
612
662
  ]);
613
- const COMMON_LAST_NAMES = /* @__PURE__ */ new Set([
663
+ const commonLastName = /* @__PURE__ */ new Set([
614
664
  // English surnames
615
665
  "smith",
616
666
  "johnson",
@@ -730,19 +780,19 @@ function isYearLike(str) {
730
780
  return /^(19|20)\d{2}$/.test(str);
731
781
  }
732
782
  function isKnownFirstName(str) {
733
- return COMMON_FIRST_NAMES.has(str.toLowerCase());
783
+ return commonFirstName.has(str.toLowerCase());
734
784
  }
735
785
  function isKnownLastName(str) {
736
- return COMMON_LAST_NAMES.has(str.toLowerCase());
786
+ return commonLastName.has(str.toLowerCase());
737
787
  }
738
788
  function isTitle(str) {
739
789
  return COMMON_TITLES.includes(str.toLowerCase().replace(".", ""));
740
790
  }
741
791
  function getFirstNameScore(str) {
742
792
  const lower = str.toLowerCase();
743
- if (COMMON_FIRST_NAMES.has(lower))
793
+ if (commonFirstName.has(lower))
744
794
  return 1;
745
- if (COMMON_LAST_NAMES.has(lower))
795
+ if (commonLastName.has(lower))
746
796
  return 0.3;
747
797
  if (str.length >= 2 && str.length <= 15 && /^[a-zA-Z]+$/.test(str))
748
798
  return 0.5;
@@ -750,9 +800,9 @@ function getFirstNameScore(str) {
750
800
  }
751
801
  function getLastNameScore(str) {
752
802
  const lower = str.toLowerCase();
753
- if (COMMON_LAST_NAMES.has(lower))
803
+ if (commonLastName.has(lower))
754
804
  return 1;
755
- if (COMMON_FIRST_NAMES.has(lower))
805
+ if (commonFirstName.has(lower))
756
806
  return 0.3;
757
807
  if (str.length >= 2 && str.length <= 20 && /^[a-zA-Z]+$/.test(str))
758
808
  return 0.5;
@@ -861,7 +911,7 @@ function isLikelyName(str, allowNumbers = false, allowSingleLetter = false) {
861
911
  return false;
862
912
  if (str.length === 1 && allowSingleLetter && /^[a-zA-Z]$/.test(str))
863
913
  return true;
864
- if (COMMON_NAME_SUFFIXES.includes(str.toLowerCase()))
914
+ if (commonNameSuffixes.includes(str.toLowerCase()))
865
915
  return false;
866
916
  if (allowNumbers) {
867
917
  if (/^\d+$/.test(str))
@@ -923,7 +973,7 @@ function defaultNameDetectionMethod(email) {
923
973
  }
924
974
  }
925
975
  if (!firstName && !lastName) {
926
- for (const separator of NAME_SEPARATORS) {
976
+ for (const separator of nameSeparator) {
927
977
  if (cleanedLocal.includes(separator)) {
928
978
  const parts = cleanedLocal.split(separator).filter((p) => p.length > 0);
929
979
  if (parts.length === 2) {
@@ -985,7 +1035,7 @@ function defaultNameDetectionMethod(email) {
985
1035
  const firstParsed = parseCompositeNamePart(first);
986
1036
  const middleParsed = parseCompositeNamePart(middle);
987
1037
  const lastParsed = parseCompositeNamePart(last);
988
- const isLastSuffix = COMMON_NAME_SUFFIXES.includes(last.toLowerCase()) || CONTEXTUAL_SUFFIXES.includes(last.toLowerCase()) || isYearLike(last);
1038
+ const isLastSuffix = commonNameSuffixes.includes(last.toLowerCase()) || contextualSuffixes.includes(last.toLowerCase()) || isYearLike(last);
989
1039
  if (isLastSuffix) {
990
1040
  if (isLikelyName(first, true, true) && isLikelyName(middle, true, true)) {
991
1041
  const cleanedFirst = firstParsed.hasNumbers ? firstParsed.cleaned : first;
@@ -1018,7 +1068,7 @@ function defaultNameDetectionMethod(email) {
1018
1068
  } else if (parts.length > 3) {
1019
1069
  const firstPart = parts[0];
1020
1070
  const lastPartLower = parts[parts.length - 1].toLowerCase();
1021
- const isLastPartSuffix = COMMON_NAME_SUFFIXES.includes(lastPartLower) || CONTEXTUAL_SUFFIXES.includes(lastPartLower) || isYearLike(parts[parts.length - 1]);
1071
+ const isLastPartSuffix = commonNameSuffixes.includes(lastPartLower) || contextualSuffixes.includes(lastPartLower) || isYearLike(parts[parts.length - 1]);
1022
1072
  const effectiveLastIndex = isLastPartSuffix ? parts.length - 2 : parts.length - 1;
1023
1073
  const lastToUse = effectiveLastIndex >= 0 ? parts[effectiveLastIndex] : null;
1024
1074
  if (lastToUse && isLikelyName(firstPart, true, true) && isLikelyName(lastToUse, true, true)) {
@@ -1101,7 +1151,7 @@ function detectNameFromEmail(params) {
1101
1151
  }
1102
1152
  return defaultNameDetectionMethod(email);
1103
1153
  }
1104
- function cleanNameForAlgrothin(name) {
1154
+ function cleanNameForAlgorithm(name) {
1105
1155
  if (!name)
1106
1156
  return "";
1107
1157
  let cleaned = name.replace(/[._*]/g, "");
@@ -1111,13 +1161,13 @@ function cleanNameForAlgrothin(name) {
1111
1161
  }
1112
1162
  return cleaned;
1113
1163
  }
1114
- function detectNameForAlgrothin(email) {
1164
+ function detectNameForAlgorithm(email) {
1115
1165
  const detectedName = detectName(email);
1116
1166
  if (!detectedName) {
1117
1167
  return null;
1118
1168
  }
1119
- const cleanedFirstName = detectedName.firstName ? cleanNameForAlgrothin(detectedName.firstName) : void 0;
1120
- const cleanedLastName = detectedName.lastName ? cleanNameForAlgrothin(detectedName.lastName) : void 0;
1169
+ const cleanedFirstName = detectedName.firstName ? cleanNameForAlgorithm(detectedName.firstName) : void 0;
1170
+ const cleanedLastName = detectedName.lastName ? cleanNameForAlgorithm(detectedName.lastName) : void 0;
1121
1171
  if (!cleanedFirstName && !cleanedLastName) {
1122
1172
  return null;
1123
1173
  }
@@ -1134,27 +1184,143 @@ function detectName(email) {
1134
1184
 
1135
1185
  var VerificationErrorCode;
1136
1186
  (function(VerificationErrorCode2) {
1137
- VerificationErrorCode2["INVALID_FORMAT"] = "INVALID_FORMAT";
1138
- VerificationErrorCode2["INVALID_DOMAIN"] = "INVALID_DOMAIN";
1139
- VerificationErrorCode2["NO_MX_RECORDS"] = "NO_MX_RECORDS";
1140
- VerificationErrorCode2["SMTP_CONNECTION_FAILED"] = "SMTP_CONNECTION_FAILED";
1141
- VerificationErrorCode2["SMTP_TIMEOUT"] = "SMTP_TIMEOUT";
1142
- VerificationErrorCode2["MAILBOX_NOT_FOUND"] = "MAILBOX_NOT_FOUND";
1143
- VerificationErrorCode2["MAILBOX_FULL"] = "MAILBOX_FULL";
1144
- VerificationErrorCode2["NETWORK_ERROR"] = "NETWORK_ERROR";
1145
- VerificationErrorCode2["DISPOSABLE_EMAIL"] = "DISPOSABLE_EMAIL";
1146
- VerificationErrorCode2["FREE_EMAIL_PROVIDER"] = "FREE_EMAIL_PROVIDER";
1187
+ VerificationErrorCode2["invalidFormat"] = "INVALID_FORMAT";
1188
+ VerificationErrorCode2["invalidDomain"] = "INVALID_DOMAIN";
1189
+ VerificationErrorCode2["noMxRecords"] = "NO_MX_RECORDS";
1190
+ VerificationErrorCode2["smtpConnectionFailed"] = "SMTP_CONNECTION_FAILED";
1191
+ VerificationErrorCode2["smtpTimeout"] = "SMTP_TIMEOUT";
1192
+ VerificationErrorCode2["mailboxNotFound"] = "MAILBOX_NOT_FOUND";
1193
+ VerificationErrorCode2["mailboxFull"] = "MAILBOX_FULL";
1194
+ VerificationErrorCode2["networkError"] = "NETWORK_ERROR";
1195
+ VerificationErrorCode2["disposableEmail"] = "DISPOSABLE_EMAIL";
1196
+ VerificationErrorCode2["freeEmailProvider"] = "FREE_EMAIL_PROVIDER";
1147
1197
  })(VerificationErrorCode || (VerificationErrorCode = {}));
1198
+ var EmailProvider;
1199
+ (function(EmailProvider2) {
1200
+ EmailProvider2["gmail"] = "gmail";
1201
+ EmailProvider2["hotmailB2b"] = "hotmail_b2b";
1202
+ EmailProvider2["hotmailB2c"] = "hotmail_b2c";
1203
+ EmailProvider2["proofpoint"] = "proofpoint";
1204
+ EmailProvider2["mimecast"] = "mimecast";
1205
+ EmailProvider2["yahoo"] = "yahoo";
1206
+ EmailProvider2["everythingElse"] = "everything_else";
1207
+ })(EmailProvider || (EmailProvider = {}));
1208
+ function parseSmtpError(errorMessage) {
1209
+ const lowerError = errorMessage.toLowerCase();
1210
+ const networkErrorPatterns = [
1211
+ "etimedout",
1212
+ "econnrefused",
1213
+ "enotfound",
1214
+ "econnreset",
1215
+ "socket hang up",
1216
+ "connection_timeout",
1217
+ "socket_timeout",
1218
+ "connection_error",
1219
+ "connection_closed"
1220
+ ];
1221
+ const isNetworkError = networkErrorPatterns.some((pattern) => lowerError.includes(pattern));
1222
+ if (isNetworkError) {
1223
+ return {
1224
+ isDisabled: false,
1225
+ hasFullInbox: false,
1226
+ isInvalid: true,
1227
+ isCatchAll: false
1228
+ };
1229
+ }
1230
+ const disabledPatterns = [
1231
+ "account disabled",
1232
+ "account is disabled",
1233
+ "user disabled",
1234
+ "user is disabled",
1235
+ "account locked",
1236
+ "account is locked",
1237
+ "user blocked",
1238
+ "user is blocked",
1239
+ "mailbox disabled",
1240
+ "delivery not authorized",
1241
+ "message rejected",
1242
+ "access denied",
1243
+ "permission denied",
1244
+ "recipient unknown",
1245
+ "recipient address rejected",
1246
+ "user unknown",
1247
+ "address unknown",
1248
+ "invalid recipient",
1249
+ "not a valid recipient",
1250
+ "recipient does not exist",
1251
+ "no such user",
1252
+ "user does not exist",
1253
+ "mailbox unavailable",
1254
+ "recipient unavailable",
1255
+ "address rejected",
1256
+ "550",
1257
+ "551",
1258
+ "553",
1259
+ "not_found",
1260
+ "ambiguous"
1261
+ ];
1262
+ const fullInboxPatterns = [
1263
+ "mailbox full",
1264
+ "inbox full",
1265
+ "quota exceeded",
1266
+ "over quota",
1267
+ "storage limit exceeded",
1268
+ "message too large",
1269
+ "insufficient storage",
1270
+ "mailbox over quota",
1271
+ "over the quota",
1272
+ "mailbox size limit exceeded",
1273
+ "account over quota",
1274
+ "storage space",
1275
+ "overquota",
1276
+ "452",
1277
+ "552",
1278
+ "over_quota"
1279
+ ];
1280
+ const catchAllPatterns = [
1281
+ "accept all mail",
1282
+ "catch-all",
1283
+ "catchall",
1284
+ "wildcard",
1285
+ "accepts any recipient",
1286
+ "recipient address accepted"
1287
+ ];
1288
+ const rateLimitPatterns = [
1289
+ "receiving mail at a rate that",
1290
+ "rate limit",
1291
+ "too many messages",
1292
+ "temporarily rejected",
1293
+ "try again later",
1294
+ "greylisted",
1295
+ "greylist",
1296
+ "deferring",
1297
+ "temporarily deferred",
1298
+ "421",
1299
+ "450",
1300
+ "451",
1301
+ "temporary_failure"
1302
+ ];
1303
+ const isDisabled = disabledPatterns.some((pattern) => lowerError.includes(pattern)) || lowerError.startsWith("550") || lowerError.startsWith("551") || lowerError.startsWith("553");
1304
+ const hasFullInbox = fullInboxPatterns.some((pattern) => lowerError.includes(pattern)) || lowerError.startsWith("452") || lowerError.startsWith("552");
1305
+ const isCatchAll = catchAllPatterns.some((pattern) => lowerError.includes(pattern));
1306
+ const isInvalid = !isDisabled && !hasFullInbox && !isCatchAll && !rateLimitPatterns.some((pattern) => lowerError.includes(pattern)) && !lowerError.startsWith("421") && !lowerError.startsWith("450") && !lowerError.startsWith("451");
1307
+ return {
1308
+ isDisabled,
1309
+ hasFullInbox,
1310
+ isInvalid,
1311
+ isCatchAll
1312
+ };
1313
+ }
1148
1314
  var SMTPStep;
1149
1315
  (function(SMTPStep2) {
1150
- SMTPStep2["GREETING"] = "GREETING";
1151
- SMTPStep2["EHLO"] = "EHLO";
1152
- SMTPStep2["HELO"] = "HELO";
1153
- SMTPStep2["STARTTLS"] = "STARTTLS";
1154
- SMTPStep2["MAIL_FROM"] = "MAIL_FROM";
1155
- SMTPStep2["RCPT_TO"] = "RCPT_TO";
1156
- SMTPStep2["VRFY"] = "VRFY";
1157
- SMTPStep2["QUIT"] = "QUIT";
1316
+ SMTPStep2["greeting"] = "GREETING";
1317
+ SMTPStep2["ehlo"] = "EHLO";
1318
+ SMTPStep2["helo"] = "HELO";
1319
+ SMTPStep2["startTls"] = "STARTTLS";
1320
+ SMTPStep2["mailFrom"] = "MAIL_FROM";
1321
+ SMTPStep2["rcptTo"] = "RCPT_TO";
1322
+ SMTPStep2["vrfy"] = "VRFY";
1323
+ SMTPStep2["quit"] = "QUIT";
1158
1324
  })(SMTPStep || (SMTPStep = {}));
1159
1325
 
1160
1326
  function isIPAddress(host) {
@@ -1167,6 +1333,10 @@ function isIPAddress(host) {
1167
1333
  return ipv6Regex.test(host);
1168
1334
  }
1169
1335
  function isOverQuota(smtpReply) {
1336
+ var _a;
1337
+ if ((_a = smtpReply === null || smtpReply === void 0 ? void 0 : smtpReply.toLowerCase()) === null || _a === void 0 ? void 0 : _a.includes("excessively high number of invalid recipients")) {
1338
+ return true;
1339
+ }
1170
1340
  return Boolean(smtpReply && /(over quota)/gi.test(smtpReply));
1171
1341
  }
1172
1342
  function isInvalidMailboxError(smtpReply) {
@@ -1188,9 +1358,38 @@ async function verifyMailboxSMTP(params) {
1188
1358
  const { ports = DEFAULT_PORTS, timeout = DEFAULT_TIMEOUT, maxRetries = DEFAULT_MAX_RETRIES, tls: tlsConfig = true, hostname = "localhost", useVRFY = true, cache, debug = false, sequence } = options;
1189
1359
  const log = debug ? (...args) => console.log("[SMTP]", ...args) : () => {
1190
1360
  };
1361
+ const createSmtpResult = (result, port, tlsUsed, mxHost2) => {
1362
+ const reason = result === true ? "valid" : result === null ? "ambiguous" : "not_found";
1363
+ const parsedError = parseSmtpError(reason);
1364
+ return {
1365
+ canConnectSmtp: result !== null,
1366
+ hasFullInbox: parsedError.hasFullInbox,
1367
+ isCatchAll: parsedError.isCatchAll,
1368
+ isDeliverable: result === true,
1369
+ isDisabled: result === false && parsedError.isDisabled,
1370
+ error: result === null ? reason : result === false ? reason : void 0,
1371
+ providerUsed: EmailProvider.everythingElse,
1372
+ checkedAt: Date.now()
1373
+ };
1374
+ };
1375
+ const createFailureResult = (error) => ({
1376
+ canConnectSmtp: false,
1377
+ hasFullInbox: false,
1378
+ isCatchAll: false,
1379
+ isDeliverable: false,
1380
+ isDisabled: false,
1381
+ error,
1382
+ providerUsed: EmailProvider.everythingElse,
1383
+ checkedAt: Date.now()
1384
+ });
1191
1385
  if (!mxRecords || mxRecords.length === 0) {
1192
1386
  log("No MX records found");
1193
- return { result: false, cached: false, port: 0, portCached: false };
1387
+ return {
1388
+ smtpResult: createFailureResult("No MX records found"),
1389
+ cached: false,
1390
+ port: 0,
1391
+ portCached: false
1392
+ };
1194
1393
  }
1195
1394
  const mxHost = mxRecords[0];
1196
1395
  log(`Verifying ${local}@${domain} via ${mxHost}`);
@@ -1199,16 +1398,16 @@ async function verifyMailboxSMTP(params) {
1199
1398
  let cachedResult;
1200
1399
  try {
1201
1400
  cachedResult = await smtpCacheStore.get(`${mxHost}:${local}@${domain}`);
1202
- if (cachedResult !== void 0) {
1203
- log(`Using cached SMTP result: ${cachedResult}`);
1401
+ if (cachedResult !== void 0 && cachedResult !== null) {
1402
+ log(`Using cached SMTP result: ${cachedResult.isDeliverable}`);
1204
1403
  return {
1205
- result: typeof cachedResult === "boolean" ? cachedResult : null,
1404
+ smtpResult: cachedResult,
1206
1405
  cached: true,
1207
1406
  port: 0,
1208
1407
  portCached: false
1209
1408
  };
1210
1409
  }
1211
- } catch (_error) {
1410
+ } catch (ignoredError) {
1212
1411
  cachedResult = void 0;
1213
1412
  }
1214
1413
  }
@@ -1217,7 +1416,7 @@ async function verifyMailboxSMTP(params) {
1217
1416
  let cachedPort;
1218
1417
  try {
1219
1418
  cachedPort = await smtpPortCacheStore.get(mxHost);
1220
- } catch (_error) {
1419
+ } catch (ignoredError) {
1221
1420
  cachedPort = null;
1222
1421
  }
1223
1422
  if (cachedPort) {
@@ -1234,21 +1433,22 @@ async function verifyMailboxSMTP(params) {
1234
1433
  sequence,
1235
1434
  log
1236
1435
  });
1237
- if (smtpCacheStore && result !== void 0) {
1436
+ const smtpResult = createSmtpResult(result);
1437
+ if (smtpCacheStore) {
1238
1438
  try {
1239
- await smtpCacheStore.set(`${mxHost}:${local}@${domain}`, result);
1439
+ await smtpCacheStore.set(`${mxHost}:${local}@${domain}`, smtpResult);
1240
1440
  log(`Cached SMTP result ${result} for ${local}@${domain} via ${mxHost}`);
1241
- } catch (_error) {
1441
+ } catch (ignoredError) {
1242
1442
  }
1243
1443
  }
1244
- return { result, cached: false, port: cachedPort, portCached: true };
1444
+ return { smtpResult, cached: false, port: cachedPort, portCached: true };
1245
1445
  }
1246
1446
  }
1247
1447
  for (const port of ports) {
1248
1448
  log(`Testing port ${port}`);
1249
1449
  for (let attempt = 0; attempt < maxRetries; attempt++) {
1250
1450
  if (attempt > 0) {
1251
- const delay = Math.min(1e3 * 2 ** (attempt - 1), 5e3);
1451
+ const delay = Math.min(200 * 2 ** (attempt - 1), 800);
1252
1452
  log(`Retry ${attempt + 1}, waiting ${delay}ms`);
1253
1453
  await new Promise((resolve) => setTimeout(resolve, delay));
1254
1454
  }
@@ -1264,11 +1464,12 @@ async function verifyMailboxSMTP(params) {
1264
1464
  sequence,
1265
1465
  log
1266
1466
  });
1267
- if (smtpCacheStore && result !== void 0) {
1467
+ const smtpResult = createSmtpResult(result);
1468
+ if (smtpCacheStore) {
1268
1469
  try {
1269
- await smtpCacheStore.set(`${mxHost}:${local}@${domain}`, result);
1470
+ await smtpCacheStore.set(`${mxHost}:${local}@${domain}`, smtpResult);
1270
1471
  log(`Cached SMTP result ${result} for ${local}@${domain} via ${mxHost}`);
1271
- } catch (_error) {
1472
+ } catch (ignoredError) {
1272
1473
  }
1273
1474
  }
1274
1475
  if (result !== null) {
@@ -1276,15 +1477,20 @@ async function verifyMailboxSMTP(params) {
1276
1477
  try {
1277
1478
  await smtpPortCacheStore.set(mxHost, port);
1278
1479
  log(`Cached port ${port} for ${mxHost}`);
1279
- } catch (_error) {
1480
+ } catch (ignoredError) {
1280
1481
  }
1281
1482
  }
1282
- return { result, cached: false, port, portCached: false };
1483
+ return { smtpResult, cached: false, port, portCached: false };
1283
1484
  }
1284
1485
  }
1285
1486
  }
1286
1487
  log("All ports failed");
1287
- return { result: null, cached: false, port: 0, portCached: false };
1488
+ return {
1489
+ smtpResult: createFailureResult("All SMTP connection attempts failed"),
1490
+ cached: false,
1491
+ port: 0,
1492
+ portCached: false
1493
+ };
1288
1494
  }
1289
1495
  async function testSMTPConnection(params) {
1290
1496
  const { mxHost, port, local, domain, timeout, tlsConfig, hostname, useVRFY, sequence, log } = params;
@@ -1292,11 +1498,11 @@ async function testSMTPConnection(params) {
1292
1498
  const useTLS = tlsConfig !== false && (portConfig.tls || portConfig.starttls);
1293
1499
  const implicitTLS = portConfig.tls;
1294
1500
  const defaultSequence = {
1295
- steps: [SMTPStep.GREETING, SMTPStep.EHLO, SMTPStep.MAIL_FROM, SMTPStep.RCPT_TO]
1501
+ steps: [SMTPStep.greeting, SMTPStep.ehlo, SMTPStep.mailFrom, SMTPStep.rcptTo]
1296
1502
  };
1297
1503
  const activeSequence = sequence || defaultSequence;
1298
1504
  if (port === 25) {
1299
- activeSequence.steps = activeSequence.steps.map((step) => step === SMTPStep.EHLO ? SMTPStep.HELO : step);
1505
+ activeSequence.steps = activeSequence.steps.map((step) => step === SMTPStep.ehlo ? SMTPStep.helo : step);
1300
1506
  }
1301
1507
  const tlsOptions = {
1302
1508
  host: mxHost,
@@ -1314,7 +1520,7 @@ async function testSMTPConnection(params) {
1314
1520
  let resolved = false;
1315
1521
  let supportsSTARTTLS = false;
1316
1522
  let supportsVRFY = false;
1317
- const cleanup = () => {
1523
+ let cleanup = () => {
1318
1524
  if (resolved)
1319
1525
  return;
1320
1526
  resolved = true;
@@ -1350,31 +1556,31 @@ async function testSMTPConnection(params) {
1350
1556
  if (resolved)
1351
1557
  return;
1352
1558
  switch (step) {
1353
- case SMTPStep.EHLO:
1559
+ case SMTPStep.ehlo:
1354
1560
  sendCommand(`EHLO ${hostname}`);
1355
1561
  break;
1356
- case SMTPStep.HELO:
1562
+ case SMTPStep.helo:
1357
1563
  sendCommand(`HELO ${domain}`);
1358
1564
  break;
1359
- case SMTPStep.GREETING:
1565
+ case SMTPStep.greeting:
1360
1566
  break;
1361
- case SMTPStep.STARTTLS:
1567
+ case SMTPStep.startTls:
1362
1568
  sendCommand("STARTTLS");
1363
1569
  break;
1364
- case SMTPStep.MAIL_FROM: {
1570
+ case SMTPStep.mailFrom: {
1365
1571
  const from = activeSequence.from || "<>";
1366
1572
  sendCommand(`MAIL FROM:${from}`);
1367
1573
  break;
1368
1574
  }
1369
- case SMTPStep.RCPT_TO:
1575
+ case SMTPStep.rcptTo:
1370
1576
  sendCommand(`RCPT TO:<${local}@${domain}>`);
1371
1577
  break;
1372
- case SMTPStep.VRFY: {
1578
+ case SMTPStep.vrfy: {
1373
1579
  const vrfyTarget = activeSequence.vrfyTarget || local;
1374
1580
  sendCommand(`VRFY ${vrfyTarget}`);
1375
1581
  break;
1376
1582
  }
1377
- case SMTPStep.QUIT:
1583
+ case SMTPStep.quit:
1378
1584
  sendCommand("QUIT");
1379
1585
  break;
1380
1586
  }
@@ -1398,14 +1604,14 @@ async function testSMTPConnection(params) {
1398
1604
  }
1399
1605
  if (isMultiline) {
1400
1606
  const currentStep2 = activeSequence.steps[currentStepIndex];
1401
- if (currentStep2 === SMTPStep.EHLO && code === "250") {
1607
+ if (currentStep2 === SMTPStep.ehlo && code === "250") {
1402
1608
  const upper = response.toUpperCase();
1403
1609
  if (upper.includes("STARTTLS"))
1404
1610
  supportsSTARTTLS = true;
1405
1611
  if (upper.includes("VRFY"))
1406
1612
  supportsVRFY = true;
1407
1613
  }
1408
- if (currentStep2 === SMTPStep.HELO && code === "250") {
1614
+ if (currentStep2 === SMTPStep.helo && code === "250") {
1409
1615
  const upper = response.toUpperCase();
1410
1616
  if (upper.includes("VRFY"))
1411
1617
  supportsVRFY = true;
@@ -1418,19 +1624,19 @@ async function testSMTPConnection(params) {
1418
1624
  }
1419
1625
  const currentStep = activeSequence.steps[currentStepIndex];
1420
1626
  switch (currentStep) {
1421
- case SMTPStep.GREETING:
1627
+ case SMTPStep.greeting:
1422
1628
  if (code.startsWith("220")) {
1423
1629
  nextStep();
1424
1630
  } else {
1425
1631
  finish(null, "no_greeting");
1426
1632
  }
1427
1633
  break;
1428
- case SMTPStep.EHLO:
1634
+ case SMTPStep.ehlo:
1429
1635
  if (code.startsWith("250")) {
1430
- const hasSTARTTLS = activeSequence.steps.includes(SMTPStep.STARTTLS);
1636
+ const hasSTARTTLS = activeSequence.steps.includes(SMTPStep.startTls);
1431
1637
  if (!isTLS && useTLS && supportsSTARTTLS && !implicitTLS && hasSTARTTLS) {
1432
- currentStepIndex = activeSequence.steps.indexOf(SMTPStep.STARTTLS);
1433
- executeStep(SMTPStep.STARTTLS);
1638
+ currentStepIndex = activeSequence.steps.indexOf(SMTPStep.startTls);
1639
+ executeStep(SMTPStep.startTls);
1434
1640
  } else {
1435
1641
  nextStep();
1436
1642
  }
@@ -1438,14 +1644,14 @@ async function testSMTPConnection(params) {
1438
1644
  finish(null, "ehlo_failed");
1439
1645
  }
1440
1646
  break;
1441
- case SMTPStep.HELO:
1647
+ case SMTPStep.helo:
1442
1648
  if (code.startsWith("250")) {
1443
1649
  nextStep();
1444
1650
  } else {
1445
1651
  finish(null, "helo_failed");
1446
1652
  }
1447
1653
  break;
1448
- case SMTPStep.STARTTLS:
1654
+ case SMTPStep.startTls:
1449
1655
  if (code.startsWith("220")) {
1450
1656
  const plainSocket = socket;
1451
1657
  socket = tls.connect({
@@ -1456,7 +1662,7 @@ async function testSMTPConnection(params) {
1456
1662
  isTLS = true;
1457
1663
  log("TLS upgraded");
1458
1664
  buffer = "";
1459
- const starttlsIndex = activeSequence.steps.indexOf(SMTPStep.STARTTLS);
1665
+ const starttlsIndex = activeSequence.steps.indexOf(SMTPStep.startTls);
1460
1666
  currentStepIndex = starttlsIndex;
1461
1667
  nextStep();
1462
1668
  });
@@ -1466,28 +1672,28 @@ async function testSMTPConnection(params) {
1466
1672
  nextStep();
1467
1673
  }
1468
1674
  break;
1469
- case SMTPStep.MAIL_FROM:
1675
+ case SMTPStep.mailFrom:
1470
1676
  if (code.startsWith("250")) {
1471
1677
  nextStep();
1472
1678
  } else {
1473
1679
  finish(null, "mail_from_rejected");
1474
1680
  }
1475
1681
  break;
1476
- case SMTPStep.RCPT_TO:
1682
+ case SMTPStep.rcptTo:
1477
1683
  if (code.startsWith("250") || code.startsWith("251")) {
1478
1684
  finish(true, "valid");
1479
1685
  } else if (code.startsWith("552") || code.startsWith("452")) {
1480
1686
  finish(false, "over_quota");
1481
1687
  } else if (code.startsWith("4")) {
1482
1688
  finish(null, "temporary_failure");
1483
- } else if (useVRFY && supportsVRFY && code.startsWith("5") && activeSequence.steps.includes(SMTPStep.VRFY)) {
1484
- currentStepIndex = activeSequence.steps.indexOf(SMTPStep.VRFY);
1485
- executeStep(SMTPStep.VRFY);
1689
+ } else if (useVRFY && supportsVRFY && code.startsWith("5") && activeSequence.steps.includes(SMTPStep.vrfy)) {
1690
+ currentStepIndex = activeSequence.steps.indexOf(SMTPStep.vrfy);
1691
+ executeStep(SMTPStep.vrfy);
1486
1692
  } else {
1487
1693
  finish(null, "ambiguous");
1488
1694
  }
1489
1695
  break;
1490
- case SMTPStep.VRFY:
1696
+ case SMTPStep.vrfy:
1491
1697
  if (code.startsWith("250") || code.startsWith("252")) {
1492
1698
  finish(true, "vrfy_valid");
1493
1699
  } else if (code.startsWith("550")) {
@@ -1496,14 +1702,14 @@ async function testSMTPConnection(params) {
1496
1702
  finish(null, "vrfy_failed");
1497
1703
  }
1498
1704
  break;
1499
- case SMTPStep.QUIT:
1705
+ case SMTPStep.quit:
1500
1706
  if (code.startsWith("221")) {
1501
1707
  finish(null, "quit_received");
1502
1708
  }
1503
1709
  break;
1504
1710
  }
1505
1711
  };
1506
- const handleData = (data) => {
1712
+ let handleData = (data) => {
1507
1713
  if (resolved)
1508
1714
  return;
1509
1715
  buffer += data.toString();
@@ -1539,65 +1745,69 @@ async function testSMTPConnection(params) {
1539
1745
  return;
1540
1746
  }
1541
1747
  const firstStep = activeSequence.steps[0];
1542
- if (firstStep !== SMTPStep.GREETING) {
1748
+ let connectionTimeout;
1749
+ let stepTimeout;
1750
+ const resetActivityTimeout = () => {
1751
+ if (stepTimeout) {
1752
+ clearTimeout(stepTimeout);
1753
+ }
1754
+ stepTimeout = setTimeout(() => {
1755
+ if (!resolved) {
1756
+ log(`Step timeout after ${timeout}ms of inactivity`);
1757
+ finish(null, "step_timeout");
1758
+ }
1759
+ }, timeout);
1760
+ };
1761
+ connectionTimeout = setTimeout(() => {
1762
+ if (!resolved) {
1763
+ log(`Connection timeout after ${timeout}ms`);
1764
+ finish(null, "connection_timeout");
1765
+ }
1766
+ }, timeout);
1767
+ if (firstStep !== SMTPStep.greeting) {
1543
1768
  executeStep(firstStep);
1544
1769
  }
1545
- socket.setTimeout(timeout, () => finish(null, "timeout"));
1546
- socket.on("error", () => finish(null, "connection_error"));
1547
- socket.on("close", () => {
1770
+ socket.setTimeout(timeout, () => {
1771
+ if (!resolved) {
1772
+ log(`Socket timeout after ${timeout}ms`);
1773
+ finish(null, "socket_timeout");
1774
+ }
1775
+ });
1776
+ socket.on("error", (error) => {
1777
+ log(`Socket error: ${error.message}`);
1548
1778
  if (!resolved)
1779
+ finish(null, "connection_error");
1780
+ });
1781
+ socket.on("close", () => {
1782
+ if (!resolved) {
1783
+ log("Socket closed unexpectedly");
1549
1784
  finish(null, "connection_closed");
1785
+ }
1550
1786
  });
1787
+ const originalHandleData = handleData;
1788
+ handleData = (data) => {
1789
+ resetActivityTimeout();
1790
+ originalHandleData(data);
1791
+ };
1792
+ const enhancedCleanup = () => {
1793
+ if (resolved)
1794
+ return;
1795
+ resolved = true;
1796
+ if (connectionTimeout)
1797
+ clearTimeout(connectionTimeout);
1798
+ if (stepTimeout)
1799
+ clearTimeout(stepTimeout);
1800
+ socket.setTimeout(0);
1801
+ try {
1802
+ socket === null || socket === void 0 ? void 0 : socket.write("QUIT\r\n");
1803
+ } catch {
1804
+ }
1805
+ setTimeout(() => socket === null || socket === void 0 ? void 0 : socket.destroy(), 100);
1806
+ };
1807
+ cleanup = enhancedCleanup;
1551
1808
  });
1552
1809
  }
1553
1810
 
1554
- async function isValidEmailDomain(emailOrDomain, cache) {
1555
- let [_, emailDomain] = (emailOrDomain === null || emailOrDomain === void 0 ? void 0 : emailOrDomain.split("@")) || [];
1556
- if (!emailDomain) {
1557
- emailDomain = _;
1558
- }
1559
- if (!emailDomain) {
1560
- return false;
1561
- }
1562
- const cacheStore = getCacheStore(cache, "domainValid");
1563
- const cached = await cacheStore.get(emailDomain);
1564
- if (cached !== null && cached !== void 0) {
1565
- return cached;
1566
- }
1567
- try {
1568
- const result = isValid(emailDomain) || false;
1569
- await cacheStore.set(emailDomain, result);
1570
- return result;
1571
- } catch (_e) {
1572
- await cacheStore.set(emailDomain, false);
1573
- return false;
1574
- }
1575
- }
1576
- function isValidEmail(emailAddress) {
1577
- if (!emailAddress || typeof emailAddress !== "string") {
1578
- return false;
1579
- }
1580
- 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,}))$/;
1581
- const emailLower = emailAddress.toLowerCase();
1582
- if (emailLower.indexOf(".+") !== -1)
1583
- return false;
1584
- if (emailLower.indexOf("..") !== -1)
1585
- return false;
1586
- if (emailLower.startsWith(".") || emailLower.endsWith("."))
1587
- return false;
1588
- const parts = emailAddress.split("@");
1589
- if (parts.length !== 2)
1590
- return false;
1591
- const [localPart, domain] = parts;
1592
- if (!localPart || !domain)
1593
- return false;
1594
- if (localPart.length > 64)
1595
- return false;
1596
- if (domain.length > 253)
1597
- return false;
1598
- return re.test(emailLower);
1599
- }
1600
-
1601
1811
  const defaultRegex = {
1602
1812
  domainName: "Domain Name: *([^\\s]+)",
1603
1813
  registrar: "Registrar: *(.+)",
@@ -2015,7 +2225,7 @@ function parseWhoisData({ rawData, domain }) {
2015
2225
  return result;
2016
2226
  }
2017
2227
 
2018
- const WHOIS_SERVERS = {
2228
+ const whoisServers = {
2019
2229
  com: "whois.verisign-grs.com",
2020
2230
  net: "whois.verisign-grs.com",
2021
2231
  org: "whois.pir.org",
@@ -2115,7 +2325,7 @@ async function getWhoisData(domain, timeout = 5e3, debug = false, cache) {
2115
2325
  throw new Error("Invalid domain");
2116
2326
  }
2117
2327
  log(`[whois] extracted TLD: ${tld} for domain: ${domain}`);
2118
- const whoisServer = WHOIS_SERVERS[tld];
2328
+ const whoisServer = whoisServers[tld];
2119
2329
  if (!whoisServer) {
2120
2330
  log(`[whois] no specific server for TLD ${tld}, trying IANA`);
2121
2331
  const defaultServer = "whois.iana.org";
@@ -2141,8 +2351,8 @@ async function getWhoisData(domain, timeout = 5e3, debug = false, cache) {
2141
2351
  await cacheStore.set(cacheKey, whoisData);
2142
2352
  log(`[whois] successfully retrieved and cached WHOIS data for ${domain}`);
2143
2353
  return whoisData;
2144
- } catch (_error) {
2145
- log(`[whois] failed to get WHOIS data for ${domain}: ${_error instanceof Error ? _error.message : "Unknown error"}`);
2354
+ } catch (ignoredError) {
2355
+ log(`[whois] failed to get WHOIS data for ${domain}: ${ignoredError instanceof Error ? ignoredError.message : "Unknown error"}`);
2146
2356
  return null;
2147
2357
  }
2148
2358
  }
@@ -2179,8 +2389,8 @@ async function getDomainAge(domain, timeout = 5e3, debug = false, cache) {
2179
2389
  expirationDate: whoisData.expirationDate ? new Date(whoisData.expirationDate) : null,
2180
2390
  updatedDate: whoisData.updatedDate ? new Date(whoisData.updatedDate) : null
2181
2391
  };
2182
- } catch (_error) {
2183
- log(`[whois] error getting domain age for ${domain}: ${_error instanceof Error ? _error.message : "Unknown error"}`);
2392
+ } catch (ignoredError) {
2393
+ log(`[whois] error getting domain age for ${domain}: ${ignoredError instanceof Error ? ignoredError.message : "Unknown error"}`);
2184
2394
  return null;
2185
2395
  }
2186
2396
  }
@@ -2251,8 +2461,8 @@ async function getDomainRegistrationStatus(domain, timeout = 5e3, debug = false,
2251
2461
  isPendingDelete,
2252
2462
  isLocked
2253
2463
  };
2254
- } catch (_error) {
2255
- log(`[whois] error getting domain registration status for ${domain}: ${_error instanceof Error ? _error.message : "Unknown error"}`);
2464
+ } catch (ignoredError) {
2465
+ log(`[whois] error getting domain registration status for ${domain}: ${ignoredError instanceof Error ? ignoredError.message : "Unknown error"}`);
2256
2466
  return null;
2257
2467
  }
2258
2468
  }
@@ -2428,7 +2638,7 @@ function createErrorResult(email, _error) {
2428
2638
  metadata: {
2429
2639
  verificationTime: 0,
2430
2640
  cached: false,
2431
- error: VerificationErrorCode.SMTP_CONNECTION_FAILED
2641
+ error: VerificationErrorCode.smtpConnectionFailed
2432
2642
  }
2433
2643
  };
2434
2644
  }
@@ -2448,25 +2658,31 @@ async function isDisposableEmail(params) {
2448
2658
  let cached;
2449
2659
  try {
2450
2660
  cached = await cacheStore.get(emailDomain);
2451
- } catch (_error) {
2661
+ } catch (ignoredError) {
2452
2662
  cached = null;
2453
2663
  }
2454
2664
  if (cached !== null && cached !== void 0) {
2455
- log(`[isDisposableEmail] Cache hit for ${emailDomain}: ${cached}`);
2456
- return cached;
2665
+ log(`[isDisposableEmail] Cache hit for ${emailDomain}: ${cached.isDisposable}`);
2666
+ return cached.isDisposable;
2457
2667
  }
2458
2668
  if (!disposableEmailProviders) {
2459
2669
  disposableEmailProviders = new Set(require("./disposable-email-providers.json"));
2460
2670
  }
2461
- const result = disposableEmailProviders.has(emailDomain);
2671
+ const isDisposable = disposableEmailProviders.has(emailDomain);
2672
+ const richResult = {
2673
+ isDisposable,
2674
+ source: "disposable-email-providers.json",
2675
+ category: isDisposable ? "disposable" : void 0,
2676
+ checkedAt: Date.now()
2677
+ };
2462
2678
  try {
2463
- await cacheStore.set(emailDomain, result);
2464
- log(`[isDisposableEmail] Cached result for ${emailDomain}: ${result}`);
2465
- } catch (_error) {
2679
+ await cacheStore.set(emailDomain, richResult);
2680
+ log(`[isDisposableEmail] Cached result for ${emailDomain}: ${isDisposable}`);
2681
+ } catch (ignoredError) {
2466
2682
  log(`[isDisposableEmail] Cache write error for ${emailDomain}`);
2467
2683
  }
2468
- log(`[isDisposableEmail] Check result for ${emailDomain}: ${result}`);
2469
- return result;
2684
+ log(`[isDisposableEmail] Check result for ${emailDomain}: ${isDisposable}`);
2685
+ return isDisposable;
2470
2686
  }
2471
2687
  async function isFreeEmail(params) {
2472
2688
  const { emailOrDomain, cache, logger } = params;
@@ -2481,25 +2697,30 @@ async function isFreeEmail(params) {
2481
2697
  let cached;
2482
2698
  try {
2483
2699
  cached = await cacheStore.get(emailDomain);
2484
- } catch (_error) {
2700
+ } catch (ignoredError) {
2485
2701
  cached = null;
2486
2702
  }
2487
2703
  if (cached !== null && cached !== void 0) {
2488
- log(`[isFreeEmail] Cache hit for ${emailDomain}: ${cached}`);
2489
- return cached;
2704
+ log(`[isFreeEmail] Cache hit for ${emailDomain}: ${cached.isFree}`);
2705
+ return cached.isFree;
2490
2706
  }
2491
2707
  if (!freeEmailProviders) {
2492
2708
  freeEmailProviders = new Set(require("./free-email-providers.json"));
2493
2709
  }
2494
- const result = freeEmailProviders.has(emailDomain);
2710
+ const isFree = freeEmailProviders.has(emailDomain);
2711
+ const richResult = {
2712
+ isFree,
2713
+ provider: isFree ? emailDomain : void 0,
2714
+ checkedAt: Date.now()
2715
+ };
2495
2716
  try {
2496
- await cacheStore.set(emailDomain, result);
2497
- log(`[isFreeEmail] Cached result for ${emailDomain}: ${result}`);
2498
- } catch (_error) {
2717
+ await cacheStore.set(emailDomain, richResult);
2718
+ log(`[isFreeEmail] Cached result for ${emailDomain}: ${isFree}`);
2719
+ } catch (ignoredError) {
2499
2720
  log(`[isFreeEmail] Cache write error for ${emailDomain}`);
2500
2721
  }
2501
- log(`[isFreeEmail] Check result for ${emailDomain}: ${result}`);
2502
- return result;
2722
+ log(`[isFreeEmail] Check result for ${emailDomain}: ${isFree}`);
2723
+ return isFree;
2503
2724
  }
2504
2725
  const domainPorts = {
2505
2726
  // 465 or 587
@@ -2507,7 +2728,7 @@ const domainPorts = {
2507
2728
  "ovh.net": 465
2508
2729
  };
2509
2730
  async function verifyEmail(params) {
2510
- var _a;
2731
+ var _a, _b;
2511
2732
  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;
2512
2733
  const startTime = Date.now();
2513
2734
  const log = debug ? console.debug : (..._args) => {
@@ -2527,7 +2748,7 @@ async function verifyEmail(params) {
2527
2748
  if (!isValidEmail(emailAddress)) {
2528
2749
  if (result.metadata) {
2529
2750
  result.metadata.verificationTime = Date.now() - startTime;
2530
- result.metadata.error = VerificationErrorCode.INVALID_FORMAT;
2751
+ result.metadata.error = VerificationErrorCode.invalidFormat;
2531
2752
  }
2532
2753
  return result;
2533
2754
  }
@@ -2553,14 +2774,14 @@ async function verifyEmail(params) {
2553
2774
  if (!domain || !local) {
2554
2775
  if (result.metadata) {
2555
2776
  result.metadata.verificationTime = Date.now() - startTime;
2556
- result.metadata.error = VerificationErrorCode.INVALID_FORMAT;
2777
+ result.metadata.error = VerificationErrorCode.invalidFormat;
2557
2778
  }
2558
2779
  return result;
2559
2780
  }
2560
2781
  if (!await isValidEmailDomain(domain, params.cache)) {
2561
2782
  if (result.metadata) {
2562
2783
  result.metadata.verificationTime = Date.now() - startTime;
2563
- result.metadata.error = VerificationErrorCode.INVALID_DOMAIN;
2784
+ result.metadata.error = VerificationErrorCode.invalidDomain;
2564
2785
  }
2565
2786
  return result;
2566
2787
  }
@@ -2569,7 +2790,7 @@ async function verifyEmail(params) {
2569
2790
  result.isDisposable = await isDisposableEmail({ emailOrDomain: emailAddress, cache: params.cache, logger: log });
2570
2791
  log(`[verifyEmail] Disposable check result: ${result.isDisposable}`);
2571
2792
  if (result.isDisposable && result.metadata) {
2572
- result.metadata.error = VerificationErrorCode.DISPOSABLE_EMAIL;
2793
+ result.metadata.error = VerificationErrorCode.disposableEmail;
2573
2794
  }
2574
2795
  }
2575
2796
  if (checkFree) {
@@ -2590,8 +2811,8 @@ async function verifyEmail(params) {
2590
2811
  try {
2591
2812
  result.domainAge = await getDomainAge(domain, whoisTimeout, debug, params.cache);
2592
2813
  log(`[verifyEmail] Domain age result:`, result.domainAge ? `${result.domainAge.ageInDays} days` : "null");
2593
- } catch (err) {
2594
- log("[verifyEmail] Failed to get domain age", err);
2814
+ } catch (error) {
2815
+ log("[verifyEmail] Failed to get domain age", error);
2595
2816
  result.domainAge = null;
2596
2817
  }
2597
2818
  } else if (checkDomainAge && shouldSkipDomainWhois) {
@@ -2602,8 +2823,8 @@ async function verifyEmail(params) {
2602
2823
  try {
2603
2824
  result.domainRegistration = await getDomainRegistrationStatus(domain, whoisTimeout, debug, params.cache);
2604
2825
  log(`[verifyEmail] Domain registration result:`, ((_a = result.domainRegistration) === null || _a === void 0 ? void 0 : _a.isRegistered) ? "registered" : "not registered");
2605
- } catch (err) {
2606
- log("[verifyEmail] Failed to get domain registration status", err);
2826
+ } catch (error) {
2827
+ log("[verifyEmail] Failed to get domain registration status", error);
2607
2828
  result.domainRegistration = null;
2608
2829
  }
2609
2830
  } else if (checkDomainRegistration && shouldSkipDomainWhois) {
@@ -2616,14 +2837,19 @@ async function verifyEmail(params) {
2616
2837
  result.validMx = mxRecords.length > 0;
2617
2838
  log(`[verifyEmail] MX records found: ${mxRecords.length}, valid: ${result.validMx}`);
2618
2839
  if (!result.validMx && result.metadata) {
2619
- result.metadata.error = VerificationErrorCode.NO_MX_RECORDS;
2840
+ result.metadata.error = VerificationErrorCode.noMxRecords;
2620
2841
  }
2621
2842
  if (verifySmtp && mxRecords.length > 0) {
2622
2843
  const cacheKey = `${emailAddress}:smtp`;
2623
2844
  const smtpCacheInstance = getCacheStore(params.cache, "smtp");
2624
2845
  const cachedSmtp = await smtpCacheInstance.get(cacheKey);
2625
2846
  if (cachedSmtp !== null && cachedSmtp !== void 0) {
2626
- result.validSmtp = cachedSmtp;
2847
+ result.canConnectSmtp = cachedSmtp.canConnectSmtp;
2848
+ result.hasFullInbox = cachedSmtp.hasFullInbox;
2849
+ result.isCatchAll = cachedSmtp.isCatchAll;
2850
+ result.isDeliverable = cachedSmtp.isDeliverable;
2851
+ result.isDisabled = cachedSmtp.isDisabled;
2852
+ result.validSmtp = (_b = cachedSmtp.isDeliverable) !== null && _b !== void 0 ? _b : null;
2627
2853
  log(`[verifyEmail] SMTP result from cache: ${result.validSmtp} for ${emailAddress}`);
2628
2854
  if (result.metadata) {
2629
2855
  result.metadata.cached = true;
@@ -2643,7 +2869,7 @@ async function verifyEmail(params) {
2643
2869
  domainPort = domainPorts[mxDomain.domain];
2644
2870
  }
2645
2871
  }
2646
- const { result: smtpResult, cached, portCached, port } = await verifyMailboxSMTP({
2872
+ const { smtpResult, cached, port } = await verifyMailboxSMTP({
2647
2873
  local,
2648
2874
  domain,
2649
2875
  mxRecords,
@@ -2656,22 +2882,31 @@ async function verifyEmail(params) {
2656
2882
  }
2657
2883
  });
2658
2884
  await smtpCacheInstance.set(cacheKey, smtpResult);
2659
- result.validSmtp = smtpResult;
2885
+ result.canConnectSmtp = smtpResult === null || smtpResult === void 0 ? void 0 : smtpResult.canConnectSmtp;
2886
+ result.hasFullInbox = smtpResult === null || smtpResult === void 0 ? void 0 : smtpResult.hasFullInbox;
2887
+ result.isCatchAll = smtpResult === null || smtpResult === void 0 ? void 0 : smtpResult.isCatchAll;
2888
+ result.isDeliverable = smtpResult === null || smtpResult === void 0 ? void 0 : smtpResult.isDeliverable;
2889
+ result.isDisabled = smtpResult === null || smtpResult === void 0 ? void 0 : smtpResult.isDisabled;
2890
+ if (!smtpResult.canConnectSmtp) {
2891
+ result.validSmtp = null;
2892
+ } else {
2893
+ result.validSmtp = smtpResult.isDeliverable;
2894
+ }
2660
2895
  if (result.metadata)
2661
2896
  result.metadata.cached = cached;
2662
2897
  log(`[verifyEmail] SMTP verification result: ${result.validSmtp} for ${emailAddress} (cached for future use)`);
2663
2898
  }
2664
2899
  if (result.validSmtp === false && result.metadata) {
2665
- result.metadata.error = VerificationErrorCode.MAILBOX_NOT_FOUND;
2900
+ result.metadata.error = VerificationErrorCode.mailboxNotFound;
2666
2901
  } else if (result.validSmtp === null && result.metadata) {
2667
- result.metadata.error = VerificationErrorCode.SMTP_CONNECTION_FAILED;
2902
+ result.metadata.error = VerificationErrorCode.smtpConnectionFailed;
2668
2903
  }
2669
2904
  }
2670
- } catch (err) {
2671
- log("[verifyEmail] Failed to resolve MX records", err);
2905
+ } catch (error) {
2906
+ log("[verifyEmail] Failed to resolve MX records", error);
2672
2907
  result.validMx = false;
2673
2908
  if (result.metadata) {
2674
- result.metadata.error = VerificationErrorCode.NO_MX_RECORDS;
2909
+ result.metadata.error = VerificationErrorCode.noMxRecords;
2675
2910
  }
2676
2911
  }
2677
2912
  } else if ((verifyMx || verifySmtp) && shouldSkipMx) {
@@ -2683,5 +2918,5 @@ async function verifyEmail(params) {
2683
2918
  return result;
2684
2919
  }
2685
2920
 
2686
- export { COMMON_EMAIL_DOMAINS, DEFAULT_CACHE_OPTIONS, LRUAdapter, RedisAdapter, SMTPStep, VerificationErrorCode, cleanNameForAlgrothin, clearDefaultCache, defaultDomainSuggestionMethod, defaultNameDetectionMethod, detectName, detectNameForAlgrothin, detectNameFromEmail, domainPorts, getCacheStore, getDefaultCache, getDomainAge, getDomainRegistrationStatus, getDomainSimilarity, isCommonDomain, isDisposableEmail, isFreeEmail, isValidEmail, isValidEmailDomain, resetDefaultCache, suggestDomain, suggestEmailDomain, verifyEmail, verifyEmailBatch };
2921
+ export { DEFAULT_CACHE_OPTIONS, EmailProvider, LRUAdapter, RedisAdapter, SMTPStep, VerificationErrorCode, cleanNameForAlgorithm, clearDefaultCache, commonEmailDomains, defaultDomainSuggestionMethod, defaultNameDetectionMethod, detectName, detectNameForAlgorithm, detectNameFromEmail, domainPorts, getCacheStore, getDefaultCache, getDomainAge, getDomainRegistrationStatus, getDomainSimilarity, isCommonDomain, isDisposableEmail, isFreeEmail, isValidEmail, isValidEmailDomain, parseSmtpError, resetDefaultCache, suggestDomain, suggestEmailDomain, verifyEmail, verifyEmailBatch };
2687
2922
  //# sourceMappingURL=index.esm.js.map