@emailcheck/email-validator-js 2.13.1-beta.3 → 2.13.1-beta.5

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/dist/dns.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- import type { ICache } from './cache-interface';
2
- export declare function resolveMxRecords(domain: string, cache?: ICache | null): Promise<string[]>;
1
+ import type { IResolveMxParams } from './types';
2
+ export declare function resolveMxRecords(params: IResolveMxParams): Promise<string[]>;
package/dist/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
- import type { ICache } from './cache-interface';
2
- import { type IVerifyEmailParams, type VerificationResult } from './types';
1
+ import { type IDisposableEmailParams, type IFreeEmailParams, type IVerifyEmailParams, type VerificationResult } from './types';
2
+ export * from './adapters/lru-adapter';
3
+ export * from './adapters/redis-adapter';
3
4
  export { verifyEmailBatch } from './batch';
4
5
  export { clearAllCaches } from './cache';
5
6
  export { COMMON_EMAIL_DOMAINS, defaultDomainSuggestionMethod, getDomainSimilarity, isCommonDomain, suggestDomain, suggestEmailDomain, } from './domain-suggester';
@@ -7,8 +8,8 @@ export { defaultNameDetectionMethod, detectName, detectNameFromEmail } from './n
7
8
  export * from './types';
8
9
  export { isValidEmail, isValidEmailDomain } from './validator';
9
10
  export { getDomainAge, getDomainRegistrationStatus } from './whois';
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
+ export declare function isDisposableEmail(params: IDisposableEmailParams): Promise<boolean>;
12
+ export declare function isFreeEmail(params: IFreeEmailParams): Promise<boolean>;
12
13
  export declare const domainPorts: Record<string, number>;
13
14
  /**
14
15
  * Verify email address
package/dist/index.esm.js CHANGED
@@ -96,12 +96,17 @@ function clearAllCaches() {
96
96
  whoisCache.clear();
97
97
  }
98
98
 
99
- async function resolveMxRecords(domain, cache) {
99
+ async function resolveMxRecords(params) {
100
+ const { domain, cache, logger } = params;
101
+ const log = logger || (() => {
102
+ });
100
103
  const cacheStore = mxCacheStore(cache);
101
104
  const cached = await cacheStore.get(domain);
102
105
  if (cached !== null && cached !== void 0) {
106
+ log(`[resolveMxRecords] Cache hit for ${domain}: ${cached.length} MX records`);
103
107
  return cached;
104
108
  }
109
+ log(`[resolveMxRecords] Performing DNS MX lookup for ${domain}`);
105
110
  try {
106
111
  const records = await promises.resolveMx(domain);
107
112
  records.sort((a, b) => {
@@ -114,9 +119,12 @@ async function resolveMxRecords(domain, cache) {
114
119
  return 0;
115
120
  });
116
121
  const exchanges = records.map((record) => record.exchange);
122
+ log(`[resolveMxRecords] Found ${exchanges.length} MX records for ${domain}: [${exchanges.join(", ")}]`);
117
123
  await cacheStore.set(domain, exchanges);
124
+ log(`[resolveMxRecords] Cached ${exchanges.length} MX records for ${domain}`);
118
125
  return exchanges;
119
126
  } catch (error) {
127
+ log(`[resolveMxRecords] MX lookup failed for ${domain}, caching empty result`);
120
128
  await cacheStore.set(domain, []);
121
129
  throw error;
122
130
  }
@@ -1926,6 +1934,106 @@ async function getDomainRegistrationStatus(domain, timeout = 5e3, debug = false)
1926
1934
  }
1927
1935
  }
1928
1936
 
1937
+ class RedisAdapter {
1938
+ constructor(redis, options = {}) {
1939
+ this.redis = redis;
1940
+ this.keyPrefix = options.keyPrefix || "email_validator:";
1941
+ this.defaultTtlMs = options.defaultTtlMs || 36e5;
1942
+ this.jsonSerializer = options.jsonSerializer || {
1943
+ stringify: (value) => {
1944
+ const processed = this.processDatesForSerialization(value);
1945
+ return JSON.stringify(processed);
1946
+ },
1947
+ parse: (value) => JSON.parse(value, (key, v) => {
1948
+ if (v && typeof v === "object" && v.__type === "Date") {
1949
+ return new Date(v.value);
1950
+ }
1951
+ return v;
1952
+ })
1953
+ };
1954
+ }
1955
+ getKey(key) {
1956
+ return `${this.keyPrefix}${key}`;
1957
+ }
1958
+ /**
1959
+ * Recursively process an object to convert Date instances to a serializable format
1960
+ */
1961
+ processDatesForSerialization(obj) {
1962
+ if (obj instanceof Date) {
1963
+ return { __type: "Date", value: obj.toISOString() };
1964
+ }
1965
+ if (obj && typeof obj === "object") {
1966
+ if (Array.isArray(obj)) {
1967
+ return obj.map((item) => this.processDatesForSerialization(item));
1968
+ }
1969
+ const result = {};
1970
+ for (const [key, value] of Object.entries(obj)) {
1971
+ result[key] = this.processDatesForSerialization(value);
1972
+ }
1973
+ return result;
1974
+ }
1975
+ return obj;
1976
+ }
1977
+ async get(key) {
1978
+ try {
1979
+ const value = await this.redis.get(this.getKey(key));
1980
+ if (value === null) {
1981
+ return null;
1982
+ }
1983
+ return this.jsonSerializer.parse(value);
1984
+ } catch (error) {
1985
+ console.error("Redis get error:", error);
1986
+ return null;
1987
+ }
1988
+ }
1989
+ async set(key, value, ttlMs) {
1990
+ try {
1991
+ const serializedValue = this.jsonSerializer.stringify(value);
1992
+ const ttl = ttlMs || this.defaultTtlMs;
1993
+ const ttlSeconds = Math.ceil(ttl / 1e3);
1994
+ await this.redis.set(this.getKey(key), serializedValue, "EX", ttlSeconds);
1995
+ } catch (error) {
1996
+ console.error("Redis set error:", error);
1997
+ }
1998
+ }
1999
+ async delete(key) {
2000
+ try {
2001
+ const result = await this.redis.del(this.getKey(key));
2002
+ return result > 0;
2003
+ } catch (error) {
2004
+ console.error("Redis delete error:", error);
2005
+ return false;
2006
+ }
2007
+ }
2008
+ async has(key) {
2009
+ try {
2010
+ const result = await this.redis.exists(this.getKey(key));
2011
+ return result > 0;
2012
+ } catch (error) {
2013
+ console.error("Redis exists error:", error);
2014
+ return false;
2015
+ }
2016
+ }
2017
+ async clear() {
2018
+ try {
2019
+ await this.redis.flushdb();
2020
+ } catch (error) {
2021
+ console.error("Redis clear error:", error);
2022
+ }
2023
+ }
2024
+ // size() is not applicable for Redis as it's a distributed store
2025
+ size() {
2026
+ return void 0;
2027
+ }
2028
+ /**
2029
+ * Helper method to delete only keys with the configured prefix
2030
+ * Requires Redis SCAN command which might not be available in all Redis clients
2031
+ */
2032
+ async clearPrefixed() {
2033
+ console.warn("clearPrefixed not implemented. Use clear() to flush the entire database.");
2034
+ }
2035
+ }
2036
+
1929
2037
  async function verifyEmailBatch(params) {
1930
2038
  const { emailAddresses, concurrency = 5, timeout = 4e3, verifyMx = true, verifySmtp = false, checkDisposable = true, checkFree = true, detectName = false, nameDetectionMethod, suggestDomain = false, domainSuggestionMethod, commonDomains, skipMxForDisposable = false, skipDomainWhoisForDisposable = false, cache } = params;
1931
2039
  const startTime = Date.now();
@@ -2004,7 +2112,10 @@ function createErrorResult(email, _error) {
2004
2112
 
2005
2113
  let disposableEmailProviders;
2006
2114
  let freeEmailProviders;
2007
- async function isDisposableEmail(emailOrDomain, cache) {
2115
+ async function isDisposableEmail(params) {
2116
+ const { emailOrDomain, cache, logger } = params;
2117
+ const log = logger || (() => {
2118
+ });
2008
2119
  const parts = emailOrDomain.split("@");
2009
2120
  const emailDomain = parts.length > 1 ? parts[1] : parts[0];
2010
2121
  if (!emailDomain) {
@@ -2018,6 +2129,7 @@ async function isDisposableEmail(emailOrDomain, cache) {
2018
2129
  cached = null;
2019
2130
  }
2020
2131
  if (cached !== null && cached !== void 0) {
2132
+ log(`[isDisposableEmail] Cache hit for ${emailDomain}: ${cached}`);
2021
2133
  return cached;
2022
2134
  }
2023
2135
  if (!disposableEmailProviders) {
@@ -2026,11 +2138,17 @@ async function isDisposableEmail(emailOrDomain, cache) {
2026
2138
  const result = disposableEmailProviders.has(emailDomain);
2027
2139
  try {
2028
2140
  await cacheStore.set(emailDomain, result);
2141
+ log(`[isDisposableEmail] Cached result for ${emailDomain}: ${result}`);
2029
2142
  } catch (_error) {
2143
+ log(`[isDisposableEmail] Cache write error for ${emailDomain}`);
2030
2144
  }
2145
+ log(`[isDisposableEmail] Check result for ${emailDomain}: ${result}`);
2031
2146
  return result;
2032
2147
  }
2033
- async function isFreeEmail(emailOrDomain, cache) {
2148
+ async function isFreeEmail(params) {
2149
+ const { emailOrDomain, cache, logger } = params;
2150
+ const log = logger || (() => {
2151
+ });
2034
2152
  const parts = emailOrDomain.split("@");
2035
2153
  const emailDomain = parts.length > 1 ? parts[1] : parts[0];
2036
2154
  if (!emailDomain) {
@@ -2044,6 +2162,7 @@ async function isFreeEmail(emailOrDomain, cache) {
2044
2162
  cached = null;
2045
2163
  }
2046
2164
  if (cached !== null && cached !== void 0) {
2165
+ log(`[isFreeEmail] Cache hit for ${emailDomain}: ${cached}`);
2047
2166
  return cached;
2048
2167
  }
2049
2168
  if (!freeEmailProviders) {
@@ -2052,8 +2171,11 @@ async function isFreeEmail(emailOrDomain, cache) {
2052
2171
  const result = freeEmailProviders.has(emailDomain);
2053
2172
  try {
2054
2173
  await cacheStore.set(emailDomain, result);
2174
+ log(`[isFreeEmail] Cached result for ${emailDomain}: ${result}`);
2055
2175
  } catch (_error) {
2176
+ log(`[isFreeEmail] Cache write error for ${emailDomain}`);
2056
2177
  }
2178
+ log(`[isFreeEmail] Check result for ${emailDomain}: ${result}`);
2057
2179
  return result;
2058
2180
  }
2059
2181
  const domainPorts = {
@@ -2062,6 +2184,7 @@ const domainPorts = {
2062
2184
  "ovh.net": 465
2063
2185
  };
2064
2186
  async function verifyEmail(params) {
2187
+ var _a;
2065
2188
  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;
2066
2189
  const startTime = Date.now();
2067
2190
  const log = debug ? console.debug : (..._args) => {
@@ -2119,36 +2242,56 @@ async function verifyEmail(params) {
2119
2242
  return result;
2120
2243
  }
2121
2244
  if (checkDisposable) {
2122
- result.isDisposable = await isDisposableEmail(emailAddress, params.cache);
2245
+ log(`[verifyEmail] Checking if ${emailAddress} is disposable email`);
2246
+ result.isDisposable = await isDisposableEmail({ emailOrDomain: emailAddress, cache: params.cache, logger: log });
2247
+ log(`[verifyEmail] Disposable check result: ${result.isDisposable}`);
2123
2248
  if (result.isDisposable && result.metadata) {
2124
2249
  result.metadata.error = VerificationErrorCode.DISPOSABLE_EMAIL;
2125
2250
  }
2126
2251
  }
2127
2252
  if (checkFree) {
2128
- result.isFree = await isFreeEmail(emailAddress, params.cache);
2253
+ log(`[verifyEmail] Checking if ${emailAddress} is free email provider`);
2254
+ result.isFree = await isFreeEmail({ emailOrDomain: emailAddress, cache: params.cache, logger: log });
2255
+ log(`[verifyEmail] Free email check result: ${result.isFree}`);
2129
2256
  }
2130
2257
  const shouldSkipMx = skipMxForDisposable && result.isDisposable;
2131
2258
  const shouldSkipDomainWhois = skipDomainWhoisForDisposable && result.isDisposable;
2259
+ if (shouldSkipMx) {
2260
+ log(`[verifyEmail] Skipping MX record check for disposable email: ${emailAddress}`);
2261
+ }
2262
+ if (shouldSkipDomainWhois) {
2263
+ log(`[verifyEmail] Skipping domain WHOIS checks for disposable email: ${emailAddress}`);
2264
+ }
2132
2265
  if (checkDomainAge && !shouldSkipDomainWhois) {
2266
+ log(`[verifyEmail] Checking domain age for ${domain}`);
2133
2267
  try {
2134
2268
  result.domainAge = await getDomainAge(domain, whoisTimeout, debug);
2269
+ log(`[verifyEmail] Domain age result:`, result.domainAge ? `${result.domainAge.ageInDays} days` : "null");
2135
2270
  } catch (err) {
2136
2271
  log("[verifyEmail] Failed to get domain age", err);
2137
2272
  result.domainAge = null;
2138
2273
  }
2274
+ } else if (checkDomainAge && shouldSkipDomainWhois) {
2275
+ log(`[verifyEmail] Domain age check skipped due to disposable email and skipDomainWhoisForDisposable=true`);
2139
2276
  }
2140
2277
  if (checkDomainRegistration && !shouldSkipDomainWhois) {
2278
+ log(`[verifyEmail] Checking domain registration status for ${domain}`);
2141
2279
  try {
2142
2280
  result.domainRegistration = await getDomainRegistrationStatus(domain, whoisTimeout, debug);
2281
+ log(`[verifyEmail] Domain registration result:`, ((_a = result.domainRegistration) === null || _a === void 0 ? void 0 : _a.isRegistered) ? "registered" : "not registered");
2143
2282
  } catch (err) {
2144
2283
  log("[verifyEmail] Failed to get domain registration status", err);
2145
2284
  result.domainRegistration = null;
2146
2285
  }
2286
+ } else if (checkDomainRegistration && shouldSkipDomainWhois) {
2287
+ log(`[verifyEmail] Domain registration check skipped due to disposable email and skipDomainWhoisForDisposable=true`);
2147
2288
  }
2148
2289
  if ((verifyMx || verifySmtp) && !shouldSkipMx) {
2290
+ log(`[verifyEmail] Checking MX records for ${domain}`);
2149
2291
  try {
2150
- const mxRecords = await resolveMxRecords(domain, params.cache);
2292
+ const mxRecords = await resolveMxRecords({ domain, cache: params.cache, logger: log });
2151
2293
  result.validMx = mxRecords.length > 0;
2294
+ log(`[verifyEmail] MX records found: ${mxRecords.length}, valid: ${result.validMx}`);
2152
2295
  if (!result.validMx && result.metadata) {
2153
2296
  result.metadata.error = VerificationErrorCode.NO_MX_RECORDS;
2154
2297
  }
@@ -2158,6 +2301,7 @@ async function verifyEmail(params) {
2158
2301
  const cachedSmtp = await smtpCacheInstance.get(cacheKey);
2159
2302
  if (cachedSmtp !== null && cachedSmtp !== void 0) {
2160
2303
  result.validSmtp = cachedSmtp;
2304
+ log(`[verifyEmail] SMTP result from cache: ${result.validSmtp} for ${emailAddress}`);
2161
2305
  if (result.metadata) {
2162
2306
  result.metadata.cached = true;
2163
2307
  }
@@ -2168,6 +2312,7 @@ async function verifyEmail(params) {
2168
2312
  });
2169
2313
  }
2170
2314
  } else {
2315
+ log(`[verifyEmail] Performing SMTP verification for ${emailAddress}`);
2171
2316
  let domainPort = params.smtpPort;
2172
2317
  if (!domainPort) {
2173
2318
  const mxDomain = parse(mxRecords[0]);
@@ -2186,6 +2331,7 @@ async function verifyEmail(params) {
2186
2331
  });
2187
2332
  await smtpCacheInstance.set(cacheKey, smtpResult);
2188
2333
  result.validSmtp = smtpResult;
2334
+ log(`[verifyEmail] SMTP verification result: ${result.validSmtp} for ${emailAddress} (cached for future use)`);
2189
2335
  }
2190
2336
  if (result.validSmtp === false && result.metadata) {
2191
2337
  result.metadata.error = VerificationErrorCode.MAILBOX_NOT_FOUND;
@@ -2200,6 +2346,8 @@ async function verifyEmail(params) {
2200
2346
  result.metadata.error = VerificationErrorCode.NO_MX_RECORDS;
2201
2347
  }
2202
2348
  }
2349
+ } else if ((verifyMx || verifySmtp) && shouldSkipMx) {
2350
+ log(`[verifyEmail] MX/SMTP checks skipped due to disposable email and skipMxForDisposable=true`);
2203
2351
  }
2204
2352
  if (result.metadata) {
2205
2353
  result.metadata.verificationTime = Date.now() - startTime;
@@ -2207,5 +2355,5 @@ async function verifyEmail(params) {
2207
2355
  return result;
2208
2356
  }
2209
2357
 
2210
- export { COMMON_EMAIL_DOMAINS, VerificationErrorCode, clearAllCaches, defaultDomainSuggestionMethod, defaultNameDetectionMethod, detectName, detectNameFromEmail, domainPorts, getDomainAge, getDomainRegistrationStatus, getDomainSimilarity, isCommonDomain, isDisposableEmail, isFreeEmail, isValidEmail, isValidEmailDomain, suggestDomain, suggestEmailDomain, verifyEmail, verifyEmailBatch };
2358
+ export { COMMON_EMAIL_DOMAINS, LRUAdapter, RedisAdapter, VerificationErrorCode, clearAllCaches, defaultDomainSuggestionMethod, defaultNameDetectionMethod, detectName, detectNameFromEmail, domainPorts, getDomainAge, getDomainRegistrationStatus, getDomainSimilarity, isCommonDomain, isDisposableEmail, isFreeEmail, isValidEmail, isValidEmailDomain, suggestDomain, suggestEmailDomain, verifyEmail, verifyEmailBatch };
2211
2359
  //# sourceMappingURL=index.esm.js.map