@emailcheck/email-validator-js 2.12.0 → 2.13.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.
- package/README.md +330 -77
- 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 +6 -9
- package/dist/index.esm.js +202 -166
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +201 -166
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +4 -15
- package/dist/validator.d.ts +2 -1
- package/package.json +2 -2
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,
|
|
@@ -1091,7 +1222,7 @@ exports.VerificationErrorCode = void 0;
|
|
|
1091
1222
|
VerificationErrorCode2["FREE_EMAIL_PROVIDER"] = "FREE_EMAIL_PROVIDER";
|
|
1092
1223
|
})(exports.VerificationErrorCode || (exports.VerificationErrorCode = {}));
|
|
1093
1224
|
|
|
1094
|
-
function isValidEmailDomain(emailOrDomain) {
|
|
1225
|
+
async function isValidEmailDomain(emailOrDomain, cache) {
|
|
1095
1226
|
let [_, emailDomain] = (emailOrDomain === null || emailOrDomain === void 0 ? void 0 : emailOrDomain.split("@")) || [];
|
|
1096
1227
|
if (!emailDomain) {
|
|
1097
1228
|
emailDomain = _;
|
|
@@ -1099,16 +1230,17 @@ function isValidEmailDomain(emailOrDomain) {
|
|
|
1099
1230
|
if (!emailDomain) {
|
|
1100
1231
|
return false;
|
|
1101
1232
|
}
|
|
1102
|
-
const
|
|
1103
|
-
|
|
1233
|
+
const cacheStore = domainValidCacheStore(cache);
|
|
1234
|
+
const cached = await cacheStore.get(emailDomain);
|
|
1235
|
+
if (cached !== null && cached !== void 0) {
|
|
1104
1236
|
return cached;
|
|
1105
1237
|
}
|
|
1106
1238
|
try {
|
|
1107
1239
|
const result = psl.isValid(emailDomain) || false;
|
|
1108
|
-
|
|
1240
|
+
await cacheStore.set(emailDomain, result);
|
|
1109
1241
|
return result;
|
|
1110
1242
|
} catch (_e) {
|
|
1111
|
-
|
|
1243
|
+
await cacheStore.set(emailDomain, false);
|
|
1112
1244
|
return false;
|
|
1113
1245
|
}
|
|
1114
1246
|
}
|
|
@@ -1630,8 +1762,9 @@ function queryWhoisServer(domain, server, timeout = 5e3) {
|
|
|
1630
1762
|
async function getWhoisData(domain, timeout = 5e3) {
|
|
1631
1763
|
var _a;
|
|
1632
1764
|
const cacheKey = `whois:${domain}`;
|
|
1633
|
-
const
|
|
1634
|
-
|
|
1765
|
+
const cache = whoisCacheStore();
|
|
1766
|
+
const cached = await cache.get(cacheKey);
|
|
1767
|
+
if (cached !== null && cached !== void 0) {
|
|
1635
1768
|
return cached;
|
|
1636
1769
|
}
|
|
1637
1770
|
try {
|
|
@@ -1648,16 +1781,16 @@ async function getWhoisData(domain, timeout = 5e3) {
|
|
|
1648
1781
|
const referredServer = referMatch[1];
|
|
1649
1782
|
const whoisResponse2 = await queryWhoisServer(domain, referredServer, timeout);
|
|
1650
1783
|
const whoisData3 = parseWhoisData({ rawData: whoisResponse2, domain });
|
|
1651
|
-
|
|
1784
|
+
await cache.set(cacheKey, whoisData3);
|
|
1652
1785
|
return whoisData3;
|
|
1653
1786
|
}
|
|
1654
1787
|
const whoisData2 = parseWhoisData({ rawData: ianaResponse, domain });
|
|
1655
|
-
|
|
1788
|
+
await cache.set(cacheKey, whoisData2);
|
|
1656
1789
|
return whoisData2;
|
|
1657
1790
|
}
|
|
1658
1791
|
const whoisResponse = await queryWhoisServer(domain, whoisServer, timeout);
|
|
1659
1792
|
const whoisData = parseWhoisData({ rawData: whoisResponse, domain });
|
|
1660
|
-
|
|
1793
|
+
await cache.set(cacheKey, whoisData);
|
|
1661
1794
|
return whoisData;
|
|
1662
1795
|
} catch (_error) {
|
|
1663
1796
|
return null;
|
|
@@ -1758,7 +1891,7 @@ async function getDomainRegistrationStatus(domain, timeout = 5e3) {
|
|
|
1758
1891
|
}
|
|
1759
1892
|
|
|
1760
1893
|
async function verifyEmailBatch(params) {
|
|
1761
|
-
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;
|
|
1762
1895
|
const startTime = Date.now();
|
|
1763
1896
|
const results = /* @__PURE__ */ new Map();
|
|
1764
1897
|
const batches = [];
|
|
@@ -1771,7 +1904,7 @@ async function verifyEmailBatch(params) {
|
|
|
1771
1904
|
for (const batch of batches) {
|
|
1772
1905
|
const batchPromises = batch.map(async (email) => {
|
|
1773
1906
|
try {
|
|
1774
|
-
const result =
|
|
1907
|
+
const result = await verifyEmail({
|
|
1775
1908
|
emailAddress: email,
|
|
1776
1909
|
timeout,
|
|
1777
1910
|
verifyMx,
|
|
@@ -1782,39 +1915,20 @@ async function verifyEmailBatch(params) {
|
|
|
1782
1915
|
nameDetectionMethod,
|
|
1783
1916
|
suggestDomain,
|
|
1784
1917
|
domainSuggestionMethod,
|
|
1785
|
-
commonDomains
|
|
1786
|
-
|
|
1787
|
-
emailAddress: email,
|
|
1788
|
-
timeout,
|
|
1789
|
-
verifyMx,
|
|
1790
|
-
verifySmtp,
|
|
1791
|
-
detectName,
|
|
1792
|
-
nameDetectionMethod,
|
|
1793
|
-
suggestDomain,
|
|
1794
|
-
domainSuggestionMethod,
|
|
1795
|
-
commonDomains
|
|
1918
|
+
commonDomains,
|
|
1919
|
+
cache
|
|
1796
1920
|
});
|
|
1797
|
-
if (
|
|
1798
|
-
|
|
1799
|
-
if (detailedResult.valid) {
|
|
1800
|
-
totalValid++;
|
|
1801
|
-
} else {
|
|
1802
|
-
totalInvalid++;
|
|
1803
|
-
}
|
|
1921
|
+
if (result.valid) {
|
|
1922
|
+
totalValid++;
|
|
1804
1923
|
} else {
|
|
1805
|
-
|
|
1806
|
-
if (basicResult.validFormat && basicResult.validMx !== false) {
|
|
1807
|
-
totalValid++;
|
|
1808
|
-
} else {
|
|
1809
|
-
totalInvalid++;
|
|
1810
|
-
}
|
|
1924
|
+
totalInvalid++;
|
|
1811
1925
|
}
|
|
1812
1926
|
return { email, result };
|
|
1813
1927
|
} catch (error) {
|
|
1814
1928
|
totalErrors++;
|
|
1815
1929
|
return {
|
|
1816
1930
|
email,
|
|
1817
|
-
result:
|
|
1931
|
+
result: createErrorDetailedResult(email)
|
|
1818
1932
|
};
|
|
1819
1933
|
}
|
|
1820
1934
|
});
|
|
@@ -1852,38 +1966,56 @@ function createErrorDetailedResult(email, _error) {
|
|
|
1852
1966
|
|
|
1853
1967
|
let disposableEmailProviders;
|
|
1854
1968
|
let freeEmailProviders;
|
|
1855
|
-
function isDisposableEmail(emailOrDomain) {
|
|
1969
|
+
async function isDisposableEmail(emailOrDomain, cache) {
|
|
1856
1970
|
const parts = emailOrDomain.split("@");
|
|
1857
1971
|
const emailDomain = parts.length > 1 ? parts[1] : parts[0];
|
|
1858
1972
|
if (!emailDomain) {
|
|
1859
1973
|
return false;
|
|
1860
1974
|
}
|
|
1861
|
-
const
|
|
1862
|
-
|
|
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) {
|
|
1863
1983
|
return cached;
|
|
1864
1984
|
}
|
|
1865
1985
|
if (!disposableEmailProviders) {
|
|
1866
1986
|
disposableEmailProviders = new Set(require("./disposable-email-providers.json"));
|
|
1867
1987
|
}
|
|
1868
1988
|
const result = disposableEmailProviders.has(emailDomain);
|
|
1869
|
-
|
|
1989
|
+
try {
|
|
1990
|
+
await cacheStore.set(emailDomain, result);
|
|
1991
|
+
} catch (_error) {
|
|
1992
|
+
}
|
|
1870
1993
|
return result;
|
|
1871
1994
|
}
|
|
1872
|
-
function isFreeEmail(emailOrDomain) {
|
|
1995
|
+
async function isFreeEmail(emailOrDomain, cache) {
|
|
1873
1996
|
const parts = emailOrDomain.split("@");
|
|
1874
1997
|
const emailDomain = parts.length > 1 ? parts[1] : parts[0];
|
|
1875
1998
|
if (!emailDomain) {
|
|
1876
1999
|
return false;
|
|
1877
2000
|
}
|
|
1878
|
-
const
|
|
1879
|
-
|
|
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) {
|
|
1880
2009
|
return cached;
|
|
1881
2010
|
}
|
|
1882
2011
|
if (!freeEmailProviders) {
|
|
1883
2012
|
freeEmailProviders = new Set(require("./free-email-providers.json"));
|
|
1884
2013
|
}
|
|
1885
2014
|
const result = freeEmailProviders.has(emailDomain);
|
|
1886
|
-
|
|
2015
|
+
try {
|
|
2016
|
+
await cacheStore.set(emailDomain, result);
|
|
2017
|
+
} catch (_error) {
|
|
2018
|
+
}
|
|
1887
2019
|
return result;
|
|
1888
2020
|
}
|
|
1889
2021
|
const domainPorts = {
|
|
@@ -1892,103 +2024,6 @@ const domainPorts = {
|
|
|
1892
2024
|
"ovh.net": 465
|
|
1893
2025
|
};
|
|
1894
2026
|
async function verifyEmail(params) {
|
|
1895
|
-
const { emailAddress, timeout = 4e3, verifyMx = false, verifySmtp = false, debug = false, detectName: detectName2 = false, nameDetectionMethod, suggestDomain: suggestDomain2 = false, domainSuggestionMethod, commonDomains, checkDomainAge = false, checkDomainRegistration = false, whoisTimeout = 5e3 } = params;
|
|
1896
|
-
const result = { validFormat: false, validMx: null, validSmtp: null };
|
|
1897
|
-
const log = debug ? console.debug : (..._args) => {
|
|
1898
|
-
};
|
|
1899
|
-
let mxRecords;
|
|
1900
|
-
if (!isValidEmail(emailAddress)) {
|
|
1901
|
-
log("[verifyEmail] Failed on wellFormed check");
|
|
1902
|
-
return result;
|
|
1903
|
-
}
|
|
1904
|
-
const [local, domain] = emailAddress.split("@");
|
|
1905
|
-
if (!domain || !local) {
|
|
1906
|
-
log("[verifyEmail] Failed on wellFormed check");
|
|
1907
|
-
return result;
|
|
1908
|
-
}
|
|
1909
|
-
result.validFormat = true;
|
|
1910
|
-
if (detectName2) {
|
|
1911
|
-
result.detectedName = detectNameFromEmail({
|
|
1912
|
-
email: emailAddress,
|
|
1913
|
-
customMethod: nameDetectionMethod
|
|
1914
|
-
});
|
|
1915
|
-
}
|
|
1916
|
-
if (suggestDomain2) {
|
|
1917
|
-
const [, emailDomain] = emailAddress.split("@");
|
|
1918
|
-
if (emailDomain) {
|
|
1919
|
-
result.domainSuggestion = domainSuggestionMethod ? domainSuggestionMethod(emailDomain) : suggestEmailDomain(emailAddress, commonDomains);
|
|
1920
|
-
}
|
|
1921
|
-
}
|
|
1922
|
-
if (checkDomainAge) {
|
|
1923
|
-
try {
|
|
1924
|
-
result.domainAge = await getDomainAge(domain, whoisTimeout);
|
|
1925
|
-
} catch (err) {
|
|
1926
|
-
log("[verifyEmail] Failed to get domain age", err);
|
|
1927
|
-
result.domainAge = null;
|
|
1928
|
-
}
|
|
1929
|
-
}
|
|
1930
|
-
if (checkDomainRegistration) {
|
|
1931
|
-
try {
|
|
1932
|
-
result.domainRegistration = await getDomainRegistrationStatus(domain, whoisTimeout);
|
|
1933
|
-
} catch (err) {
|
|
1934
|
-
log("[verifyEmail] Failed to get domain registration status", err);
|
|
1935
|
-
result.domainRegistration = null;
|
|
1936
|
-
}
|
|
1937
|
-
}
|
|
1938
|
-
if (!verifyMx && !verifySmtp)
|
|
1939
|
-
return result;
|
|
1940
|
-
try {
|
|
1941
|
-
mxRecords = await resolveMxRecords(domain);
|
|
1942
|
-
log("[verifyEmail] Found MX records", mxRecords);
|
|
1943
|
-
} catch (err) {
|
|
1944
|
-
log("[verifyEmail] Failed to resolve MX records", err);
|
|
1945
|
-
mxRecords = [];
|
|
1946
|
-
}
|
|
1947
|
-
if (verifyMx || verifySmtp) {
|
|
1948
|
-
result.validMx = mxRecords && mxRecords.length > 0;
|
|
1949
|
-
}
|
|
1950
|
-
if (verifySmtp && !(mxRecords === null || mxRecords === void 0 ? void 0 : mxRecords.length)) {
|
|
1951
|
-
result.validSmtp = false;
|
|
1952
|
-
}
|
|
1953
|
-
if (verifySmtp && (mxRecords === null || mxRecords === void 0 ? void 0 : mxRecords.length) > 0) {
|
|
1954
|
-
const cacheKey = `${emailAddress}:smtp`;
|
|
1955
|
-
const cachedSmtp = smtpCache.get(cacheKey);
|
|
1956
|
-
if (cachedSmtp !== void 0) {
|
|
1957
|
-
result.validSmtp = cachedSmtp;
|
|
1958
|
-
if (detectName2 && !result.detectedName) {
|
|
1959
|
-
result.detectedName = detectNameFromEmail({
|
|
1960
|
-
email: emailAddress,
|
|
1961
|
-
customMethod: nameDetectionMethod
|
|
1962
|
-
});
|
|
1963
|
-
}
|
|
1964
|
-
return result;
|
|
1965
|
-
}
|
|
1966
|
-
let domainPort = params.smtpPort;
|
|
1967
|
-
if (!domainPort) {
|
|
1968
|
-
const mxDomain = psl.parse(mxRecords[0]);
|
|
1969
|
-
if ("domain" in mxDomain && mxDomain.domain) {
|
|
1970
|
-
domainPort = domainPorts[mxDomain.domain];
|
|
1971
|
-
log(`[verifyEmail] Found mxDomain ${mxDomain.domain} with port ${domainPort}`);
|
|
1972
|
-
}
|
|
1973
|
-
if ("error" in mxDomain) {
|
|
1974
|
-
log(`[verifyEmail] Failed to parse mxDomain ${mxDomain.error}`);
|
|
1975
|
-
}
|
|
1976
|
-
}
|
|
1977
|
-
const smtpResult = await verifyMailboxSMTP({
|
|
1978
|
-
local,
|
|
1979
|
-
domain,
|
|
1980
|
-
mxRecords,
|
|
1981
|
-
timeout,
|
|
1982
|
-
debug,
|
|
1983
|
-
port: domainPort,
|
|
1984
|
-
retryAttempts: params.retryAttempts
|
|
1985
|
-
});
|
|
1986
|
-
smtpCache.set(cacheKey, smtpResult);
|
|
1987
|
-
result.validSmtp = smtpResult;
|
|
1988
|
-
}
|
|
1989
|
-
return result;
|
|
1990
|
-
}
|
|
1991
|
-
async function verifyEmailDetailed(params) {
|
|
1992
2027
|
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 } = params;
|
|
1993
2028
|
const startTime = Date.now();
|
|
1994
2029
|
const log = debug ? console.debug : (..._args) => {
|
|
@@ -2023,7 +2058,7 @@ async function verifyEmailDetailed(params) {
|
|
|
2023
2058
|
if (suggestDomain2) {
|
|
2024
2059
|
const [, emailDomain] = emailAddress.split("@");
|
|
2025
2060
|
if (emailDomain) {
|
|
2026
|
-
result.domainSuggestion = domainSuggestionMethod ? domainSuggestionMethod(emailDomain) : suggestEmailDomain(emailAddress, commonDomains);
|
|
2061
|
+
result.domainSuggestion = domainSuggestionMethod ? domainSuggestionMethod(emailDomain) : await suggestEmailDomain(emailAddress, commonDomains);
|
|
2027
2062
|
}
|
|
2028
2063
|
}
|
|
2029
2064
|
const [local, domain] = emailAddress.split("@");
|
|
@@ -2034,7 +2069,7 @@ async function verifyEmailDetailed(params) {
|
|
|
2034
2069
|
}
|
|
2035
2070
|
return result;
|
|
2036
2071
|
}
|
|
2037
|
-
if (!isValidEmailDomain(domain)) {
|
|
2072
|
+
if (!await isValidEmailDomain(domain, params.cache)) {
|
|
2038
2073
|
result.domain.error = exports.VerificationErrorCode.INVALID_DOMAIN;
|
|
2039
2074
|
if (result.metadata) {
|
|
2040
2075
|
result.metadata.verificationTime = Date.now() - startTime;
|
|
@@ -2042,14 +2077,14 @@ async function verifyEmailDetailed(params) {
|
|
|
2042
2077
|
return result;
|
|
2043
2078
|
}
|
|
2044
2079
|
if (checkDisposable) {
|
|
2045
|
-
result.disposable = isDisposableEmail(emailAddress);
|
|
2080
|
+
result.disposable = await isDisposableEmail(emailAddress, params.cache);
|
|
2046
2081
|
if (result.disposable) {
|
|
2047
2082
|
result.valid = false;
|
|
2048
2083
|
result.domain.error = exports.VerificationErrorCode.DISPOSABLE_EMAIL;
|
|
2049
2084
|
}
|
|
2050
2085
|
}
|
|
2051
2086
|
if (checkFree) {
|
|
2052
|
-
result.freeProvider = isFreeEmail(emailAddress);
|
|
2087
|
+
result.freeProvider = await isFreeEmail(emailAddress, params.cache);
|
|
2053
2088
|
}
|
|
2054
2089
|
if (checkDomainAge) {
|
|
2055
2090
|
try {
|
|
@@ -2069,7 +2104,7 @@ async function verifyEmailDetailed(params) {
|
|
|
2069
2104
|
}
|
|
2070
2105
|
if (verifyMx || verifySmtp) {
|
|
2071
2106
|
try {
|
|
2072
|
-
const mxRecords = await resolveMxRecords(domain);
|
|
2107
|
+
const mxRecords = await resolveMxRecords(domain, params.cache);
|
|
2073
2108
|
result.domain.mxRecords = mxRecords;
|
|
2074
2109
|
result.domain.valid = mxRecords.length > 0;
|
|
2075
2110
|
if (!result.domain.valid) {
|
|
@@ -2077,8 +2112,9 @@ async function verifyEmailDetailed(params) {
|
|
|
2077
2112
|
}
|
|
2078
2113
|
if (verifySmtp && mxRecords.length > 0) {
|
|
2079
2114
|
const cacheKey = `${emailAddress}:smtp`;
|
|
2080
|
-
const
|
|
2081
|
-
|
|
2115
|
+
const smtpCacheInstance = smtpCacheStore(params.cache);
|
|
2116
|
+
const cachedSmtp = await smtpCacheInstance.get(cacheKey);
|
|
2117
|
+
if (cachedSmtp !== null && cachedSmtp !== void 0) {
|
|
2082
2118
|
result.smtp.valid = cachedSmtp;
|
|
2083
2119
|
if (result.metadata) {
|
|
2084
2120
|
result.metadata.cached = true;
|
|
@@ -2106,7 +2142,7 @@ async function verifyEmailDetailed(params) {
|
|
|
2106
2142
|
port: domainPort,
|
|
2107
2143
|
retryAttempts: params.retryAttempts
|
|
2108
2144
|
});
|
|
2109
|
-
|
|
2145
|
+
await smtpCacheInstance.set(cacheKey, smtpResult);
|
|
2110
2146
|
result.smtp.valid = smtpResult;
|
|
2111
2147
|
}
|
|
2112
2148
|
if (result.smtp.valid === false) {
|
|
@@ -2147,5 +2183,4 @@ exports.suggestDomain = suggestDomain;
|
|
|
2147
2183
|
exports.suggestEmailDomain = suggestEmailDomain;
|
|
2148
2184
|
exports.verifyEmail = verifyEmail;
|
|
2149
2185
|
exports.verifyEmailBatch = verifyEmailBatch;
|
|
2150
|
-
exports.verifyEmailDetailed = verifyEmailDetailed;
|
|
2151
2186
|
//# sourceMappingURL=index.js.map
|