@emailcheck/email-validator-js 2.12.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 +207 -73
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +207 -73
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +4 -2
- package/dist/validator.d.ts +2 -1
- package/package.json +2 -2
|
@@ -5,9 +5,13 @@ import type { DomainSuggestion, ISuggestDomainParams } from './types';
|
|
|
5
5
|
*/
|
|
6
6
|
export declare const COMMON_EMAIL_DOMAINS: string[];
|
|
7
7
|
/**
|
|
8
|
-
* Default domain suggestion method using string similarity
|
|
8
|
+
* Default domain suggestion method using string similarity (sync version)
|
|
9
9
|
*/
|
|
10
10
|
export declare function defaultDomainSuggestionMethod(domain: string, commonDomains?: string[]): DomainSuggestion | null;
|
|
11
|
+
/**
|
|
12
|
+
* Async version of default domain suggestion method
|
|
13
|
+
*/
|
|
14
|
+
export declare function defaultDomainSuggestionMethodAsync(domain: string, commonDomains?: string[]): Promise<DomainSuggestion | null>;
|
|
11
15
|
/**
|
|
12
16
|
* Suggest a corrected domain for a potentially misspelled email domain
|
|
13
17
|
* @param params - Parameters including domain and optional custom method
|
|
@@ -20,7 +24,7 @@ export declare function suggestDomain(params: ISuggestDomainParams): DomainSugge
|
|
|
20
24
|
* @param commonDomains - Optional list of common domains to check against
|
|
21
25
|
* @returns Domain suggestion with confidence score, or null if no suggestion
|
|
22
26
|
*/
|
|
23
|
-
export declare function suggestEmailDomain(email: string, commonDomains?: string[]): DomainSuggestion | null
|
|
27
|
+
export declare function suggestEmailDomain(email: string, commonDomains?: string[]): Promise<DomainSuggestion | null>;
|
|
24
28
|
/**
|
|
25
29
|
* Check if a domain is in the common domains list
|
|
26
30
|
* @param domain - Domain to check
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ICache } from './cache-interface';
|
|
1
2
|
import { type DetailedVerificationResult, type IVerifyEmailParams, type IVerifyEmailResult } from './types';
|
|
2
3
|
export { verifyEmailBatch } from './batch';
|
|
3
4
|
export { clearAllCaches } from './cache';
|
|
@@ -6,8 +7,8 @@ export { defaultNameDetectionMethod, detectName, detectNameFromEmail } from './n
|
|
|
6
7
|
export * from './types';
|
|
7
8
|
export { isValidEmail, isValidEmailDomain } from './validator';
|
|
8
9
|
export { getDomainAge, getDomainRegistrationStatus } from './whois';
|
|
9
|
-
export declare function isDisposableEmail(emailOrDomain: string): boolean
|
|
10
|
-
export declare function isFreeEmail(emailOrDomain: string): boolean
|
|
10
|
+
export declare function isDisposableEmail(emailOrDomain: string, cache?: ICache | null): Promise<boolean>;
|
|
11
|
+
export declare function isFreeEmail(emailOrDomain: string, cache?: ICache | null): Promise<boolean>;
|
|
11
12
|
export declare const domainPorts: Record<string, number>;
|
|
12
13
|
/**
|
|
13
14
|
* Verify email address with basic result format (backward compatible)
|
package/dist/index.esm.js
CHANGED
|
@@ -4,6 +4,68 @@ import { promises } from 'node:dns';
|
|
|
4
4
|
import { stringSimilarity } from 'string-similarity-js';
|
|
5
5
|
import net from 'node:net';
|
|
6
6
|
|
|
7
|
+
class LRUAdapter {
|
|
8
|
+
constructor(maxSize = 1e3, ttlMs = 36e5) {
|
|
9
|
+
this.lru = lru(maxSize, ttlMs);
|
|
10
|
+
}
|
|
11
|
+
get(key) {
|
|
12
|
+
const value = this.lru.get(key);
|
|
13
|
+
return value === void 0 ? null : value;
|
|
14
|
+
}
|
|
15
|
+
async set(key, value, ttlMs) {
|
|
16
|
+
if (ttlMs !== void 0) {
|
|
17
|
+
this.lru.set(key, value);
|
|
18
|
+
} else {
|
|
19
|
+
this.lru.set(key, value);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
async delete(key) {
|
|
23
|
+
this.lru.delete(key);
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
async has(key) {
|
|
27
|
+
return this.lru.has(key);
|
|
28
|
+
}
|
|
29
|
+
async clear() {
|
|
30
|
+
this.lru.clear();
|
|
31
|
+
}
|
|
32
|
+
size() {
|
|
33
|
+
return this.lru.size;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Get the underlying LRU instance for advanced operations
|
|
37
|
+
*/
|
|
38
|
+
getLRU() {
|
|
39
|
+
return this.lru;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const DEFAULT_CACHE_TTL = {
|
|
44
|
+
mx: 36e5,
|
|
45
|
+
// 1 hour
|
|
46
|
+
disposable: 864e5,
|
|
47
|
+
// 24 hours
|
|
48
|
+
free: 864e5,
|
|
49
|
+
// 24 hours
|
|
50
|
+
domainValid: 864e5,
|
|
51
|
+
// 24 hours
|
|
52
|
+
smtp: 18e5,
|
|
53
|
+
// 30 minutes
|
|
54
|
+
domainSuggestion: 864e5,
|
|
55
|
+
// 24 hours
|
|
56
|
+
whois: 36e5
|
|
57
|
+
// 1 hour
|
|
58
|
+
};
|
|
59
|
+
const DEFAULT_CACHE_SIZE = {
|
|
60
|
+
mx: 500,
|
|
61
|
+
disposable: 1e3,
|
|
62
|
+
free: 1e3,
|
|
63
|
+
domainValid: 1e3,
|
|
64
|
+
smtp: 500,
|
|
65
|
+
domainSuggestion: 1e3,
|
|
66
|
+
whois: 200
|
|
67
|
+
};
|
|
68
|
+
|
|
7
69
|
const mxCache = lru(500, 36e5);
|
|
8
70
|
const disposableCache = lru(1e3, 864e5);
|
|
9
71
|
const freeCache = lru(1e3, 864e5);
|
|
@@ -11,6 +73,19 @@ const domainValidCache = lru(1e3, 864e5);
|
|
|
11
73
|
const smtpCache = lru(500, 18e5);
|
|
12
74
|
const domainSuggestionCache = lru(1e3, 864e5);
|
|
13
75
|
const whoisCache = lru(200, 36e5);
|
|
76
|
+
function getCacheStore(defaultLru, cacheType, passedCache) {
|
|
77
|
+
if (passedCache && passedCache[cacheType]) {
|
|
78
|
+
return passedCache[cacheType];
|
|
79
|
+
}
|
|
80
|
+
return new LRUAdapter(DEFAULT_CACHE_SIZE[cacheType], DEFAULT_CACHE_TTL[cacheType]);
|
|
81
|
+
}
|
|
82
|
+
const mxCacheStore = (passedCache) => getCacheStore(mxCache, "mx", passedCache);
|
|
83
|
+
const disposableCacheStore = (passedCache) => getCacheStore(disposableCache, "disposable", passedCache);
|
|
84
|
+
const freeCacheStore = (passedCache) => getCacheStore(freeCache, "free", passedCache);
|
|
85
|
+
const domainValidCacheStore = (passedCache) => getCacheStore(domainValidCache, "domainValid", passedCache);
|
|
86
|
+
const smtpCacheStore = (passedCache) => getCacheStore(smtpCache, "smtp", passedCache);
|
|
87
|
+
const domainSuggestionCacheStore = (passedCache) => getCacheStore(domainSuggestionCache, "domainSuggestion", passedCache);
|
|
88
|
+
const whoisCacheStore = (passedCache) => getCacheStore(whoisCache, "whois", passedCache);
|
|
14
89
|
function clearAllCaches() {
|
|
15
90
|
mxCache.clear();
|
|
16
91
|
disposableCache.clear();
|
|
@@ -21,9 +96,10 @@ function clearAllCaches() {
|
|
|
21
96
|
whoisCache.clear();
|
|
22
97
|
}
|
|
23
98
|
|
|
24
|
-
async function resolveMxRecords(domain) {
|
|
25
|
-
const
|
|
26
|
-
|
|
99
|
+
async function resolveMxRecords(domain, cache) {
|
|
100
|
+
const cacheStore = mxCacheStore(cache);
|
|
101
|
+
const cached = await cacheStore.get(domain);
|
|
102
|
+
if (cached !== null && cached !== void 0) {
|
|
27
103
|
return cached;
|
|
28
104
|
}
|
|
29
105
|
try {
|
|
@@ -38,10 +114,10 @@ async function resolveMxRecords(domain) {
|
|
|
38
114
|
return 0;
|
|
39
115
|
});
|
|
40
116
|
const exchanges = records.map((record) => record.exchange);
|
|
41
|
-
|
|
117
|
+
await cacheStore.set(domain, exchanges);
|
|
42
118
|
return exchanges;
|
|
43
119
|
} catch (error) {
|
|
44
|
-
|
|
120
|
+
await cacheStore.set(domain, []);
|
|
45
121
|
throw error;
|
|
46
122
|
}
|
|
47
123
|
}
|
|
@@ -131,18 +207,73 @@ function getSimilarityThreshold(domain) {
|
|
|
131
207
|
return 0.75;
|
|
132
208
|
}
|
|
133
209
|
function defaultDomainSuggestionMethod(domain, commonDomains) {
|
|
210
|
+
const domainsToCheck = commonDomains || COMMON_EMAIL_DOMAINS;
|
|
211
|
+
const lowerDomain = domain.toLowerCase();
|
|
212
|
+
if (domainsToCheck.includes(lowerDomain)) {
|
|
213
|
+
return null;
|
|
214
|
+
}
|
|
215
|
+
for (const [correctDomain, typos] of Object.entries(TYPO_PATTERNS)) {
|
|
216
|
+
if (typos.includes(lowerDomain)) {
|
|
217
|
+
return {
|
|
218
|
+
original: domain,
|
|
219
|
+
suggested: correctDomain,
|
|
220
|
+
confidence: 0.95
|
|
221
|
+
// High confidence for known typo patterns
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
let bestMatch = null;
|
|
226
|
+
const threshold = getSimilarityThreshold(lowerDomain);
|
|
227
|
+
for (const commonDomain of domainsToCheck) {
|
|
228
|
+
const similarity = stringSimilarity(lowerDomain, commonDomain.toLowerCase());
|
|
229
|
+
if (similarity >= threshold) {
|
|
230
|
+
if (!bestMatch || similarity > bestMatch.similarity) {
|
|
231
|
+
bestMatch = { domain: commonDomain, similarity };
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
if (!bestMatch) {
|
|
236
|
+
for (const commonDomain of domainsToCheck) {
|
|
237
|
+
if (Math.abs(lowerDomain.length - commonDomain.length) <= 2) {
|
|
238
|
+
const similarity = stringSimilarity(lowerDomain, commonDomain.toLowerCase());
|
|
239
|
+
if (similarity >= 0.7) {
|
|
240
|
+
if (!bestMatch || similarity > bestMatch.similarity) {
|
|
241
|
+
bestMatch = { domain: commonDomain, similarity };
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
if (bestMatch) {
|
|
248
|
+
if (bestMatch.domain.charAt(0) !== lowerDomain.charAt(0) && bestMatch.similarity < 0.9) {
|
|
249
|
+
return null;
|
|
250
|
+
}
|
|
251
|
+
return {
|
|
252
|
+
original: domain,
|
|
253
|
+
suggested: bestMatch.domain,
|
|
254
|
+
confidence: bestMatch.similarity
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
return null;
|
|
258
|
+
}
|
|
259
|
+
async function defaultDomainSuggestionMethodAsync(domain, commonDomains) {
|
|
260
|
+
return defaultDomainSuggestionMethodImpl(domain, commonDomains);
|
|
261
|
+
}
|
|
262
|
+
async function defaultDomainSuggestionMethodImpl(domain, commonDomains) {
|
|
134
263
|
if (!domain || domain.length < 3) {
|
|
135
264
|
return null;
|
|
136
265
|
}
|
|
137
266
|
const domainsToCheck = commonDomains || COMMON_EMAIL_DOMAINS;
|
|
138
267
|
const lowerDomain = domain.toLowerCase();
|
|
139
268
|
const cacheKey = `${lowerDomain}:${domainsToCheck.length}`;
|
|
140
|
-
const
|
|
141
|
-
|
|
142
|
-
|
|
269
|
+
const cache = domainSuggestionCacheStore();
|
|
270
|
+
const cached = cache.get(cacheKey);
|
|
271
|
+
const resolved = cached && typeof cached === "object" && "then" in cached ? await cached : cached;
|
|
272
|
+
if (resolved !== null && resolved !== void 0) {
|
|
273
|
+
return resolved ? { original: domain, suggested: resolved.suggested, confidence: resolved.confidence } : null;
|
|
143
274
|
}
|
|
144
275
|
if (domainsToCheck.includes(lowerDomain)) {
|
|
145
|
-
|
|
276
|
+
await cache.set(cacheKey, null);
|
|
146
277
|
return null;
|
|
147
278
|
}
|
|
148
279
|
for (const [correctDomain, typos] of Object.entries(TYPO_PATTERNS)) {
|
|
@@ -153,7 +284,7 @@ function defaultDomainSuggestionMethod(domain, commonDomains) {
|
|
|
153
284
|
confidence: 0.95
|
|
154
285
|
// High confidence for known typo patterns
|
|
155
286
|
};
|
|
156
|
-
|
|
287
|
+
await cache.set(cacheKey, { suggested: result.suggested, confidence: result.confidence });
|
|
157
288
|
return result;
|
|
158
289
|
}
|
|
159
290
|
}
|
|
@@ -181,7 +312,7 @@ function defaultDomainSuggestionMethod(domain, commonDomains) {
|
|
|
181
312
|
}
|
|
182
313
|
if (bestMatch) {
|
|
183
314
|
if (bestMatch.domain.charAt(0) !== lowerDomain.charAt(0) && bestMatch.similarity < 0.9) {
|
|
184
|
-
|
|
315
|
+
await cache.set(cacheKey, null);
|
|
185
316
|
return null;
|
|
186
317
|
}
|
|
187
318
|
const result = {
|
|
@@ -189,10 +320,10 @@ function defaultDomainSuggestionMethod(domain, commonDomains) {
|
|
|
189
320
|
suggested: bestMatch.domain,
|
|
190
321
|
confidence: bestMatch.similarity
|
|
191
322
|
};
|
|
192
|
-
|
|
323
|
+
await cache.set(cacheKey, { suggested: result.suggested, confidence: result.confidence });
|
|
193
324
|
return result;
|
|
194
325
|
}
|
|
195
|
-
|
|
326
|
+
await cache.set(cacheKey, null);
|
|
196
327
|
return null;
|
|
197
328
|
}
|
|
198
329
|
function suggestDomain(params) {
|
|
@@ -209,7 +340,7 @@ function suggestDomain(params) {
|
|
|
209
340
|
}
|
|
210
341
|
return defaultDomainSuggestionMethod(domain, commonDomains);
|
|
211
342
|
}
|
|
212
|
-
function suggestEmailDomain(email, commonDomains) {
|
|
343
|
+
async function suggestEmailDomain(email, commonDomains) {
|
|
213
344
|
if (!email || !email.includes("@")) {
|
|
214
345
|
return null;
|
|
215
346
|
}
|
|
@@ -217,7 +348,7 @@ function suggestEmailDomain(email, commonDomains) {
|
|
|
217
348
|
if (!domain || !localPart) {
|
|
218
349
|
return null;
|
|
219
350
|
}
|
|
220
|
-
const suggestion =
|
|
351
|
+
const suggestion = await defaultDomainSuggestionMethodAsync(domain, commonDomains);
|
|
221
352
|
if (suggestion) {
|
|
222
353
|
return {
|
|
223
354
|
original: email,
|
|
@@ -1089,7 +1220,7 @@ var VerificationErrorCode;
|
|
|
1089
1220
|
VerificationErrorCode2["FREE_EMAIL_PROVIDER"] = "FREE_EMAIL_PROVIDER";
|
|
1090
1221
|
})(VerificationErrorCode || (VerificationErrorCode = {}));
|
|
1091
1222
|
|
|
1092
|
-
function isValidEmailDomain(emailOrDomain) {
|
|
1223
|
+
async function isValidEmailDomain(emailOrDomain, cache) {
|
|
1093
1224
|
let [_, emailDomain] = (emailOrDomain === null || emailOrDomain === void 0 ? void 0 : emailOrDomain.split("@")) || [];
|
|
1094
1225
|
if (!emailDomain) {
|
|
1095
1226
|
emailDomain = _;
|
|
@@ -1097,16 +1228,17 @@ function isValidEmailDomain(emailOrDomain) {
|
|
|
1097
1228
|
if (!emailDomain) {
|
|
1098
1229
|
return false;
|
|
1099
1230
|
}
|
|
1100
|
-
const
|
|
1101
|
-
|
|
1231
|
+
const cacheStore = domainValidCacheStore(cache);
|
|
1232
|
+
const cached = await cacheStore.get(emailDomain);
|
|
1233
|
+
if (cached !== null && cached !== void 0) {
|
|
1102
1234
|
return cached;
|
|
1103
1235
|
}
|
|
1104
1236
|
try {
|
|
1105
1237
|
const result = isValid(emailDomain) || false;
|
|
1106
|
-
|
|
1238
|
+
await cacheStore.set(emailDomain, result);
|
|
1107
1239
|
return result;
|
|
1108
1240
|
} catch (_e) {
|
|
1109
|
-
|
|
1241
|
+
await cacheStore.set(emailDomain, false);
|
|
1110
1242
|
return false;
|
|
1111
1243
|
}
|
|
1112
1244
|
}
|
|
@@ -1628,8 +1760,9 @@ function queryWhoisServer(domain, server, timeout = 5e3) {
|
|
|
1628
1760
|
async function getWhoisData(domain, timeout = 5e3) {
|
|
1629
1761
|
var _a;
|
|
1630
1762
|
const cacheKey = `whois:${domain}`;
|
|
1631
|
-
const
|
|
1632
|
-
|
|
1763
|
+
const cache = whoisCacheStore();
|
|
1764
|
+
const cached = await cache.get(cacheKey);
|
|
1765
|
+
if (cached !== null && cached !== void 0) {
|
|
1633
1766
|
return cached;
|
|
1634
1767
|
}
|
|
1635
1768
|
try {
|
|
@@ -1646,16 +1779,16 @@ async function getWhoisData(domain, timeout = 5e3) {
|
|
|
1646
1779
|
const referredServer = referMatch[1];
|
|
1647
1780
|
const whoisResponse2 = await queryWhoisServer(domain, referredServer, timeout);
|
|
1648
1781
|
const whoisData3 = parseWhoisData({ rawData: whoisResponse2, domain });
|
|
1649
|
-
|
|
1782
|
+
await cache.set(cacheKey, whoisData3);
|
|
1650
1783
|
return whoisData3;
|
|
1651
1784
|
}
|
|
1652
1785
|
const whoisData2 = parseWhoisData({ rawData: ianaResponse, domain });
|
|
1653
|
-
|
|
1786
|
+
await cache.set(cacheKey, whoisData2);
|
|
1654
1787
|
return whoisData2;
|
|
1655
1788
|
}
|
|
1656
1789
|
const whoisResponse = await queryWhoisServer(domain, whoisServer, timeout);
|
|
1657
1790
|
const whoisData = parseWhoisData({ rawData: whoisResponse, domain });
|
|
1658
|
-
|
|
1791
|
+
await cache.set(cacheKey, whoisData);
|
|
1659
1792
|
return whoisData;
|
|
1660
1793
|
} catch (_error) {
|
|
1661
1794
|
return null;
|
|
@@ -1756,7 +1889,7 @@ async function getDomainRegistrationStatus(domain, timeout = 5e3) {
|
|
|
1756
1889
|
}
|
|
1757
1890
|
|
|
1758
1891
|
async function verifyEmailBatch(params) {
|
|
1759
|
-
const { emailAddresses, concurrency = 5, timeout = 4e3, verifyMx = true, verifySmtp = false, checkDisposable = true, checkFree = true,
|
|
1892
|
+
const { emailAddresses, concurrency = 5, timeout = 4e3, verifyMx = true, verifySmtp = false, checkDisposable = true, checkFree = true, detectName = false, nameDetectionMethod, suggestDomain = false, domainSuggestionMethod, commonDomains, cache } = params;
|
|
1760
1893
|
const startTime = Date.now();
|
|
1761
1894
|
const results = /* @__PURE__ */ new Map();
|
|
1762
1895
|
const batches = [];
|
|
@@ -1769,7 +1902,7 @@ async function verifyEmailBatch(params) {
|
|
|
1769
1902
|
for (const batch of batches) {
|
|
1770
1903
|
const batchPromises = batch.map(async (email) => {
|
|
1771
1904
|
try {
|
|
1772
|
-
const result =
|
|
1905
|
+
const result = await verifyEmailDetailed({
|
|
1773
1906
|
emailAddress: email,
|
|
1774
1907
|
timeout,
|
|
1775
1908
|
verifyMx,
|
|
@@ -1780,39 +1913,20 @@ async function verifyEmailBatch(params) {
|
|
|
1780
1913
|
nameDetectionMethod,
|
|
1781
1914
|
suggestDomain,
|
|
1782
1915
|
domainSuggestionMethod,
|
|
1783
|
-
commonDomains
|
|
1784
|
-
|
|
1785
|
-
emailAddress: email,
|
|
1786
|
-
timeout,
|
|
1787
|
-
verifyMx,
|
|
1788
|
-
verifySmtp,
|
|
1789
|
-
detectName,
|
|
1790
|
-
nameDetectionMethod,
|
|
1791
|
-
suggestDomain,
|
|
1792
|
-
domainSuggestionMethod,
|
|
1793
|
-
commonDomains
|
|
1916
|
+
commonDomains,
|
|
1917
|
+
cache
|
|
1794
1918
|
});
|
|
1795
|
-
if (
|
|
1796
|
-
|
|
1797
|
-
if (detailedResult.valid) {
|
|
1798
|
-
totalValid++;
|
|
1799
|
-
} else {
|
|
1800
|
-
totalInvalid++;
|
|
1801
|
-
}
|
|
1919
|
+
if (result.valid) {
|
|
1920
|
+
totalValid++;
|
|
1802
1921
|
} else {
|
|
1803
|
-
|
|
1804
|
-
if (basicResult.validFormat && basicResult.validMx !== false) {
|
|
1805
|
-
totalValid++;
|
|
1806
|
-
} else {
|
|
1807
|
-
totalInvalid++;
|
|
1808
|
-
}
|
|
1922
|
+
totalInvalid++;
|
|
1809
1923
|
}
|
|
1810
1924
|
return { email, result };
|
|
1811
1925
|
} catch (error) {
|
|
1812
1926
|
totalErrors++;
|
|
1813
1927
|
return {
|
|
1814
1928
|
email,
|
|
1815
|
-
result:
|
|
1929
|
+
result: createErrorDetailedResult(email)
|
|
1816
1930
|
};
|
|
1817
1931
|
}
|
|
1818
1932
|
});
|
|
@@ -1850,38 +1964,56 @@ function createErrorDetailedResult(email, _error) {
|
|
|
1850
1964
|
|
|
1851
1965
|
let disposableEmailProviders;
|
|
1852
1966
|
let freeEmailProviders;
|
|
1853
|
-
function isDisposableEmail(emailOrDomain) {
|
|
1967
|
+
async function isDisposableEmail(emailOrDomain, cache) {
|
|
1854
1968
|
const parts = emailOrDomain.split("@");
|
|
1855
1969
|
const emailDomain = parts.length > 1 ? parts[1] : parts[0];
|
|
1856
1970
|
if (!emailDomain) {
|
|
1857
1971
|
return false;
|
|
1858
1972
|
}
|
|
1859
|
-
const
|
|
1860
|
-
|
|
1973
|
+
const cacheStore = disposableCacheStore(cache);
|
|
1974
|
+
let cached;
|
|
1975
|
+
try {
|
|
1976
|
+
cached = await cacheStore.get(emailDomain);
|
|
1977
|
+
} catch (_error) {
|
|
1978
|
+
cached = null;
|
|
1979
|
+
}
|
|
1980
|
+
if (cached !== null && cached !== void 0) {
|
|
1861
1981
|
return cached;
|
|
1862
1982
|
}
|
|
1863
1983
|
if (!disposableEmailProviders) {
|
|
1864
1984
|
disposableEmailProviders = new Set(require("./disposable-email-providers.json"));
|
|
1865
1985
|
}
|
|
1866
1986
|
const result = disposableEmailProviders.has(emailDomain);
|
|
1867
|
-
|
|
1987
|
+
try {
|
|
1988
|
+
await cacheStore.set(emailDomain, result);
|
|
1989
|
+
} catch (_error) {
|
|
1990
|
+
}
|
|
1868
1991
|
return result;
|
|
1869
1992
|
}
|
|
1870
|
-
function isFreeEmail(emailOrDomain) {
|
|
1993
|
+
async function isFreeEmail(emailOrDomain, cache) {
|
|
1871
1994
|
const parts = emailOrDomain.split("@");
|
|
1872
1995
|
const emailDomain = parts.length > 1 ? parts[1] : parts[0];
|
|
1873
1996
|
if (!emailDomain) {
|
|
1874
1997
|
return false;
|
|
1875
1998
|
}
|
|
1876
|
-
const
|
|
1877
|
-
|
|
1999
|
+
const cacheStore = freeCacheStore(cache);
|
|
2000
|
+
let cached;
|
|
2001
|
+
try {
|
|
2002
|
+
cached = await cacheStore.get(emailDomain);
|
|
2003
|
+
} catch (_error) {
|
|
2004
|
+
cached = null;
|
|
2005
|
+
}
|
|
2006
|
+
if (cached !== null && cached !== void 0) {
|
|
1878
2007
|
return cached;
|
|
1879
2008
|
}
|
|
1880
2009
|
if (!freeEmailProviders) {
|
|
1881
2010
|
freeEmailProviders = new Set(require("./free-email-providers.json"));
|
|
1882
2011
|
}
|
|
1883
2012
|
const result = freeEmailProviders.has(emailDomain);
|
|
1884
|
-
|
|
2013
|
+
try {
|
|
2014
|
+
await cacheStore.set(emailDomain, result);
|
|
2015
|
+
} catch (_error) {
|
|
2016
|
+
}
|
|
1885
2017
|
return result;
|
|
1886
2018
|
}
|
|
1887
2019
|
const domainPorts = {
|
|
@@ -1914,7 +2046,7 @@ async function verifyEmail(params) {
|
|
|
1914
2046
|
if (suggestDomain2) {
|
|
1915
2047
|
const [, emailDomain] = emailAddress.split("@");
|
|
1916
2048
|
if (emailDomain) {
|
|
1917
|
-
result.domainSuggestion = domainSuggestionMethod ? domainSuggestionMethod(emailDomain) : suggestEmailDomain(emailAddress, commonDomains);
|
|
2049
|
+
result.domainSuggestion = domainSuggestionMethod ? domainSuggestionMethod(emailDomain) : await suggestEmailDomain(emailAddress, commonDomains);
|
|
1918
2050
|
}
|
|
1919
2051
|
}
|
|
1920
2052
|
if (checkDomainAge) {
|
|
@@ -1936,7 +2068,7 @@ async function verifyEmail(params) {
|
|
|
1936
2068
|
if (!verifyMx && !verifySmtp)
|
|
1937
2069
|
return result;
|
|
1938
2070
|
try {
|
|
1939
|
-
mxRecords = await resolveMxRecords(domain);
|
|
2071
|
+
mxRecords = await resolveMxRecords(domain, params.cache);
|
|
1940
2072
|
log("[verifyEmail] Found MX records", mxRecords);
|
|
1941
2073
|
} catch (err) {
|
|
1942
2074
|
log("[verifyEmail] Failed to resolve MX records", err);
|
|
@@ -1950,8 +2082,9 @@ async function verifyEmail(params) {
|
|
|
1950
2082
|
}
|
|
1951
2083
|
if (verifySmtp && (mxRecords === null || mxRecords === void 0 ? void 0 : mxRecords.length) > 0) {
|
|
1952
2084
|
const cacheKey = `${emailAddress}:smtp`;
|
|
1953
|
-
const
|
|
1954
|
-
|
|
2085
|
+
const smtpCacheInstance = smtpCacheStore(params.cache);
|
|
2086
|
+
const cachedSmtp = await smtpCacheInstance.get(cacheKey);
|
|
2087
|
+
if (cachedSmtp !== null && cachedSmtp !== void 0) {
|
|
1955
2088
|
result.validSmtp = cachedSmtp;
|
|
1956
2089
|
if (detectName2 && !result.detectedName) {
|
|
1957
2090
|
result.detectedName = detectNameFromEmail({
|
|
@@ -1981,7 +2114,7 @@ async function verifyEmail(params) {
|
|
|
1981
2114
|
port: domainPort,
|
|
1982
2115
|
retryAttempts: params.retryAttempts
|
|
1983
2116
|
});
|
|
1984
|
-
|
|
2117
|
+
await smtpCacheInstance.set(cacheKey, smtpResult);
|
|
1985
2118
|
result.validSmtp = smtpResult;
|
|
1986
2119
|
}
|
|
1987
2120
|
return result;
|
|
@@ -2021,7 +2154,7 @@ async function verifyEmailDetailed(params) {
|
|
|
2021
2154
|
if (suggestDomain2) {
|
|
2022
2155
|
const [, emailDomain] = emailAddress.split("@");
|
|
2023
2156
|
if (emailDomain) {
|
|
2024
|
-
result.domainSuggestion = domainSuggestionMethod ? domainSuggestionMethod(emailDomain) : suggestEmailDomain(emailAddress, commonDomains);
|
|
2157
|
+
result.domainSuggestion = domainSuggestionMethod ? domainSuggestionMethod(emailDomain) : await suggestEmailDomain(emailAddress, commonDomains);
|
|
2025
2158
|
}
|
|
2026
2159
|
}
|
|
2027
2160
|
const [local, domain] = emailAddress.split("@");
|
|
@@ -2032,7 +2165,7 @@ async function verifyEmailDetailed(params) {
|
|
|
2032
2165
|
}
|
|
2033
2166
|
return result;
|
|
2034
2167
|
}
|
|
2035
|
-
if (!isValidEmailDomain(domain)) {
|
|
2168
|
+
if (!await isValidEmailDomain(domain, params.cache)) {
|
|
2036
2169
|
result.domain.error = VerificationErrorCode.INVALID_DOMAIN;
|
|
2037
2170
|
if (result.metadata) {
|
|
2038
2171
|
result.metadata.verificationTime = Date.now() - startTime;
|
|
@@ -2040,14 +2173,14 @@ async function verifyEmailDetailed(params) {
|
|
|
2040
2173
|
return result;
|
|
2041
2174
|
}
|
|
2042
2175
|
if (checkDisposable) {
|
|
2043
|
-
result.disposable = isDisposableEmail(emailAddress);
|
|
2176
|
+
result.disposable = await isDisposableEmail(emailAddress, params.cache);
|
|
2044
2177
|
if (result.disposable) {
|
|
2045
2178
|
result.valid = false;
|
|
2046
2179
|
result.domain.error = VerificationErrorCode.DISPOSABLE_EMAIL;
|
|
2047
2180
|
}
|
|
2048
2181
|
}
|
|
2049
2182
|
if (checkFree) {
|
|
2050
|
-
result.freeProvider = isFreeEmail(emailAddress);
|
|
2183
|
+
result.freeProvider = await isFreeEmail(emailAddress, params.cache);
|
|
2051
2184
|
}
|
|
2052
2185
|
if (checkDomainAge) {
|
|
2053
2186
|
try {
|
|
@@ -2067,7 +2200,7 @@ async function verifyEmailDetailed(params) {
|
|
|
2067
2200
|
}
|
|
2068
2201
|
if (verifyMx || verifySmtp) {
|
|
2069
2202
|
try {
|
|
2070
|
-
const mxRecords = await resolveMxRecords(domain);
|
|
2203
|
+
const mxRecords = await resolveMxRecords(domain, params.cache);
|
|
2071
2204
|
result.domain.mxRecords = mxRecords;
|
|
2072
2205
|
result.domain.valid = mxRecords.length > 0;
|
|
2073
2206
|
if (!result.domain.valid) {
|
|
@@ -2075,8 +2208,9 @@ async function verifyEmailDetailed(params) {
|
|
|
2075
2208
|
}
|
|
2076
2209
|
if (verifySmtp && mxRecords.length > 0) {
|
|
2077
2210
|
const cacheKey = `${emailAddress}:smtp`;
|
|
2078
|
-
const
|
|
2079
|
-
|
|
2211
|
+
const smtpCacheInstance = smtpCacheStore(params.cache);
|
|
2212
|
+
const cachedSmtp = await smtpCacheInstance.get(cacheKey);
|
|
2213
|
+
if (cachedSmtp !== null && cachedSmtp !== void 0) {
|
|
2080
2214
|
result.smtp.valid = cachedSmtp;
|
|
2081
2215
|
if (result.metadata) {
|
|
2082
2216
|
result.metadata.cached = true;
|
|
@@ -2104,7 +2238,7 @@ async function verifyEmailDetailed(params) {
|
|
|
2104
2238
|
port: domainPort,
|
|
2105
2239
|
retryAttempts: params.retryAttempts
|
|
2106
2240
|
});
|
|
2107
|
-
|
|
2241
|
+
await smtpCacheInstance.set(cacheKey, smtpResult);
|
|
2108
2242
|
result.smtp.valid = smtpResult;
|
|
2109
2243
|
}
|
|
2110
2244
|
if (result.smtp.valid === false) {
|