@emailcheck/email-validator-js 2.13.1-beta.1 → 2.13.1-beta.2
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 +38 -41
- package/dist/index.d.ts +2 -2
- package/dist/index.esm.js +95 -54
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +95 -54
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +10 -22
- package/dist/whois.d.ts +2 -2
- package/package.json +3 -2
package/dist/index.js
CHANGED
|
@@ -1734,37 +1734,50 @@ const WHOIS_SERVERS = {
|
|
|
1734
1734
|
ar: "whois.nic.ar",
|
|
1735
1735
|
cl: "whois.nic.cl"
|
|
1736
1736
|
};
|
|
1737
|
-
function queryWhoisServer(domain, server, timeout = 5e3) {
|
|
1737
|
+
function queryWhoisServer(domain, server, timeout = 5e3, debug = false) {
|
|
1738
|
+
const log = debug ? console.debug : (..._args) => {
|
|
1739
|
+
};
|
|
1738
1740
|
return new Promise((resolve, reject) => {
|
|
1739
1741
|
const client = new net.Socket();
|
|
1740
1742
|
let data = "";
|
|
1743
|
+
log(`[whois] querying ${server} for domain ${domain}`);
|
|
1741
1744
|
const timer = setTimeout(() => {
|
|
1745
|
+
log(`[whois] timeout after ${timeout}ms for ${domain} at ${server}`);
|
|
1742
1746
|
client.destroy();
|
|
1743
1747
|
reject(new Error("WHOIS query timeout"));
|
|
1744
1748
|
}, timeout);
|
|
1745
1749
|
client.connect(43, server, () => {
|
|
1750
|
+
log(`[whois] connected to ${server}, sending query for ${domain}`);
|
|
1746
1751
|
client.write(`${domain}\r
|
|
1747
1752
|
`);
|
|
1748
1753
|
});
|
|
1749
1754
|
client.on("data", (chunk) => {
|
|
1750
|
-
|
|
1755
|
+
const chunkStr = chunk.toString();
|
|
1756
|
+
data += chunkStr;
|
|
1757
|
+
log(`[whois] received ${chunkStr.length} bytes from ${server}`);
|
|
1751
1758
|
});
|
|
1752
1759
|
client.on("close", () => {
|
|
1753
1760
|
clearTimeout(timer);
|
|
1761
|
+
log(`[whois] connection closed, received total ${data.length} bytes from ${server}`);
|
|
1754
1762
|
resolve(data);
|
|
1755
1763
|
});
|
|
1756
1764
|
client.on("error", (err) => {
|
|
1757
1765
|
clearTimeout(timer);
|
|
1766
|
+
log(`[whois] error querying ${server}: ${err.message}`);
|
|
1758
1767
|
reject(err);
|
|
1759
1768
|
});
|
|
1760
1769
|
});
|
|
1761
1770
|
}
|
|
1762
|
-
async function getWhoisData(domain, timeout = 5e3) {
|
|
1771
|
+
async function getWhoisData(domain, timeout = 5e3, debug = false) {
|
|
1763
1772
|
var _a;
|
|
1773
|
+
const log = debug ? console.debug : (..._args) => {
|
|
1774
|
+
};
|
|
1764
1775
|
const cacheKey = `whois:${domain}`;
|
|
1765
1776
|
const cache = whoisCacheStore();
|
|
1777
|
+
log(`[whois] getting WHOIS data for ${domain}`);
|
|
1766
1778
|
const cached = await cache.get(cacheKey);
|
|
1767
1779
|
if (cached !== null && cached !== void 0) {
|
|
1780
|
+
log(`[whois] using cached data for ${domain}`);
|
|
1768
1781
|
return cached;
|
|
1769
1782
|
}
|
|
1770
1783
|
try {
|
|
@@ -1772,41 +1785,55 @@ async function getWhoisData(domain, timeout = 5e3) {
|
|
|
1772
1785
|
if (!tld) {
|
|
1773
1786
|
throw new Error("Invalid domain");
|
|
1774
1787
|
}
|
|
1788
|
+
log(`[whois] extracted TLD: ${tld} for domain: ${domain}`);
|
|
1775
1789
|
const whoisServer = WHOIS_SERVERS[tld];
|
|
1776
1790
|
if (!whoisServer) {
|
|
1791
|
+
log(`[whois] no specific server for TLD ${tld}, trying IANA`);
|
|
1777
1792
|
const defaultServer = "whois.iana.org";
|
|
1778
|
-
const ianaResponse = await queryWhoisServer(domain, defaultServer, timeout);
|
|
1793
|
+
const ianaResponse = await queryWhoisServer(domain, defaultServer, timeout, debug);
|
|
1779
1794
|
const referMatch = ianaResponse.match(/refer:\s+(\S+)/i);
|
|
1780
1795
|
if (referMatch === null || referMatch === void 0 ? void 0 : referMatch[1]) {
|
|
1781
1796
|
const referredServer = referMatch[1];
|
|
1782
|
-
|
|
1797
|
+
log(`[whois] IANA referred to ${referredServer} for ${domain}`);
|
|
1798
|
+
const whoisResponse2 = await queryWhoisServer(domain, referredServer, timeout, debug);
|
|
1783
1799
|
const whoisData3 = parseWhoisData({ rawData: whoisResponse2, domain });
|
|
1784
1800
|
await cache.set(cacheKey, whoisData3);
|
|
1801
|
+
log(`[whois] successfully retrieved and cached WHOIS data from referred server for ${domain}`);
|
|
1785
1802
|
return whoisData3;
|
|
1786
1803
|
}
|
|
1787
1804
|
const whoisData2 = parseWhoisData({ rawData: ianaResponse, domain });
|
|
1788
1805
|
await cache.set(cacheKey, whoisData2);
|
|
1806
|
+
log(`[whois] successfully retrieved and cached WHOIS data from IANA for ${domain}`);
|
|
1789
1807
|
return whoisData2;
|
|
1790
1808
|
}
|
|
1791
|
-
|
|
1809
|
+
log(`[whois] using WHOIS server ${whoisServer} for TLD ${tld}`);
|
|
1810
|
+
const whoisResponse = await queryWhoisServer(domain, whoisServer, timeout, debug);
|
|
1792
1811
|
const whoisData = parseWhoisData({ rawData: whoisResponse, domain });
|
|
1793
1812
|
await cache.set(cacheKey, whoisData);
|
|
1813
|
+
log(`[whois] successfully retrieved and cached WHOIS data for ${domain}`);
|
|
1794
1814
|
return whoisData;
|
|
1795
1815
|
} catch (_error) {
|
|
1816
|
+
log(`[whois] failed to get WHOIS data for ${domain}: ${_error instanceof Error ? _error.message : "Unknown error"}`);
|
|
1796
1817
|
return null;
|
|
1797
1818
|
}
|
|
1798
1819
|
}
|
|
1799
|
-
async function getDomainAge(domain, timeout = 5e3) {
|
|
1820
|
+
async function getDomainAge(domain, timeout = 5e3, debug = false) {
|
|
1821
|
+
const log = debug ? console.debug : (..._args) => {
|
|
1822
|
+
};
|
|
1800
1823
|
try {
|
|
1801
1824
|
const cleanDomain = domain.replace(/^https?:\/\//, "").split("/")[0].split("@").pop();
|
|
1802
1825
|
if (!cleanDomain) {
|
|
1826
|
+
log(`[whois] invalid domain format: ${domain}`);
|
|
1803
1827
|
return null;
|
|
1804
1828
|
}
|
|
1829
|
+
log(`[whois] checking domain age for ${cleanDomain}`);
|
|
1805
1830
|
if (!psl.isValid(cleanDomain)) {
|
|
1831
|
+
log(`[whois] domain validation failed: ${cleanDomain}`);
|
|
1806
1832
|
return null;
|
|
1807
1833
|
}
|
|
1808
|
-
const whoisData = await getWhoisData(cleanDomain, timeout);
|
|
1834
|
+
const whoisData = await getWhoisData(cleanDomain, timeout, debug);
|
|
1809
1835
|
if (!whoisData || !whoisData.creationDate) {
|
|
1836
|
+
log(`[whois] no creation date found for ${cleanDomain}`);
|
|
1810
1837
|
return null;
|
|
1811
1838
|
}
|
|
1812
1839
|
const now = /* @__PURE__ */ new Date();
|
|
@@ -1814,6 +1841,7 @@ async function getDomainAge(domain, timeout = 5e3) {
|
|
|
1814
1841
|
const ageInMilliseconds = now.getTime() - creationDate.getTime();
|
|
1815
1842
|
const ageInDays = Math.floor(ageInMilliseconds / (1e3 * 60 * 60 * 24));
|
|
1816
1843
|
const ageInYears = ageInDays / 365.25;
|
|
1844
|
+
log(`[whois] calculated age for ${cleanDomain}: ${ageInDays} days (${ageInYears.toFixed(2)} years)`);
|
|
1817
1845
|
return {
|
|
1818
1846
|
domain: cleanDomain,
|
|
1819
1847
|
creationDate,
|
|
@@ -1823,20 +1851,27 @@ async function getDomainAge(domain, timeout = 5e3) {
|
|
|
1823
1851
|
updatedDate: whoisData.updatedDate ? new Date(whoisData.updatedDate) : null
|
|
1824
1852
|
};
|
|
1825
1853
|
} catch (_error) {
|
|
1854
|
+
log(`[whois] error getting domain age for ${domain}: ${_error instanceof Error ? _error.message : "Unknown error"}`);
|
|
1826
1855
|
return null;
|
|
1827
1856
|
}
|
|
1828
1857
|
}
|
|
1829
|
-
async function getDomainRegistrationStatus(domain, timeout = 5e3) {
|
|
1858
|
+
async function getDomainRegistrationStatus(domain, timeout = 5e3, debug = false) {
|
|
1859
|
+
const log = debug ? console.debug : (..._args) => {
|
|
1860
|
+
};
|
|
1830
1861
|
try {
|
|
1831
1862
|
const cleanDomain = domain.replace(/^https?:\/\//, "").split("/")[0].split("@").pop();
|
|
1832
1863
|
if (!cleanDomain) {
|
|
1864
|
+
log(`[whois] invalid domain format: ${domain}`);
|
|
1833
1865
|
return null;
|
|
1834
1866
|
}
|
|
1867
|
+
log(`[whois] checking domain registration status for ${cleanDomain}`);
|
|
1835
1868
|
if (!psl.isValid(cleanDomain)) {
|
|
1869
|
+
log(`[whois] domain validation failed: ${cleanDomain}`);
|
|
1836
1870
|
return null;
|
|
1837
1871
|
}
|
|
1838
|
-
const whoisData = await getWhoisData(cleanDomain, timeout);
|
|
1872
|
+
const whoisData = await getWhoisData(cleanDomain, timeout, debug);
|
|
1839
1873
|
if (!whoisData || whoisData.isAvailable) {
|
|
1874
|
+
log(`[whois] domain ${cleanDomain} is available or not registered`);
|
|
1840
1875
|
return {
|
|
1841
1876
|
domain: cleanDomain,
|
|
1842
1877
|
isRegistered: false,
|
|
@@ -1864,6 +1899,7 @@ async function getDomainRegistrationStatus(domain, timeout = 5e3) {
|
|
|
1864
1899
|
if (!isExpired) {
|
|
1865
1900
|
daysUntilExpiration = Math.floor((expirationTime - currentTime) / (1e3 * 60 * 60 * 24));
|
|
1866
1901
|
}
|
|
1902
|
+
log(`[whois] domain ${cleanDomain} expires in ${daysUntilExpiration} days`);
|
|
1867
1903
|
}
|
|
1868
1904
|
const statusList = whoisData.status || [];
|
|
1869
1905
|
const formattedStatusList = statusList.map((s) => {
|
|
@@ -1872,6 +1908,7 @@ async function getDomainRegistrationStatus(domain, timeout = 5e3) {
|
|
|
1872
1908
|
});
|
|
1873
1909
|
const isPendingDelete = formattedStatusList.some((s) => s.toLowerCase().includes("pendingdelete") || s.toLowerCase().includes("redemption"));
|
|
1874
1910
|
const isLocked = formattedStatusList.some((s) => s.toLowerCase().includes("clienttransferprohibited") || s.toLowerCase().includes("servertransferprohibited"));
|
|
1911
|
+
log(`[whois] domain ${cleanDomain} - registered: ${isRegistered}, expired: ${isExpired}, locked: ${isLocked}, pending delete: ${isPendingDelete}`);
|
|
1875
1912
|
return {
|
|
1876
1913
|
domain: cleanDomain,
|
|
1877
1914
|
isRegistered,
|
|
@@ -1886,6 +1923,7 @@ async function getDomainRegistrationStatus(domain, timeout = 5e3) {
|
|
|
1886
1923
|
isLocked
|
|
1887
1924
|
};
|
|
1888
1925
|
} catch (_error) {
|
|
1926
|
+
log(`[whois] error getting domain registration status for ${domain}: ${_error instanceof Error ? _error.message : "Unknown error"}`);
|
|
1889
1927
|
return null;
|
|
1890
1928
|
}
|
|
1891
1929
|
}
|
|
@@ -1918,7 +1956,7 @@ async function verifyEmailBatch(params) {
|
|
|
1918
1956
|
commonDomains,
|
|
1919
1957
|
cache
|
|
1920
1958
|
});
|
|
1921
|
-
if (result.
|
|
1959
|
+
if (result.validFormat) {
|
|
1922
1960
|
totalValid++;
|
|
1923
1961
|
} else {
|
|
1924
1962
|
totalInvalid++;
|
|
@@ -1928,7 +1966,7 @@ async function verifyEmailBatch(params) {
|
|
|
1928
1966
|
totalErrors++;
|
|
1929
1967
|
return {
|
|
1930
1968
|
email,
|
|
1931
|
-
result:
|
|
1969
|
+
result: createErrorResult(email)
|
|
1932
1970
|
};
|
|
1933
1971
|
}
|
|
1934
1972
|
});
|
|
@@ -1948,18 +1986,18 @@ async function verifyEmailBatch(params) {
|
|
|
1948
1986
|
}
|
|
1949
1987
|
};
|
|
1950
1988
|
}
|
|
1951
|
-
function
|
|
1989
|
+
function createErrorResult(email, _error) {
|
|
1952
1990
|
return {
|
|
1953
|
-
valid: false,
|
|
1954
1991
|
email,
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1992
|
+
validFormat: false,
|
|
1993
|
+
validMx: null,
|
|
1994
|
+
validSmtp: null,
|
|
1995
|
+
isDisposable: false,
|
|
1996
|
+
isFree: false,
|
|
1960
1997
|
metadata: {
|
|
1961
1998
|
verificationTime: 0,
|
|
1962
|
-
cached: false
|
|
1999
|
+
cached: false,
|
|
2000
|
+
error: exports.VerificationErrorCode.SMTP_CONNECTION_FAILED
|
|
1963
2001
|
}
|
|
1964
2002
|
};
|
|
1965
2003
|
}
|
|
@@ -2029,26 +2067,25 @@ async function verifyEmail(params) {
|
|
|
2029
2067
|
const log = debug ? console.debug : (..._args) => {
|
|
2030
2068
|
};
|
|
2031
2069
|
const result = {
|
|
2032
|
-
valid: false,
|
|
2033
2070
|
email: emailAddress,
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2071
|
+
validFormat: false,
|
|
2072
|
+
validMx: null,
|
|
2073
|
+
validSmtp: null,
|
|
2074
|
+
isDisposable: false,
|
|
2075
|
+
isFree: false,
|
|
2039
2076
|
metadata: {
|
|
2040
2077
|
verificationTime: 0,
|
|
2041
2078
|
cached: false
|
|
2042
2079
|
}
|
|
2043
2080
|
};
|
|
2044
2081
|
if (!isValidEmail(emailAddress)) {
|
|
2045
|
-
result.format.error = exports.VerificationErrorCode.INVALID_FORMAT;
|
|
2046
2082
|
if (result.metadata) {
|
|
2047
2083
|
result.metadata.verificationTime = Date.now() - startTime;
|
|
2084
|
+
result.metadata.error = exports.VerificationErrorCode.INVALID_FORMAT;
|
|
2048
2085
|
}
|
|
2049
2086
|
return result;
|
|
2050
2087
|
}
|
|
2051
|
-
result.
|
|
2088
|
+
result.validFormat = true;
|
|
2052
2089
|
if (detectName2) {
|
|
2053
2090
|
result.detectedName = detectNameFromEmail({
|
|
2054
2091
|
email: emailAddress,
|
|
@@ -2058,64 +2095,67 @@ async function verifyEmail(params) {
|
|
|
2058
2095
|
if (suggestDomain2) {
|
|
2059
2096
|
const [, emailDomain] = emailAddress.split("@");
|
|
2060
2097
|
if (emailDomain) {
|
|
2061
|
-
|
|
2098
|
+
const suggestion = domainSuggestionMethod ? domainSuggestionMethod(emailDomain) : await suggestEmailDomain(emailAddress, commonDomains);
|
|
2099
|
+
if (suggestion) {
|
|
2100
|
+
result.domainSuggestion = suggestion;
|
|
2101
|
+
} else {
|
|
2102
|
+
result.domainSuggestion = null;
|
|
2103
|
+
}
|
|
2062
2104
|
}
|
|
2063
2105
|
}
|
|
2064
2106
|
const [local, domain] = emailAddress.split("@");
|
|
2065
2107
|
if (!domain || !local) {
|
|
2066
|
-
result.format.error = exports.VerificationErrorCode.INVALID_FORMAT;
|
|
2067
2108
|
if (result.metadata) {
|
|
2068
2109
|
result.metadata.verificationTime = Date.now() - startTime;
|
|
2110
|
+
result.metadata.error = exports.VerificationErrorCode.INVALID_FORMAT;
|
|
2069
2111
|
}
|
|
2070
2112
|
return result;
|
|
2071
2113
|
}
|
|
2072
2114
|
if (!await isValidEmailDomain(domain, params.cache)) {
|
|
2073
|
-
result.domain.error = exports.VerificationErrorCode.INVALID_DOMAIN;
|
|
2074
2115
|
if (result.metadata) {
|
|
2075
2116
|
result.metadata.verificationTime = Date.now() - startTime;
|
|
2117
|
+
result.metadata.error = exports.VerificationErrorCode.INVALID_DOMAIN;
|
|
2076
2118
|
}
|
|
2077
2119
|
return result;
|
|
2078
2120
|
}
|
|
2079
2121
|
if (checkDisposable) {
|
|
2080
|
-
result.
|
|
2081
|
-
if (result.
|
|
2082
|
-
result.
|
|
2083
|
-
result.domain.error = exports.VerificationErrorCode.DISPOSABLE_EMAIL;
|
|
2122
|
+
result.isDisposable = await isDisposableEmail(emailAddress, params.cache);
|
|
2123
|
+
if (result.isDisposable && result.metadata) {
|
|
2124
|
+
result.metadata.error = exports.VerificationErrorCode.DISPOSABLE_EMAIL;
|
|
2084
2125
|
}
|
|
2085
2126
|
}
|
|
2086
2127
|
if (checkFree) {
|
|
2087
|
-
result.
|
|
2128
|
+
result.isFree = await isFreeEmail(emailAddress, params.cache);
|
|
2088
2129
|
}
|
|
2089
2130
|
if (checkDomainAge) {
|
|
2090
2131
|
try {
|
|
2091
|
-
result.domainAge = await getDomainAge(domain, whoisTimeout);
|
|
2132
|
+
result.domainAge = await getDomainAge(domain, whoisTimeout, debug);
|
|
2092
2133
|
} catch (err) {
|
|
2093
|
-
log("[
|
|
2134
|
+
log("[verifyEmail] Failed to get domain age", err);
|
|
2094
2135
|
result.domainAge = null;
|
|
2095
2136
|
}
|
|
2096
2137
|
}
|
|
2097
2138
|
if (checkDomainRegistration) {
|
|
2098
2139
|
try {
|
|
2099
|
-
result.domainRegistration = await getDomainRegistrationStatus(domain, whoisTimeout);
|
|
2140
|
+
result.domainRegistration = await getDomainRegistrationStatus(domain, whoisTimeout, debug);
|
|
2100
2141
|
} catch (err) {
|
|
2101
|
-
log("[
|
|
2142
|
+
log("[verifyEmail] Failed to get domain registration status", err);
|
|
2102
2143
|
result.domainRegistration = null;
|
|
2103
2144
|
}
|
|
2104
2145
|
}
|
|
2105
2146
|
if (verifyMx || verifySmtp) {
|
|
2106
2147
|
try {
|
|
2107
2148
|
const mxRecords = await resolveMxRecords(domain, params.cache);
|
|
2108
|
-
result.
|
|
2109
|
-
result.
|
|
2110
|
-
|
|
2111
|
-
result.domain.error = exports.VerificationErrorCode.NO_MX_RECORDS;
|
|
2149
|
+
result.validMx = mxRecords.length > 0;
|
|
2150
|
+
if (!result.validMx && result.metadata) {
|
|
2151
|
+
result.metadata.error = exports.VerificationErrorCode.NO_MX_RECORDS;
|
|
2112
2152
|
}
|
|
2113
2153
|
if (verifySmtp && mxRecords.length > 0) {
|
|
2114
2154
|
const cacheKey = `${emailAddress}:smtp`;
|
|
2115
2155
|
const smtpCacheInstance = smtpCacheStore(params.cache);
|
|
2116
2156
|
const cachedSmtp = await smtpCacheInstance.get(cacheKey);
|
|
2117
2157
|
if (cachedSmtp !== null && cachedSmtp !== void 0) {
|
|
2118
|
-
result.
|
|
2158
|
+
result.validSmtp = cachedSmtp;
|
|
2119
2159
|
if (result.metadata) {
|
|
2120
2160
|
result.metadata.cached = true;
|
|
2121
2161
|
}
|
|
@@ -2143,21 +2183,22 @@ async function verifyEmail(params) {
|
|
|
2143
2183
|
retryAttempts: params.retryAttempts
|
|
2144
2184
|
});
|
|
2145
2185
|
await smtpCacheInstance.set(cacheKey, smtpResult);
|
|
2146
|
-
result.
|
|
2186
|
+
result.validSmtp = smtpResult;
|
|
2147
2187
|
}
|
|
2148
|
-
if (result.
|
|
2149
|
-
result.
|
|
2150
|
-
} else if (result.
|
|
2151
|
-
result.
|
|
2188
|
+
if (result.validSmtp === false && result.metadata) {
|
|
2189
|
+
result.metadata.error = exports.VerificationErrorCode.MAILBOX_NOT_FOUND;
|
|
2190
|
+
} else if (result.validSmtp === null && result.metadata) {
|
|
2191
|
+
result.metadata.error = exports.VerificationErrorCode.SMTP_CONNECTION_FAILED;
|
|
2152
2192
|
}
|
|
2153
2193
|
}
|
|
2154
2194
|
} catch (err) {
|
|
2155
|
-
log("[
|
|
2156
|
-
result.
|
|
2157
|
-
result.
|
|
2195
|
+
log("[verifyEmail] Failed to resolve MX records", err);
|
|
2196
|
+
result.validMx = false;
|
|
2197
|
+
if (result.metadata) {
|
|
2198
|
+
result.metadata.error = exports.VerificationErrorCode.NO_MX_RECORDS;
|
|
2199
|
+
}
|
|
2158
2200
|
}
|
|
2159
2201
|
}
|
|
2160
|
-
result.valid = result.format.valid && result.domain.valid !== false && result.smtp.valid !== false && !result.disposable;
|
|
2161
2202
|
if (result.metadata) {
|
|
2162
2203
|
result.metadata.verificationTime = Date.now() - startTime;
|
|
2163
2204
|
}
|