@emailcheck/email-validator-js 2.11.0 → 2.13.1-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +290 -25
- package/dist/adapters/lru-adapter.d.ts +19 -0
- package/dist/adapters/redis-adapter.d.ts +45 -0
- package/dist/cache-factory.d.ts +39 -0
- package/dist/cache-interface.d.ts +124 -0
- package/dist/cache.d.ts +28 -0
- package/dist/dns.d.ts +2 -1
- package/dist/domain-suggester.d.ts +6 -2
- package/dist/index.d.ts +3 -2
- package/dist/index.esm.js +216 -78
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +216 -78
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +4 -2
- package/dist/validator.d.ts +2 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -6,6 +6,68 @@ var node_dns = require('node:dns');
|
|
|
6
6
|
var stringSimilarityJs = require('string-similarity-js');
|
|
7
7
|
var net = require('node:net');
|
|
8
8
|
|
|
9
|
+
class LRUAdapter {
|
|
10
|
+
constructor(maxSize = 1e3, ttlMs = 36e5) {
|
|
11
|
+
this.lru = tinyLru.lru(maxSize, ttlMs);
|
|
12
|
+
}
|
|
13
|
+
get(key) {
|
|
14
|
+
const value = this.lru.get(key);
|
|
15
|
+
return value === void 0 ? null : value;
|
|
16
|
+
}
|
|
17
|
+
async set(key, value, ttlMs) {
|
|
18
|
+
if (ttlMs !== void 0) {
|
|
19
|
+
this.lru.set(key, value);
|
|
20
|
+
} else {
|
|
21
|
+
this.lru.set(key, value);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
async delete(key) {
|
|
25
|
+
this.lru.delete(key);
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
28
|
+
async has(key) {
|
|
29
|
+
return this.lru.has(key);
|
|
30
|
+
}
|
|
31
|
+
async clear() {
|
|
32
|
+
this.lru.clear();
|
|
33
|
+
}
|
|
34
|
+
size() {
|
|
35
|
+
return this.lru.size;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Get the underlying LRU instance for advanced operations
|
|
39
|
+
*/
|
|
40
|
+
getLRU() {
|
|
41
|
+
return this.lru;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const DEFAULT_CACHE_TTL = {
|
|
46
|
+
mx: 36e5,
|
|
47
|
+
// 1 hour
|
|
48
|
+
disposable: 864e5,
|
|
49
|
+
// 24 hours
|
|
50
|
+
free: 864e5,
|
|
51
|
+
// 24 hours
|
|
52
|
+
domainValid: 864e5,
|
|
53
|
+
// 24 hours
|
|
54
|
+
smtp: 18e5,
|
|
55
|
+
// 30 minutes
|
|
56
|
+
domainSuggestion: 864e5,
|
|
57
|
+
// 24 hours
|
|
58
|
+
whois: 36e5
|
|
59
|
+
// 1 hour
|
|
60
|
+
};
|
|
61
|
+
const DEFAULT_CACHE_SIZE = {
|
|
62
|
+
mx: 500,
|
|
63
|
+
disposable: 1e3,
|
|
64
|
+
free: 1e3,
|
|
65
|
+
domainValid: 1e3,
|
|
66
|
+
smtp: 500,
|
|
67
|
+
domainSuggestion: 1e3,
|
|
68
|
+
whois: 200
|
|
69
|
+
};
|
|
70
|
+
|
|
9
71
|
const mxCache = tinyLru.lru(500, 36e5);
|
|
10
72
|
const disposableCache = tinyLru.lru(1e3, 864e5);
|
|
11
73
|
const freeCache = tinyLru.lru(1e3, 864e5);
|
|
@@ -13,6 +75,19 @@ const domainValidCache = tinyLru.lru(1e3, 864e5);
|
|
|
13
75
|
const smtpCache = tinyLru.lru(500, 18e5);
|
|
14
76
|
const domainSuggestionCache = tinyLru.lru(1e3, 864e5);
|
|
15
77
|
const whoisCache = tinyLru.lru(200, 36e5);
|
|
78
|
+
function getCacheStore(defaultLru, cacheType, passedCache) {
|
|
79
|
+
if (passedCache && passedCache[cacheType]) {
|
|
80
|
+
return passedCache[cacheType];
|
|
81
|
+
}
|
|
82
|
+
return new LRUAdapter(DEFAULT_CACHE_SIZE[cacheType], DEFAULT_CACHE_TTL[cacheType]);
|
|
83
|
+
}
|
|
84
|
+
const mxCacheStore = (passedCache) => getCacheStore(mxCache, "mx", passedCache);
|
|
85
|
+
const disposableCacheStore = (passedCache) => getCacheStore(disposableCache, "disposable", passedCache);
|
|
86
|
+
const freeCacheStore = (passedCache) => getCacheStore(freeCache, "free", passedCache);
|
|
87
|
+
const domainValidCacheStore = (passedCache) => getCacheStore(domainValidCache, "domainValid", passedCache);
|
|
88
|
+
const smtpCacheStore = (passedCache) => getCacheStore(smtpCache, "smtp", passedCache);
|
|
89
|
+
const domainSuggestionCacheStore = (passedCache) => getCacheStore(domainSuggestionCache, "domainSuggestion", passedCache);
|
|
90
|
+
const whoisCacheStore = (passedCache) => getCacheStore(whoisCache, "whois", passedCache);
|
|
16
91
|
function clearAllCaches() {
|
|
17
92
|
mxCache.clear();
|
|
18
93
|
disposableCache.clear();
|
|
@@ -23,9 +98,10 @@ function clearAllCaches() {
|
|
|
23
98
|
whoisCache.clear();
|
|
24
99
|
}
|
|
25
100
|
|
|
26
|
-
async function resolveMxRecords(domain) {
|
|
27
|
-
const
|
|
28
|
-
|
|
101
|
+
async function resolveMxRecords(domain, cache) {
|
|
102
|
+
const cacheStore = mxCacheStore(cache);
|
|
103
|
+
const cached = await cacheStore.get(domain);
|
|
104
|
+
if (cached !== null && cached !== void 0) {
|
|
29
105
|
return cached;
|
|
30
106
|
}
|
|
31
107
|
try {
|
|
@@ -40,10 +116,10 @@ async function resolveMxRecords(domain) {
|
|
|
40
116
|
return 0;
|
|
41
117
|
});
|
|
42
118
|
const exchanges = records.map((record) => record.exchange);
|
|
43
|
-
|
|
119
|
+
await cacheStore.set(domain, exchanges);
|
|
44
120
|
return exchanges;
|
|
45
121
|
} catch (error) {
|
|
46
|
-
|
|
122
|
+
await cacheStore.set(domain, []);
|
|
47
123
|
throw error;
|
|
48
124
|
}
|
|
49
125
|
}
|
|
@@ -133,18 +209,73 @@ function getSimilarityThreshold(domain) {
|
|
|
133
209
|
return 0.75;
|
|
134
210
|
}
|
|
135
211
|
function defaultDomainSuggestionMethod(domain, commonDomains) {
|
|
212
|
+
const domainsToCheck = commonDomains || COMMON_EMAIL_DOMAINS;
|
|
213
|
+
const lowerDomain = domain.toLowerCase();
|
|
214
|
+
if (domainsToCheck.includes(lowerDomain)) {
|
|
215
|
+
return null;
|
|
216
|
+
}
|
|
217
|
+
for (const [correctDomain, typos] of Object.entries(TYPO_PATTERNS)) {
|
|
218
|
+
if (typos.includes(lowerDomain)) {
|
|
219
|
+
return {
|
|
220
|
+
original: domain,
|
|
221
|
+
suggested: correctDomain,
|
|
222
|
+
confidence: 0.95
|
|
223
|
+
// High confidence for known typo patterns
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
let bestMatch = null;
|
|
228
|
+
const threshold = getSimilarityThreshold(lowerDomain);
|
|
229
|
+
for (const commonDomain of domainsToCheck) {
|
|
230
|
+
const similarity = stringSimilarityJs.stringSimilarity(lowerDomain, commonDomain.toLowerCase());
|
|
231
|
+
if (similarity >= threshold) {
|
|
232
|
+
if (!bestMatch || similarity > bestMatch.similarity) {
|
|
233
|
+
bestMatch = { domain: commonDomain, similarity };
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
if (!bestMatch) {
|
|
238
|
+
for (const commonDomain of domainsToCheck) {
|
|
239
|
+
if (Math.abs(lowerDomain.length - commonDomain.length) <= 2) {
|
|
240
|
+
const similarity = stringSimilarityJs.stringSimilarity(lowerDomain, commonDomain.toLowerCase());
|
|
241
|
+
if (similarity >= 0.7) {
|
|
242
|
+
if (!bestMatch || similarity > bestMatch.similarity) {
|
|
243
|
+
bestMatch = { domain: commonDomain, similarity };
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
if (bestMatch) {
|
|
250
|
+
if (bestMatch.domain.charAt(0) !== lowerDomain.charAt(0) && bestMatch.similarity < 0.9) {
|
|
251
|
+
return null;
|
|
252
|
+
}
|
|
253
|
+
return {
|
|
254
|
+
original: domain,
|
|
255
|
+
suggested: bestMatch.domain,
|
|
256
|
+
confidence: bestMatch.similarity
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
return null;
|
|
260
|
+
}
|
|
261
|
+
async function defaultDomainSuggestionMethodAsync(domain, commonDomains) {
|
|
262
|
+
return defaultDomainSuggestionMethodImpl(domain, commonDomains);
|
|
263
|
+
}
|
|
264
|
+
async function defaultDomainSuggestionMethodImpl(domain, commonDomains) {
|
|
136
265
|
if (!domain || domain.length < 3) {
|
|
137
266
|
return null;
|
|
138
267
|
}
|
|
139
268
|
const domainsToCheck = commonDomains || COMMON_EMAIL_DOMAINS;
|
|
140
269
|
const lowerDomain = domain.toLowerCase();
|
|
141
270
|
const cacheKey = `${lowerDomain}:${domainsToCheck.length}`;
|
|
142
|
-
const
|
|
143
|
-
|
|
144
|
-
|
|
271
|
+
const cache = domainSuggestionCacheStore();
|
|
272
|
+
const cached = cache.get(cacheKey);
|
|
273
|
+
const resolved = cached && typeof cached === "object" && "then" in cached ? await cached : cached;
|
|
274
|
+
if (resolved !== null && resolved !== void 0) {
|
|
275
|
+
return resolved ? { original: domain, suggested: resolved.suggested, confidence: resolved.confidence } : null;
|
|
145
276
|
}
|
|
146
277
|
if (domainsToCheck.includes(lowerDomain)) {
|
|
147
|
-
|
|
278
|
+
await cache.set(cacheKey, null);
|
|
148
279
|
return null;
|
|
149
280
|
}
|
|
150
281
|
for (const [correctDomain, typos] of Object.entries(TYPO_PATTERNS)) {
|
|
@@ -155,7 +286,7 @@ function defaultDomainSuggestionMethod(domain, commonDomains) {
|
|
|
155
286
|
confidence: 0.95
|
|
156
287
|
// High confidence for known typo patterns
|
|
157
288
|
};
|
|
158
|
-
|
|
289
|
+
await cache.set(cacheKey, { suggested: result.suggested, confidence: result.confidence });
|
|
159
290
|
return result;
|
|
160
291
|
}
|
|
161
292
|
}
|
|
@@ -183,7 +314,7 @@ function defaultDomainSuggestionMethod(domain, commonDomains) {
|
|
|
183
314
|
}
|
|
184
315
|
if (bestMatch) {
|
|
185
316
|
if (bestMatch.domain.charAt(0) !== lowerDomain.charAt(0) && bestMatch.similarity < 0.9) {
|
|
186
|
-
|
|
317
|
+
await cache.set(cacheKey, null);
|
|
187
318
|
return null;
|
|
188
319
|
}
|
|
189
320
|
const result = {
|
|
@@ -191,10 +322,10 @@ function defaultDomainSuggestionMethod(domain, commonDomains) {
|
|
|
191
322
|
suggested: bestMatch.domain,
|
|
192
323
|
confidence: bestMatch.similarity
|
|
193
324
|
};
|
|
194
|
-
|
|
325
|
+
await cache.set(cacheKey, { suggested: result.suggested, confidence: result.confidence });
|
|
195
326
|
return result;
|
|
196
327
|
}
|
|
197
|
-
|
|
328
|
+
await cache.set(cacheKey, null);
|
|
198
329
|
return null;
|
|
199
330
|
}
|
|
200
331
|
function suggestDomain(params) {
|
|
@@ -211,7 +342,7 @@ function suggestDomain(params) {
|
|
|
211
342
|
}
|
|
212
343
|
return defaultDomainSuggestionMethod(domain, commonDomains);
|
|
213
344
|
}
|
|
214
|
-
function suggestEmailDomain(email, commonDomains) {
|
|
345
|
+
async function suggestEmailDomain(email, commonDomains) {
|
|
215
346
|
if (!email || !email.includes("@")) {
|
|
216
347
|
return null;
|
|
217
348
|
}
|
|
@@ -219,7 +350,7 @@ function suggestEmailDomain(email, commonDomains) {
|
|
|
219
350
|
if (!domain || !localPart) {
|
|
220
351
|
return null;
|
|
221
352
|
}
|
|
222
|
-
const suggestion =
|
|
353
|
+
const suggestion = await defaultDomainSuggestionMethodAsync(domain, commonDomains);
|
|
223
354
|
if (suggestion) {
|
|
224
355
|
return {
|
|
225
356
|
original: email,
|
|
@@ -790,7 +921,11 @@ function defaultNameDetectionMethod(email) {
|
|
|
790
921
|
const lastNameScore = getLastNameScore(lastParsed.cleaned);
|
|
791
922
|
const reverseScore = getLastNameScore(firstParsed.cleaned) + getFirstNameScore(lastParsed.cleaned);
|
|
792
923
|
const normalScore = firstNameScore + lastNameScore;
|
|
793
|
-
const
|
|
924
|
+
const firstLikely = isLikelyName(first, true, true);
|
|
925
|
+
const lastLikely = isLikelyName(last, true, true);
|
|
926
|
+
const oneIsSingleLetter = first.length === 1 || last.length === 1;
|
|
927
|
+
const otherIsLongEnough = oneIsSingleLetter ? first.length === 1 ? last.length >= 2 : first.length >= 2 : true;
|
|
928
|
+
const bothPartsValid = firstLikely && lastLikely && otherIsLongEnough;
|
|
794
929
|
if (bothPartsValid) {
|
|
795
930
|
const useReversed = reverseScore > normalScore * 1.2;
|
|
796
931
|
if (firstParsed.hasNumbers || lastParsed.hasNumbers) {
|
|
@@ -836,7 +971,7 @@ function defaultNameDetectionMethod(email) {
|
|
|
836
971
|
const lastParsed = parseCompositeNamePart(last);
|
|
837
972
|
const isLastSuffix = COMMON_NAME_SUFFIXES.includes(last.toLowerCase()) || CONTEXTUAL_SUFFIXES.includes(last.toLowerCase()) || isYearLike(last);
|
|
838
973
|
if (isLastSuffix) {
|
|
839
|
-
if (isLikelyName(first, true) && isLikelyName(middle, true)) {
|
|
974
|
+
if (isLikelyName(first, true, true) && isLikelyName(middle, true, true)) {
|
|
840
975
|
const cleanedFirst = firstParsed.hasNumbers ? firstParsed.cleaned : first;
|
|
841
976
|
const cleanedMiddle = middleParsed.hasNumbers ? middleParsed.cleaned : middle;
|
|
842
977
|
if (isLikelyName(cleanedFirst, false, true) && isLikelyName(cleanedMiddle, false, true)) {
|
|
@@ -850,7 +985,7 @@ function defaultNameDetectionMethod(email) {
|
|
|
850
985
|
}
|
|
851
986
|
break;
|
|
852
987
|
}
|
|
853
|
-
} else if (isLikelyName(first, true) && isLikelyName(last, true)) {
|
|
988
|
+
} else if (isLikelyName(first, true, true) && isLikelyName(last, true, true)) {
|
|
854
989
|
const cleanedFirst = firstParsed.hasNumbers ? firstParsed.cleaned : first;
|
|
855
990
|
const cleanedLast = lastParsed.hasNumbers ? lastParsed.cleaned : last;
|
|
856
991
|
if (isLikelyName(cleanedFirst, false, true) && isLikelyName(cleanedLast, false, true)) {
|
|
@@ -870,7 +1005,7 @@ function defaultNameDetectionMethod(email) {
|
|
|
870
1005
|
const isLastPartSuffix = COMMON_NAME_SUFFIXES.includes(lastPartLower) || CONTEXTUAL_SUFFIXES.includes(lastPartLower) || isYearLike(parts[parts.length - 1]);
|
|
871
1006
|
const effectiveLastIndex = isLastPartSuffix ? parts.length - 2 : parts.length - 1;
|
|
872
1007
|
const lastToUse = effectiveLastIndex >= 0 ? parts[effectiveLastIndex] : null;
|
|
873
|
-
if (lastToUse && isLikelyName(firstPart, true) && isLikelyName(lastToUse, true)) {
|
|
1008
|
+
if (lastToUse && isLikelyName(firstPart, true, true) && isLikelyName(lastToUse, true, true)) {
|
|
874
1009
|
const firstParsed = parseCompositeNamePart(firstPart);
|
|
875
1010
|
const lastParsed = parseCompositeNamePart(lastToUse);
|
|
876
1011
|
const cleanedFirst = firstParsed.hasNumbers ? firstParsed.cleaned : firstPart;
|
|
@@ -906,7 +1041,7 @@ function defaultNameDetectionMethod(email) {
|
|
|
906
1041
|
}
|
|
907
1042
|
if (!firstName && !lastName) {
|
|
908
1043
|
const parsed = parseCompositeNamePart(cleanedLocal);
|
|
909
|
-
if (isLikelyName(cleanedLocal, true)) {
|
|
1044
|
+
if (isLikelyName(cleanedLocal, true, false)) {
|
|
910
1045
|
if (/^[a-zA-Z]+$/.test(cleanedLocal)) {
|
|
911
1046
|
const nameScore = Math.max(getFirstNameScore(cleanedLocal), getLastNameScore(cleanedLocal));
|
|
912
1047
|
if (getFirstNameScore(cleanedLocal) >= getLastNameScore(cleanedLocal)) {
|
|
@@ -1087,7 +1222,7 @@ exports.VerificationErrorCode = void 0;
|
|
|
1087
1222
|
VerificationErrorCode2["FREE_EMAIL_PROVIDER"] = "FREE_EMAIL_PROVIDER";
|
|
1088
1223
|
})(exports.VerificationErrorCode || (exports.VerificationErrorCode = {}));
|
|
1089
1224
|
|
|
1090
|
-
function isValidEmailDomain(emailOrDomain) {
|
|
1225
|
+
async function isValidEmailDomain(emailOrDomain, cache) {
|
|
1091
1226
|
let [_, emailDomain] = (emailOrDomain === null || emailOrDomain === void 0 ? void 0 : emailOrDomain.split("@")) || [];
|
|
1092
1227
|
if (!emailDomain) {
|
|
1093
1228
|
emailDomain = _;
|
|
@@ -1095,16 +1230,17 @@ function isValidEmailDomain(emailOrDomain) {
|
|
|
1095
1230
|
if (!emailDomain) {
|
|
1096
1231
|
return false;
|
|
1097
1232
|
}
|
|
1098
|
-
const
|
|
1099
|
-
|
|
1233
|
+
const cacheStore = domainValidCacheStore(cache);
|
|
1234
|
+
const cached = await cacheStore.get(emailDomain);
|
|
1235
|
+
if (cached !== null && cached !== void 0) {
|
|
1100
1236
|
return cached;
|
|
1101
1237
|
}
|
|
1102
1238
|
try {
|
|
1103
1239
|
const result = psl.isValid(emailDomain) || false;
|
|
1104
|
-
|
|
1240
|
+
await cacheStore.set(emailDomain, result);
|
|
1105
1241
|
return result;
|
|
1106
1242
|
} catch (_e) {
|
|
1107
|
-
|
|
1243
|
+
await cacheStore.set(emailDomain, false);
|
|
1108
1244
|
return false;
|
|
1109
1245
|
}
|
|
1110
1246
|
}
|
|
@@ -1626,8 +1762,9 @@ function queryWhoisServer(domain, server, timeout = 5e3) {
|
|
|
1626
1762
|
async function getWhoisData(domain, timeout = 5e3) {
|
|
1627
1763
|
var _a;
|
|
1628
1764
|
const cacheKey = `whois:${domain}`;
|
|
1629
|
-
const
|
|
1630
|
-
|
|
1765
|
+
const cache = whoisCacheStore();
|
|
1766
|
+
const cached = await cache.get(cacheKey);
|
|
1767
|
+
if (cached !== null && cached !== void 0) {
|
|
1631
1768
|
return cached;
|
|
1632
1769
|
}
|
|
1633
1770
|
try {
|
|
@@ -1644,16 +1781,16 @@ async function getWhoisData(domain, timeout = 5e3) {
|
|
|
1644
1781
|
const referredServer = referMatch[1];
|
|
1645
1782
|
const whoisResponse2 = await queryWhoisServer(domain, referredServer, timeout);
|
|
1646
1783
|
const whoisData3 = parseWhoisData({ rawData: whoisResponse2, domain });
|
|
1647
|
-
|
|
1784
|
+
await cache.set(cacheKey, whoisData3);
|
|
1648
1785
|
return whoisData3;
|
|
1649
1786
|
}
|
|
1650
1787
|
const whoisData2 = parseWhoisData({ rawData: ianaResponse, domain });
|
|
1651
|
-
|
|
1788
|
+
await cache.set(cacheKey, whoisData2);
|
|
1652
1789
|
return whoisData2;
|
|
1653
1790
|
}
|
|
1654
1791
|
const whoisResponse = await queryWhoisServer(domain, whoisServer, timeout);
|
|
1655
1792
|
const whoisData = parseWhoisData({ rawData: whoisResponse, domain });
|
|
1656
|
-
|
|
1793
|
+
await cache.set(cacheKey, whoisData);
|
|
1657
1794
|
return whoisData;
|
|
1658
1795
|
} catch (_error) {
|
|
1659
1796
|
return null;
|
|
@@ -1754,7 +1891,7 @@ async function getDomainRegistrationStatus(domain, timeout = 5e3) {
|
|
|
1754
1891
|
}
|
|
1755
1892
|
|
|
1756
1893
|
async function verifyEmailBatch(params) {
|
|
1757
|
-
const { emailAddresses, concurrency = 5, timeout = 4e3, verifyMx = true, verifySmtp = false, checkDisposable = true, checkFree = true,
|
|
1894
|
+
const { emailAddresses, concurrency = 5, timeout = 4e3, verifyMx = true, verifySmtp = false, checkDisposable = true, checkFree = true, detectName = false, nameDetectionMethod, suggestDomain = false, domainSuggestionMethod, commonDomains, cache } = params;
|
|
1758
1895
|
const startTime = Date.now();
|
|
1759
1896
|
const results = /* @__PURE__ */ new Map();
|
|
1760
1897
|
const batches = [];
|
|
@@ -1767,7 +1904,7 @@ async function verifyEmailBatch(params) {
|
|
|
1767
1904
|
for (const batch of batches) {
|
|
1768
1905
|
const batchPromises = batch.map(async (email) => {
|
|
1769
1906
|
try {
|
|
1770
|
-
const result =
|
|
1907
|
+
const result = await verifyEmailDetailed({
|
|
1771
1908
|
emailAddress: email,
|
|
1772
1909
|
timeout,
|
|
1773
1910
|
verifyMx,
|
|
@@ -1778,39 +1915,20 @@ async function verifyEmailBatch(params) {
|
|
|
1778
1915
|
nameDetectionMethod,
|
|
1779
1916
|
suggestDomain,
|
|
1780
1917
|
domainSuggestionMethod,
|
|
1781
|
-
commonDomains
|
|
1782
|
-
|
|
1783
|
-
emailAddress: email,
|
|
1784
|
-
timeout,
|
|
1785
|
-
verifyMx,
|
|
1786
|
-
verifySmtp,
|
|
1787
|
-
detectName,
|
|
1788
|
-
nameDetectionMethod,
|
|
1789
|
-
suggestDomain,
|
|
1790
|
-
domainSuggestionMethod,
|
|
1791
|
-
commonDomains
|
|
1918
|
+
commonDomains,
|
|
1919
|
+
cache
|
|
1792
1920
|
});
|
|
1793
|
-
if (
|
|
1794
|
-
|
|
1795
|
-
if (detailedResult.valid) {
|
|
1796
|
-
totalValid++;
|
|
1797
|
-
} else {
|
|
1798
|
-
totalInvalid++;
|
|
1799
|
-
}
|
|
1921
|
+
if (result.valid) {
|
|
1922
|
+
totalValid++;
|
|
1800
1923
|
} else {
|
|
1801
|
-
|
|
1802
|
-
if (basicResult.validFormat && basicResult.validMx !== false) {
|
|
1803
|
-
totalValid++;
|
|
1804
|
-
} else {
|
|
1805
|
-
totalInvalid++;
|
|
1806
|
-
}
|
|
1924
|
+
totalInvalid++;
|
|
1807
1925
|
}
|
|
1808
1926
|
return { email, result };
|
|
1809
1927
|
} catch (error) {
|
|
1810
1928
|
totalErrors++;
|
|
1811
1929
|
return {
|
|
1812
1930
|
email,
|
|
1813
|
-
result:
|
|
1931
|
+
result: createErrorDetailedResult(email)
|
|
1814
1932
|
};
|
|
1815
1933
|
}
|
|
1816
1934
|
});
|
|
@@ -1848,38 +1966,56 @@ function createErrorDetailedResult(email, _error) {
|
|
|
1848
1966
|
|
|
1849
1967
|
let disposableEmailProviders;
|
|
1850
1968
|
let freeEmailProviders;
|
|
1851
|
-
function isDisposableEmail(emailOrDomain) {
|
|
1969
|
+
async function isDisposableEmail(emailOrDomain, cache) {
|
|
1852
1970
|
const parts = emailOrDomain.split("@");
|
|
1853
1971
|
const emailDomain = parts.length > 1 ? parts[1] : parts[0];
|
|
1854
1972
|
if (!emailDomain) {
|
|
1855
1973
|
return false;
|
|
1856
1974
|
}
|
|
1857
|
-
const
|
|
1858
|
-
|
|
1975
|
+
const cacheStore = disposableCacheStore(cache);
|
|
1976
|
+
let cached;
|
|
1977
|
+
try {
|
|
1978
|
+
cached = await cacheStore.get(emailDomain);
|
|
1979
|
+
} catch (_error) {
|
|
1980
|
+
cached = null;
|
|
1981
|
+
}
|
|
1982
|
+
if (cached !== null && cached !== void 0) {
|
|
1859
1983
|
return cached;
|
|
1860
1984
|
}
|
|
1861
1985
|
if (!disposableEmailProviders) {
|
|
1862
1986
|
disposableEmailProviders = new Set(require("./disposable-email-providers.json"));
|
|
1863
1987
|
}
|
|
1864
1988
|
const result = disposableEmailProviders.has(emailDomain);
|
|
1865
|
-
|
|
1989
|
+
try {
|
|
1990
|
+
await cacheStore.set(emailDomain, result);
|
|
1991
|
+
} catch (_error) {
|
|
1992
|
+
}
|
|
1866
1993
|
return result;
|
|
1867
1994
|
}
|
|
1868
|
-
function isFreeEmail(emailOrDomain) {
|
|
1995
|
+
async function isFreeEmail(emailOrDomain, cache) {
|
|
1869
1996
|
const parts = emailOrDomain.split("@");
|
|
1870
1997
|
const emailDomain = parts.length > 1 ? parts[1] : parts[0];
|
|
1871
1998
|
if (!emailDomain) {
|
|
1872
1999
|
return false;
|
|
1873
2000
|
}
|
|
1874
|
-
const
|
|
1875
|
-
|
|
2001
|
+
const cacheStore = freeCacheStore(cache);
|
|
2002
|
+
let cached;
|
|
2003
|
+
try {
|
|
2004
|
+
cached = await cacheStore.get(emailDomain);
|
|
2005
|
+
} catch (_error) {
|
|
2006
|
+
cached = null;
|
|
2007
|
+
}
|
|
2008
|
+
if (cached !== null && cached !== void 0) {
|
|
1876
2009
|
return cached;
|
|
1877
2010
|
}
|
|
1878
2011
|
if (!freeEmailProviders) {
|
|
1879
2012
|
freeEmailProviders = new Set(require("./free-email-providers.json"));
|
|
1880
2013
|
}
|
|
1881
2014
|
const result = freeEmailProviders.has(emailDomain);
|
|
1882
|
-
|
|
2015
|
+
try {
|
|
2016
|
+
await cacheStore.set(emailDomain, result);
|
|
2017
|
+
} catch (_error) {
|
|
2018
|
+
}
|
|
1883
2019
|
return result;
|
|
1884
2020
|
}
|
|
1885
2021
|
const domainPorts = {
|
|
@@ -1912,7 +2048,7 @@ async function verifyEmail(params) {
|
|
|
1912
2048
|
if (suggestDomain2) {
|
|
1913
2049
|
const [, emailDomain] = emailAddress.split("@");
|
|
1914
2050
|
if (emailDomain) {
|
|
1915
|
-
result.domainSuggestion = domainSuggestionMethod ? domainSuggestionMethod(emailDomain) : suggestEmailDomain(emailAddress, commonDomains);
|
|
2051
|
+
result.domainSuggestion = domainSuggestionMethod ? domainSuggestionMethod(emailDomain) : await suggestEmailDomain(emailAddress, commonDomains);
|
|
1916
2052
|
}
|
|
1917
2053
|
}
|
|
1918
2054
|
if (checkDomainAge) {
|
|
@@ -1934,7 +2070,7 @@ async function verifyEmail(params) {
|
|
|
1934
2070
|
if (!verifyMx && !verifySmtp)
|
|
1935
2071
|
return result;
|
|
1936
2072
|
try {
|
|
1937
|
-
mxRecords = await resolveMxRecords(domain);
|
|
2073
|
+
mxRecords = await resolveMxRecords(domain, params.cache);
|
|
1938
2074
|
log("[verifyEmail] Found MX records", mxRecords);
|
|
1939
2075
|
} catch (err) {
|
|
1940
2076
|
log("[verifyEmail] Failed to resolve MX records", err);
|
|
@@ -1948,8 +2084,9 @@ async function verifyEmail(params) {
|
|
|
1948
2084
|
}
|
|
1949
2085
|
if (verifySmtp && (mxRecords === null || mxRecords === void 0 ? void 0 : mxRecords.length) > 0) {
|
|
1950
2086
|
const cacheKey = `${emailAddress}:smtp`;
|
|
1951
|
-
const
|
|
1952
|
-
|
|
2087
|
+
const smtpCacheInstance = smtpCacheStore(params.cache);
|
|
2088
|
+
const cachedSmtp = await smtpCacheInstance.get(cacheKey);
|
|
2089
|
+
if (cachedSmtp !== null && cachedSmtp !== void 0) {
|
|
1953
2090
|
result.validSmtp = cachedSmtp;
|
|
1954
2091
|
if (detectName2 && !result.detectedName) {
|
|
1955
2092
|
result.detectedName = detectNameFromEmail({
|
|
@@ -1979,7 +2116,7 @@ async function verifyEmail(params) {
|
|
|
1979
2116
|
port: domainPort,
|
|
1980
2117
|
retryAttempts: params.retryAttempts
|
|
1981
2118
|
});
|
|
1982
|
-
|
|
2119
|
+
await smtpCacheInstance.set(cacheKey, smtpResult);
|
|
1983
2120
|
result.validSmtp = smtpResult;
|
|
1984
2121
|
}
|
|
1985
2122
|
return result;
|
|
@@ -2019,7 +2156,7 @@ async function verifyEmailDetailed(params) {
|
|
|
2019
2156
|
if (suggestDomain2) {
|
|
2020
2157
|
const [, emailDomain] = emailAddress.split("@");
|
|
2021
2158
|
if (emailDomain) {
|
|
2022
|
-
result.domainSuggestion = domainSuggestionMethod ? domainSuggestionMethod(emailDomain) : suggestEmailDomain(emailAddress, commonDomains);
|
|
2159
|
+
result.domainSuggestion = domainSuggestionMethod ? domainSuggestionMethod(emailDomain) : await suggestEmailDomain(emailAddress, commonDomains);
|
|
2023
2160
|
}
|
|
2024
2161
|
}
|
|
2025
2162
|
const [local, domain] = emailAddress.split("@");
|
|
@@ -2030,7 +2167,7 @@ async function verifyEmailDetailed(params) {
|
|
|
2030
2167
|
}
|
|
2031
2168
|
return result;
|
|
2032
2169
|
}
|
|
2033
|
-
if (!isValidEmailDomain(domain)) {
|
|
2170
|
+
if (!await isValidEmailDomain(domain, params.cache)) {
|
|
2034
2171
|
result.domain.error = exports.VerificationErrorCode.INVALID_DOMAIN;
|
|
2035
2172
|
if (result.metadata) {
|
|
2036
2173
|
result.metadata.verificationTime = Date.now() - startTime;
|
|
@@ -2038,14 +2175,14 @@ async function verifyEmailDetailed(params) {
|
|
|
2038
2175
|
return result;
|
|
2039
2176
|
}
|
|
2040
2177
|
if (checkDisposable) {
|
|
2041
|
-
result.disposable = isDisposableEmail(emailAddress);
|
|
2178
|
+
result.disposable = await isDisposableEmail(emailAddress, params.cache);
|
|
2042
2179
|
if (result.disposable) {
|
|
2043
2180
|
result.valid = false;
|
|
2044
2181
|
result.domain.error = exports.VerificationErrorCode.DISPOSABLE_EMAIL;
|
|
2045
2182
|
}
|
|
2046
2183
|
}
|
|
2047
2184
|
if (checkFree) {
|
|
2048
|
-
result.freeProvider = isFreeEmail(emailAddress);
|
|
2185
|
+
result.freeProvider = await isFreeEmail(emailAddress, params.cache);
|
|
2049
2186
|
}
|
|
2050
2187
|
if (checkDomainAge) {
|
|
2051
2188
|
try {
|
|
@@ -2065,7 +2202,7 @@ async function verifyEmailDetailed(params) {
|
|
|
2065
2202
|
}
|
|
2066
2203
|
if (verifyMx || verifySmtp) {
|
|
2067
2204
|
try {
|
|
2068
|
-
const mxRecords = await resolveMxRecords(domain);
|
|
2205
|
+
const mxRecords = await resolveMxRecords(domain, params.cache);
|
|
2069
2206
|
result.domain.mxRecords = mxRecords;
|
|
2070
2207
|
result.domain.valid = mxRecords.length > 0;
|
|
2071
2208
|
if (!result.domain.valid) {
|
|
@@ -2073,8 +2210,9 @@ async function verifyEmailDetailed(params) {
|
|
|
2073
2210
|
}
|
|
2074
2211
|
if (verifySmtp && mxRecords.length > 0) {
|
|
2075
2212
|
const cacheKey = `${emailAddress}:smtp`;
|
|
2076
|
-
const
|
|
2077
|
-
|
|
2213
|
+
const smtpCacheInstance = smtpCacheStore(params.cache);
|
|
2214
|
+
const cachedSmtp = await smtpCacheInstance.get(cacheKey);
|
|
2215
|
+
if (cachedSmtp !== null && cachedSmtp !== void 0) {
|
|
2078
2216
|
result.smtp.valid = cachedSmtp;
|
|
2079
2217
|
if (result.metadata) {
|
|
2080
2218
|
result.metadata.cached = true;
|
|
@@ -2102,7 +2240,7 @@ async function verifyEmailDetailed(params) {
|
|
|
2102
2240
|
port: domainPort,
|
|
2103
2241
|
retryAttempts: params.retryAttempts
|
|
2104
2242
|
});
|
|
2105
|
-
|
|
2243
|
+
await smtpCacheInstance.set(cacheKey, smtpResult);
|
|
2106
2244
|
result.smtp.valid = smtpResult;
|
|
2107
2245
|
}
|
|
2108
2246
|
if (result.smtp.valid === false) {
|