@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.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) {
@@ -1188,9 +1354,38 @@ async function verifyMailboxSMTP(params) {
1188
1354
  const { ports = DEFAULT_PORTS, timeout = DEFAULT_TIMEOUT, maxRetries = DEFAULT_MAX_RETRIES, tls: tlsConfig = true, hostname = "localhost", useVRFY = true, cache, debug = false, sequence } = options;
1189
1355
  const log = debug ? (...args) => console.log("[SMTP]", ...args) : () => {
1190
1356
  };
1357
+ const createSmtpResult = (result, port, tlsUsed, mxHost2) => {
1358
+ const reason = result === true ? "valid" : result === null ? "ambiguous" : "not_found";
1359
+ const parsedError = parseSmtpError(reason);
1360
+ return {
1361
+ canConnectSmtp: result !== null,
1362
+ hasFullInbox: parsedError.hasFullInbox,
1363
+ isCatchAll: parsedError.isCatchAll,
1364
+ isDeliverable: result === true,
1365
+ isDisabled: result === false && parsedError.isDisabled,
1366
+ error: result === null ? reason : result === false ? reason : void 0,
1367
+ providerUsed: EmailProvider.everythingElse,
1368
+ checkedAt: Date.now()
1369
+ };
1370
+ };
1371
+ const createFailureResult = (error) => ({
1372
+ canConnectSmtp: false,
1373
+ hasFullInbox: false,
1374
+ isCatchAll: false,
1375
+ isDeliverable: false,
1376
+ isDisabled: false,
1377
+ error,
1378
+ providerUsed: EmailProvider.everythingElse,
1379
+ checkedAt: Date.now()
1380
+ });
1191
1381
  if (!mxRecords || mxRecords.length === 0) {
1192
1382
  log("No MX records found");
1193
- return { result: false, cached: false, port: 0, portCached: false };
1383
+ return {
1384
+ smtpResult: createFailureResult("No MX records found"),
1385
+ cached: false,
1386
+ port: 0,
1387
+ portCached: false
1388
+ };
1194
1389
  }
1195
1390
  const mxHost = mxRecords[0];
1196
1391
  log(`Verifying ${local}@${domain} via ${mxHost}`);
@@ -1199,16 +1394,16 @@ async function verifyMailboxSMTP(params) {
1199
1394
  let cachedResult;
1200
1395
  try {
1201
1396
  cachedResult = await smtpCacheStore.get(`${mxHost}:${local}@${domain}`);
1202
- if (cachedResult !== void 0) {
1203
- log(`Using cached SMTP result: ${cachedResult}`);
1397
+ if (cachedResult !== void 0 && cachedResult !== null) {
1398
+ log(`Using cached SMTP result: ${cachedResult.isDeliverable}`);
1204
1399
  return {
1205
- result: typeof cachedResult === "boolean" ? cachedResult : null,
1400
+ smtpResult: cachedResult,
1206
1401
  cached: true,
1207
1402
  port: 0,
1208
1403
  portCached: false
1209
1404
  };
1210
1405
  }
1211
- } catch (_error) {
1406
+ } catch (ignoredError) {
1212
1407
  cachedResult = void 0;
1213
1408
  }
1214
1409
  }
@@ -1217,7 +1412,7 @@ async function verifyMailboxSMTP(params) {
1217
1412
  let cachedPort;
1218
1413
  try {
1219
1414
  cachedPort = await smtpPortCacheStore.get(mxHost);
1220
- } catch (_error) {
1415
+ } catch (ignoredError) {
1221
1416
  cachedPort = null;
1222
1417
  }
1223
1418
  if (cachedPort) {
@@ -1234,21 +1429,22 @@ async function verifyMailboxSMTP(params) {
1234
1429
  sequence,
1235
1430
  log
1236
1431
  });
1237
- if (smtpCacheStore && result !== void 0) {
1432
+ const smtpResult = createSmtpResult(result);
1433
+ if (smtpCacheStore) {
1238
1434
  try {
1239
- await smtpCacheStore.set(`${mxHost}:${local}@${domain}`, result);
1435
+ await smtpCacheStore.set(`${mxHost}:${local}@${domain}`, smtpResult);
1240
1436
  log(`Cached SMTP result ${result} for ${local}@${domain} via ${mxHost}`);
1241
- } catch (_error) {
1437
+ } catch (ignoredError) {
1242
1438
  }
1243
1439
  }
1244
- return { result, cached: false, port: cachedPort, portCached: true };
1440
+ return { smtpResult, cached: false, port: cachedPort, portCached: true };
1245
1441
  }
1246
1442
  }
1247
1443
  for (const port of ports) {
1248
1444
  log(`Testing port ${port}`);
1249
1445
  for (let attempt = 0; attempt < maxRetries; attempt++) {
1250
1446
  if (attempt > 0) {
1251
- const delay = Math.min(1e3 * 2 ** (attempt - 1), 5e3);
1447
+ const delay = Math.min(200 * 2 ** (attempt - 1), 800);
1252
1448
  log(`Retry ${attempt + 1}, waiting ${delay}ms`);
1253
1449
  await new Promise((resolve) => setTimeout(resolve, delay));
1254
1450
  }
@@ -1264,11 +1460,12 @@ async function verifyMailboxSMTP(params) {
1264
1460
  sequence,
1265
1461
  log
1266
1462
  });
1267
- if (smtpCacheStore && result !== void 0) {
1463
+ const smtpResult = createSmtpResult(result);
1464
+ if (smtpCacheStore) {
1268
1465
  try {
1269
- await smtpCacheStore.set(`${mxHost}:${local}@${domain}`, result);
1466
+ await smtpCacheStore.set(`${mxHost}:${local}@${domain}`, smtpResult);
1270
1467
  log(`Cached SMTP result ${result} for ${local}@${domain} via ${mxHost}`);
1271
- } catch (_error) {
1468
+ } catch (ignoredError) {
1272
1469
  }
1273
1470
  }
1274
1471
  if (result !== null) {
@@ -1276,15 +1473,20 @@ async function verifyMailboxSMTP(params) {
1276
1473
  try {
1277
1474
  await smtpPortCacheStore.set(mxHost, port);
1278
1475
  log(`Cached port ${port} for ${mxHost}`);
1279
- } catch (_error) {
1476
+ } catch (ignoredError) {
1280
1477
  }
1281
1478
  }
1282
- return { result, cached: false, port, portCached: false };
1479
+ return { smtpResult, cached: false, port, portCached: false };
1283
1480
  }
1284
1481
  }
1285
1482
  }
1286
1483
  log("All ports failed");
1287
- return { result: null, cached: false, port: 0, portCached: false };
1484
+ return {
1485
+ smtpResult: createFailureResult("All SMTP connection attempts failed"),
1486
+ cached: false,
1487
+ port: 0,
1488
+ portCached: false
1489
+ };
1288
1490
  }
1289
1491
  async function testSMTPConnection(params) {
1290
1492
  const { mxHost, port, local, domain, timeout, tlsConfig, hostname, useVRFY, sequence, log } = params;
@@ -1292,11 +1494,11 @@ async function testSMTPConnection(params) {
1292
1494
  const useTLS = tlsConfig !== false && (portConfig.tls || portConfig.starttls);
1293
1495
  const implicitTLS = portConfig.tls;
1294
1496
  const defaultSequence = {
1295
- steps: [SMTPStep.GREETING, SMTPStep.EHLO, SMTPStep.MAIL_FROM, SMTPStep.RCPT_TO]
1497
+ steps: [SMTPStep.greeting, SMTPStep.ehlo, SMTPStep.mailFrom, SMTPStep.rcptTo]
1296
1498
  };
1297
1499
  const activeSequence = sequence || defaultSequence;
1298
1500
  if (port === 25) {
1299
- activeSequence.steps = activeSequence.steps.map((step) => step === SMTPStep.EHLO ? SMTPStep.HELO : step);
1501
+ activeSequence.steps = activeSequence.steps.map((step) => step === SMTPStep.ehlo ? SMTPStep.helo : step);
1300
1502
  }
1301
1503
  const tlsOptions = {
1302
1504
  host: mxHost,
@@ -1314,7 +1516,7 @@ async function testSMTPConnection(params) {
1314
1516
  let resolved = false;
1315
1517
  let supportsSTARTTLS = false;
1316
1518
  let supportsVRFY = false;
1317
- const cleanup = () => {
1519
+ let cleanup = () => {
1318
1520
  if (resolved)
1319
1521
  return;
1320
1522
  resolved = true;
@@ -1350,31 +1552,31 @@ async function testSMTPConnection(params) {
1350
1552
  if (resolved)
1351
1553
  return;
1352
1554
  switch (step) {
1353
- case SMTPStep.EHLO:
1555
+ case SMTPStep.ehlo:
1354
1556
  sendCommand(`EHLO ${hostname}`);
1355
1557
  break;
1356
- case SMTPStep.HELO:
1558
+ case SMTPStep.helo:
1357
1559
  sendCommand(`HELO ${domain}`);
1358
1560
  break;
1359
- case SMTPStep.GREETING:
1561
+ case SMTPStep.greeting:
1360
1562
  break;
1361
- case SMTPStep.STARTTLS:
1563
+ case SMTPStep.startTls:
1362
1564
  sendCommand("STARTTLS");
1363
1565
  break;
1364
- case SMTPStep.MAIL_FROM: {
1566
+ case SMTPStep.mailFrom: {
1365
1567
  const from = activeSequence.from || "<>";
1366
1568
  sendCommand(`MAIL FROM:${from}`);
1367
1569
  break;
1368
1570
  }
1369
- case SMTPStep.RCPT_TO:
1571
+ case SMTPStep.rcptTo:
1370
1572
  sendCommand(`RCPT TO:<${local}@${domain}>`);
1371
1573
  break;
1372
- case SMTPStep.VRFY: {
1574
+ case SMTPStep.vrfy: {
1373
1575
  const vrfyTarget = activeSequence.vrfyTarget || local;
1374
1576
  sendCommand(`VRFY ${vrfyTarget}`);
1375
1577
  break;
1376
1578
  }
1377
- case SMTPStep.QUIT:
1579
+ case SMTPStep.quit:
1378
1580
  sendCommand("QUIT");
1379
1581
  break;
1380
1582
  }
@@ -1398,14 +1600,14 @@ async function testSMTPConnection(params) {
1398
1600
  }
1399
1601
  if (isMultiline) {
1400
1602
  const currentStep2 = activeSequence.steps[currentStepIndex];
1401
- if (currentStep2 === SMTPStep.EHLO && code === "250") {
1603
+ if (currentStep2 === SMTPStep.ehlo && code === "250") {
1402
1604
  const upper = response.toUpperCase();
1403
1605
  if (upper.includes("STARTTLS"))
1404
1606
  supportsSTARTTLS = true;
1405
1607
  if (upper.includes("VRFY"))
1406
1608
  supportsVRFY = true;
1407
1609
  }
1408
- if (currentStep2 === SMTPStep.HELO && code === "250") {
1610
+ if (currentStep2 === SMTPStep.helo && code === "250") {
1409
1611
  const upper = response.toUpperCase();
1410
1612
  if (upper.includes("VRFY"))
1411
1613
  supportsVRFY = true;
@@ -1418,19 +1620,19 @@ async function testSMTPConnection(params) {
1418
1620
  }
1419
1621
  const currentStep = activeSequence.steps[currentStepIndex];
1420
1622
  switch (currentStep) {
1421
- case SMTPStep.GREETING:
1623
+ case SMTPStep.greeting:
1422
1624
  if (code.startsWith("220")) {
1423
1625
  nextStep();
1424
1626
  } else {
1425
1627
  finish(null, "no_greeting");
1426
1628
  }
1427
1629
  break;
1428
- case SMTPStep.EHLO:
1630
+ case SMTPStep.ehlo:
1429
1631
  if (code.startsWith("250")) {
1430
- const hasSTARTTLS = activeSequence.steps.includes(SMTPStep.STARTTLS);
1632
+ const hasSTARTTLS = activeSequence.steps.includes(SMTPStep.startTls);
1431
1633
  if (!isTLS && useTLS && supportsSTARTTLS && !implicitTLS && hasSTARTTLS) {
1432
- currentStepIndex = activeSequence.steps.indexOf(SMTPStep.STARTTLS);
1433
- executeStep(SMTPStep.STARTTLS);
1634
+ currentStepIndex = activeSequence.steps.indexOf(SMTPStep.startTls);
1635
+ executeStep(SMTPStep.startTls);
1434
1636
  } else {
1435
1637
  nextStep();
1436
1638
  }
@@ -1438,14 +1640,14 @@ async function testSMTPConnection(params) {
1438
1640
  finish(null, "ehlo_failed");
1439
1641
  }
1440
1642
  break;
1441
- case SMTPStep.HELO:
1643
+ case SMTPStep.helo:
1442
1644
  if (code.startsWith("250")) {
1443
1645
  nextStep();
1444
1646
  } else {
1445
1647
  finish(null, "helo_failed");
1446
1648
  }
1447
1649
  break;
1448
- case SMTPStep.STARTTLS:
1650
+ case SMTPStep.startTls:
1449
1651
  if (code.startsWith("220")) {
1450
1652
  const plainSocket = socket;
1451
1653
  socket = tls.connect({
@@ -1456,7 +1658,7 @@ async function testSMTPConnection(params) {
1456
1658
  isTLS = true;
1457
1659
  log("TLS upgraded");
1458
1660
  buffer = "";
1459
- const starttlsIndex = activeSequence.steps.indexOf(SMTPStep.STARTTLS);
1661
+ const starttlsIndex = activeSequence.steps.indexOf(SMTPStep.startTls);
1460
1662
  currentStepIndex = starttlsIndex;
1461
1663
  nextStep();
1462
1664
  });
@@ -1466,28 +1668,28 @@ async function testSMTPConnection(params) {
1466
1668
  nextStep();
1467
1669
  }
1468
1670
  break;
1469
- case SMTPStep.MAIL_FROM:
1671
+ case SMTPStep.mailFrom:
1470
1672
  if (code.startsWith("250")) {
1471
1673
  nextStep();
1472
1674
  } else {
1473
1675
  finish(null, "mail_from_rejected");
1474
1676
  }
1475
1677
  break;
1476
- case SMTPStep.RCPT_TO:
1678
+ case SMTPStep.rcptTo:
1477
1679
  if (code.startsWith("250") || code.startsWith("251")) {
1478
1680
  finish(true, "valid");
1479
1681
  } else if (code.startsWith("552") || code.startsWith("452")) {
1480
1682
  finish(false, "over_quota");
1481
1683
  } else if (code.startsWith("4")) {
1482
1684
  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);
1685
+ } else if (useVRFY && supportsVRFY && code.startsWith("5") && activeSequence.steps.includes(SMTPStep.vrfy)) {
1686
+ currentStepIndex = activeSequence.steps.indexOf(SMTPStep.vrfy);
1687
+ executeStep(SMTPStep.vrfy);
1486
1688
  } else {
1487
1689
  finish(null, "ambiguous");
1488
1690
  }
1489
1691
  break;
1490
- case SMTPStep.VRFY:
1692
+ case SMTPStep.vrfy:
1491
1693
  if (code.startsWith("250") || code.startsWith("252")) {
1492
1694
  finish(true, "vrfy_valid");
1493
1695
  } else if (code.startsWith("550")) {
@@ -1496,14 +1698,14 @@ async function testSMTPConnection(params) {
1496
1698
  finish(null, "vrfy_failed");
1497
1699
  }
1498
1700
  break;
1499
- case SMTPStep.QUIT:
1701
+ case SMTPStep.quit:
1500
1702
  if (code.startsWith("221")) {
1501
1703
  finish(null, "quit_received");
1502
1704
  }
1503
1705
  break;
1504
1706
  }
1505
1707
  };
1506
- const handleData = (data) => {
1708
+ let handleData = (data) => {
1507
1709
  if (resolved)
1508
1710
  return;
1509
1711
  buffer += data.toString();
@@ -1539,65 +1741,69 @@ async function testSMTPConnection(params) {
1539
1741
  return;
1540
1742
  }
1541
1743
  const firstStep = activeSequence.steps[0];
1542
- if (firstStep !== SMTPStep.GREETING) {
1744
+ let connectionTimeout;
1745
+ let stepTimeout;
1746
+ const resetActivityTimeout = () => {
1747
+ if (stepTimeout) {
1748
+ clearTimeout(stepTimeout);
1749
+ }
1750
+ stepTimeout = setTimeout(() => {
1751
+ if (!resolved) {
1752
+ log(`Step timeout after ${timeout}ms of inactivity`);
1753
+ finish(null, "step_timeout");
1754
+ }
1755
+ }, timeout);
1756
+ };
1757
+ connectionTimeout = setTimeout(() => {
1758
+ if (!resolved) {
1759
+ log(`Connection timeout after ${timeout}ms`);
1760
+ finish(null, "connection_timeout");
1761
+ }
1762
+ }, timeout);
1763
+ if (firstStep !== SMTPStep.greeting) {
1543
1764
  executeStep(firstStep);
1544
1765
  }
1545
- socket.setTimeout(timeout, () => finish(null, "timeout"));
1546
- socket.on("error", () => finish(null, "connection_error"));
1547
- socket.on("close", () => {
1766
+ socket.setTimeout(timeout, () => {
1767
+ if (!resolved) {
1768
+ log(`Socket timeout after ${timeout}ms`);
1769
+ finish(null, "socket_timeout");
1770
+ }
1771
+ });
1772
+ socket.on("error", (error) => {
1773
+ log(`Socket error: ${error.message}`);
1548
1774
  if (!resolved)
1775
+ finish(null, "connection_error");
1776
+ });
1777
+ socket.on("close", () => {
1778
+ if (!resolved) {
1779
+ log("Socket closed unexpectedly");
1549
1780
  finish(null, "connection_closed");
1781
+ }
1550
1782
  });
1783
+ const originalHandleData = handleData;
1784
+ handleData = (data) => {
1785
+ resetActivityTimeout();
1786
+ originalHandleData(data);
1787
+ };
1788
+ const enhancedCleanup = () => {
1789
+ if (resolved)
1790
+ return;
1791
+ resolved = true;
1792
+ if (connectionTimeout)
1793
+ clearTimeout(connectionTimeout);
1794
+ if (stepTimeout)
1795
+ clearTimeout(stepTimeout);
1796
+ socket.setTimeout(0);
1797
+ try {
1798
+ socket === null || socket === void 0 ? void 0 : socket.write("QUIT\r\n");
1799
+ } catch {
1800
+ }
1801
+ setTimeout(() => socket === null || socket === void 0 ? void 0 : socket.destroy(), 100);
1802
+ };
1803
+ cleanup = enhancedCleanup;
1551
1804
  });
1552
1805
  }
1553
1806
 
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
1807
  const defaultRegex = {
1602
1808
  domainName: "Domain Name: *([^\\s]+)",
1603
1809
  registrar: "Registrar: *(.+)",
@@ -2015,7 +2221,7 @@ function parseWhoisData({ rawData, domain }) {
2015
2221
  return result;
2016
2222
  }
2017
2223
 
2018
- const WHOIS_SERVERS = {
2224
+ const whoisServers = {
2019
2225
  com: "whois.verisign-grs.com",
2020
2226
  net: "whois.verisign-grs.com",
2021
2227
  org: "whois.pir.org",
@@ -2115,7 +2321,7 @@ async function getWhoisData(domain, timeout = 5e3, debug = false, cache) {
2115
2321
  throw new Error("Invalid domain");
2116
2322
  }
2117
2323
  log(`[whois] extracted TLD: ${tld} for domain: ${domain}`);
2118
- const whoisServer = WHOIS_SERVERS[tld];
2324
+ const whoisServer = whoisServers[tld];
2119
2325
  if (!whoisServer) {
2120
2326
  log(`[whois] no specific server for TLD ${tld}, trying IANA`);
2121
2327
  const defaultServer = "whois.iana.org";
@@ -2141,8 +2347,8 @@ async function getWhoisData(domain, timeout = 5e3, debug = false, cache) {
2141
2347
  await cacheStore.set(cacheKey, whoisData);
2142
2348
  log(`[whois] successfully retrieved and cached WHOIS data for ${domain}`);
2143
2349
  return whoisData;
2144
- } catch (_error) {
2145
- log(`[whois] failed to get WHOIS data for ${domain}: ${_error instanceof Error ? _error.message : "Unknown error"}`);
2350
+ } catch (ignoredError) {
2351
+ log(`[whois] failed to get WHOIS data for ${domain}: ${ignoredError instanceof Error ? ignoredError.message : "Unknown error"}`);
2146
2352
  return null;
2147
2353
  }
2148
2354
  }
@@ -2179,8 +2385,8 @@ async function getDomainAge(domain, timeout = 5e3, debug = false, cache) {
2179
2385
  expirationDate: whoisData.expirationDate ? new Date(whoisData.expirationDate) : null,
2180
2386
  updatedDate: whoisData.updatedDate ? new Date(whoisData.updatedDate) : null
2181
2387
  };
2182
- } catch (_error) {
2183
- log(`[whois] error getting domain age for ${domain}: ${_error instanceof Error ? _error.message : "Unknown error"}`);
2388
+ } catch (ignoredError) {
2389
+ log(`[whois] error getting domain age for ${domain}: ${ignoredError instanceof Error ? ignoredError.message : "Unknown error"}`);
2184
2390
  return null;
2185
2391
  }
2186
2392
  }
@@ -2251,8 +2457,8 @@ async function getDomainRegistrationStatus(domain, timeout = 5e3, debug = false,
2251
2457
  isPendingDelete,
2252
2458
  isLocked
2253
2459
  };
2254
- } catch (_error) {
2255
- log(`[whois] error getting domain registration status for ${domain}: ${_error instanceof Error ? _error.message : "Unknown error"}`);
2460
+ } catch (ignoredError) {
2461
+ log(`[whois] error getting domain registration status for ${domain}: ${ignoredError instanceof Error ? ignoredError.message : "Unknown error"}`);
2256
2462
  return null;
2257
2463
  }
2258
2464
  }
@@ -2428,7 +2634,7 @@ function createErrorResult(email, _error) {
2428
2634
  metadata: {
2429
2635
  verificationTime: 0,
2430
2636
  cached: false,
2431
- error: VerificationErrorCode.SMTP_CONNECTION_FAILED
2637
+ error: VerificationErrorCode.smtpConnectionFailed
2432
2638
  }
2433
2639
  };
2434
2640
  }
@@ -2448,25 +2654,31 @@ async function isDisposableEmail(params) {
2448
2654
  let cached;
2449
2655
  try {
2450
2656
  cached = await cacheStore.get(emailDomain);
2451
- } catch (_error) {
2657
+ } catch (ignoredError) {
2452
2658
  cached = null;
2453
2659
  }
2454
2660
  if (cached !== null && cached !== void 0) {
2455
- log(`[isDisposableEmail] Cache hit for ${emailDomain}: ${cached}`);
2456
- return cached;
2661
+ log(`[isDisposableEmail] Cache hit for ${emailDomain}: ${cached.isDisposable}`);
2662
+ return cached.isDisposable;
2457
2663
  }
2458
2664
  if (!disposableEmailProviders) {
2459
2665
  disposableEmailProviders = new Set(require("./disposable-email-providers.json"));
2460
2666
  }
2461
- const result = disposableEmailProviders.has(emailDomain);
2667
+ const isDisposable = disposableEmailProviders.has(emailDomain);
2668
+ const richResult = {
2669
+ isDisposable,
2670
+ source: "disposable-email-providers.json",
2671
+ category: isDisposable ? "disposable" : void 0,
2672
+ checkedAt: Date.now()
2673
+ };
2462
2674
  try {
2463
- await cacheStore.set(emailDomain, result);
2464
- log(`[isDisposableEmail] Cached result for ${emailDomain}: ${result}`);
2465
- } catch (_error) {
2675
+ await cacheStore.set(emailDomain, richResult);
2676
+ log(`[isDisposableEmail] Cached result for ${emailDomain}: ${isDisposable}`);
2677
+ } catch (ignoredError) {
2466
2678
  log(`[isDisposableEmail] Cache write error for ${emailDomain}`);
2467
2679
  }
2468
- log(`[isDisposableEmail] Check result for ${emailDomain}: ${result}`);
2469
- return result;
2680
+ log(`[isDisposableEmail] Check result for ${emailDomain}: ${isDisposable}`);
2681
+ return isDisposable;
2470
2682
  }
2471
2683
  async function isFreeEmail(params) {
2472
2684
  const { emailOrDomain, cache, logger } = params;
@@ -2481,25 +2693,30 @@ async function isFreeEmail(params) {
2481
2693
  let cached;
2482
2694
  try {
2483
2695
  cached = await cacheStore.get(emailDomain);
2484
- } catch (_error) {
2696
+ } catch (ignoredError) {
2485
2697
  cached = null;
2486
2698
  }
2487
2699
  if (cached !== null && cached !== void 0) {
2488
- log(`[isFreeEmail] Cache hit for ${emailDomain}: ${cached}`);
2489
- return cached;
2700
+ log(`[isFreeEmail] Cache hit for ${emailDomain}: ${cached.isFree}`);
2701
+ return cached.isFree;
2490
2702
  }
2491
2703
  if (!freeEmailProviders) {
2492
2704
  freeEmailProviders = new Set(require("./free-email-providers.json"));
2493
2705
  }
2494
- const result = freeEmailProviders.has(emailDomain);
2706
+ const isFree = freeEmailProviders.has(emailDomain);
2707
+ const richResult = {
2708
+ isFree,
2709
+ provider: isFree ? emailDomain : void 0,
2710
+ checkedAt: Date.now()
2711
+ };
2495
2712
  try {
2496
- await cacheStore.set(emailDomain, result);
2497
- log(`[isFreeEmail] Cached result for ${emailDomain}: ${result}`);
2498
- } catch (_error) {
2713
+ await cacheStore.set(emailDomain, richResult);
2714
+ log(`[isFreeEmail] Cached result for ${emailDomain}: ${isFree}`);
2715
+ } catch (ignoredError) {
2499
2716
  log(`[isFreeEmail] Cache write error for ${emailDomain}`);
2500
2717
  }
2501
- log(`[isFreeEmail] Check result for ${emailDomain}: ${result}`);
2502
- return result;
2718
+ log(`[isFreeEmail] Check result for ${emailDomain}: ${isFree}`);
2719
+ return isFree;
2503
2720
  }
2504
2721
  const domainPorts = {
2505
2722
  // 465 or 587
@@ -2507,7 +2724,7 @@ const domainPorts = {
2507
2724
  "ovh.net": 465
2508
2725
  };
2509
2726
  async function verifyEmail(params) {
2510
- var _a;
2727
+ var _a, _b;
2511
2728
  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
2729
  const startTime = Date.now();
2513
2730
  const log = debug ? console.debug : (..._args) => {
@@ -2527,7 +2744,7 @@ async function verifyEmail(params) {
2527
2744
  if (!isValidEmail(emailAddress)) {
2528
2745
  if (result.metadata) {
2529
2746
  result.metadata.verificationTime = Date.now() - startTime;
2530
- result.metadata.error = VerificationErrorCode.INVALID_FORMAT;
2747
+ result.metadata.error = VerificationErrorCode.invalidFormat;
2531
2748
  }
2532
2749
  return result;
2533
2750
  }
@@ -2553,14 +2770,14 @@ async function verifyEmail(params) {
2553
2770
  if (!domain || !local) {
2554
2771
  if (result.metadata) {
2555
2772
  result.metadata.verificationTime = Date.now() - startTime;
2556
- result.metadata.error = VerificationErrorCode.INVALID_FORMAT;
2773
+ result.metadata.error = VerificationErrorCode.invalidFormat;
2557
2774
  }
2558
2775
  return result;
2559
2776
  }
2560
2777
  if (!await isValidEmailDomain(domain, params.cache)) {
2561
2778
  if (result.metadata) {
2562
2779
  result.metadata.verificationTime = Date.now() - startTime;
2563
- result.metadata.error = VerificationErrorCode.INVALID_DOMAIN;
2780
+ result.metadata.error = VerificationErrorCode.invalidDomain;
2564
2781
  }
2565
2782
  return result;
2566
2783
  }
@@ -2569,7 +2786,7 @@ async function verifyEmail(params) {
2569
2786
  result.isDisposable = await isDisposableEmail({ emailOrDomain: emailAddress, cache: params.cache, logger: log });
2570
2787
  log(`[verifyEmail] Disposable check result: ${result.isDisposable}`);
2571
2788
  if (result.isDisposable && result.metadata) {
2572
- result.metadata.error = VerificationErrorCode.DISPOSABLE_EMAIL;
2789
+ result.metadata.error = VerificationErrorCode.disposableEmail;
2573
2790
  }
2574
2791
  }
2575
2792
  if (checkFree) {
@@ -2590,8 +2807,8 @@ async function verifyEmail(params) {
2590
2807
  try {
2591
2808
  result.domainAge = await getDomainAge(domain, whoisTimeout, debug, params.cache);
2592
2809
  log(`[verifyEmail] Domain age result:`, result.domainAge ? `${result.domainAge.ageInDays} days` : "null");
2593
- } catch (err) {
2594
- log("[verifyEmail] Failed to get domain age", err);
2810
+ } catch (error) {
2811
+ log("[verifyEmail] Failed to get domain age", error);
2595
2812
  result.domainAge = null;
2596
2813
  }
2597
2814
  } else if (checkDomainAge && shouldSkipDomainWhois) {
@@ -2602,8 +2819,8 @@ async function verifyEmail(params) {
2602
2819
  try {
2603
2820
  result.domainRegistration = await getDomainRegistrationStatus(domain, whoisTimeout, debug, params.cache);
2604
2821
  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);
2822
+ } catch (error) {
2823
+ log("[verifyEmail] Failed to get domain registration status", error);
2607
2824
  result.domainRegistration = null;
2608
2825
  }
2609
2826
  } else if (checkDomainRegistration && shouldSkipDomainWhois) {
@@ -2616,14 +2833,14 @@ async function verifyEmail(params) {
2616
2833
  result.validMx = mxRecords.length > 0;
2617
2834
  log(`[verifyEmail] MX records found: ${mxRecords.length}, valid: ${result.validMx}`);
2618
2835
  if (!result.validMx && result.metadata) {
2619
- result.metadata.error = VerificationErrorCode.NO_MX_RECORDS;
2836
+ result.metadata.error = VerificationErrorCode.noMxRecords;
2620
2837
  }
2621
2838
  if (verifySmtp && mxRecords.length > 0) {
2622
2839
  const cacheKey = `${emailAddress}:smtp`;
2623
2840
  const smtpCacheInstance = getCacheStore(params.cache, "smtp");
2624
2841
  const cachedSmtp = await smtpCacheInstance.get(cacheKey);
2625
2842
  if (cachedSmtp !== null && cachedSmtp !== void 0) {
2626
- result.validSmtp = cachedSmtp;
2843
+ result.validSmtp = (_b = cachedSmtp.isDeliverable) !== null && _b !== void 0 ? _b : null;
2627
2844
  log(`[verifyEmail] SMTP result from cache: ${result.validSmtp} for ${emailAddress}`);
2628
2845
  if (result.metadata) {
2629
2846
  result.metadata.cached = true;
@@ -2643,7 +2860,7 @@ async function verifyEmail(params) {
2643
2860
  domainPort = domainPorts[mxDomain.domain];
2644
2861
  }
2645
2862
  }
2646
- const { result: smtpResult, cached, portCached, port } = await verifyMailboxSMTP({
2863
+ const { smtpResult, cached, port } = await verifyMailboxSMTP({
2647
2864
  local,
2648
2865
  domain,
2649
2866
  mxRecords,
@@ -2656,22 +2873,26 @@ async function verifyEmail(params) {
2656
2873
  }
2657
2874
  });
2658
2875
  await smtpCacheInstance.set(cacheKey, smtpResult);
2659
- result.validSmtp = smtpResult;
2876
+ if (!smtpResult.canConnectSmtp) {
2877
+ result.validSmtp = null;
2878
+ } else {
2879
+ result.validSmtp = smtpResult.isDeliverable;
2880
+ }
2660
2881
  if (result.metadata)
2661
2882
  result.metadata.cached = cached;
2662
2883
  log(`[verifyEmail] SMTP verification result: ${result.validSmtp} for ${emailAddress} (cached for future use)`);
2663
2884
  }
2664
2885
  if (result.validSmtp === false && result.metadata) {
2665
- result.metadata.error = VerificationErrorCode.MAILBOX_NOT_FOUND;
2886
+ result.metadata.error = VerificationErrorCode.mailboxNotFound;
2666
2887
  } else if (result.validSmtp === null && result.metadata) {
2667
- result.metadata.error = VerificationErrorCode.SMTP_CONNECTION_FAILED;
2888
+ result.metadata.error = VerificationErrorCode.smtpConnectionFailed;
2668
2889
  }
2669
2890
  }
2670
- } catch (err) {
2671
- log("[verifyEmail] Failed to resolve MX records", err);
2891
+ } catch (error) {
2892
+ log("[verifyEmail] Failed to resolve MX records", error);
2672
2893
  result.validMx = false;
2673
2894
  if (result.metadata) {
2674
- result.metadata.error = VerificationErrorCode.NO_MX_RECORDS;
2895
+ result.metadata.error = VerificationErrorCode.noMxRecords;
2675
2896
  }
2676
2897
  }
2677
2898
  } else if ((verifyMx || verifySmtp) && shouldSkipMx) {
@@ -2683,5 +2904,5 @@ async function verifyEmail(params) {
2683
2904
  return result;
2684
2905
  }
2685
2906
 
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 };
2907
+ 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
2908
  //# sourceMappingURL=index.esm.js.map