@visulima/email-verifier 1.0.1 → 1.0.3
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/CHANGELOG.md +11 -0
- package/dist/checks/character.d.ts +17 -17
- package/dist/checks/character.js +1 -1
- package/dist/checks/mx.d.ts +1 -1
- package/dist/checks/mx.js +1 -1
- package/dist/checks/role.d.ts +32 -32
- package/dist/checks/role.js +1 -1
- package/dist/checks/smtp.d.ts +26 -51
- package/dist/checks/smtp.js +4 -4
- package/dist/checks/symbol.d.ts +15 -15
- package/dist/checks/symbol.js +1 -1
- package/dist/checks/syntax.d.ts +16 -16
- package/dist/checks/syntax.js +1 -1
- package/dist/checks/tag.d.ts +17 -17
- package/dist/checks/tag.js +1 -1
- package/dist/enrich/name.d.ts +18 -18
- package/dist/enrich/name.js +1 -1
- package/dist/enrich/provider.d.ts +21 -21
- package/dist/enrich/provider.js +1 -1
- package/dist/enrich/typo.d.ts +31 -31
- package/dist/enrich/typo.js +1 -1
- package/dist/index.d.ts +20 -20
- package/dist/index.js +1 -1
- package/dist/packem_shared/{InMemoryCache-DyBUMeKq.js → InMemoryCache-DhoO8sQL.js} +1 -1
- package/dist/packem_shared/extractDomain-C7YvhtJH.js +1 -0
- package/dist/packem_shared/mx.d-HxIDdxvR.d.ts +104 -0
- package/dist/packem_shared/{score.d-BTcZnl2L.d.ts → score.d-a6cl6fPu.d.ts} +49 -43
- package/dist/score.d.ts +2 -2
- package/dist/score.js +1 -1
- package/dist/verify-email.d.ts +31 -31
- package/dist/verify-email.js +1 -1
- package/package.json +5 -5
- package/dist/packem_shared/extractDomain-CYJf1_0N.js +0 -1
- package/dist/packem_shared/mx.d-NAesS5sg.d.ts +0 -117
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,14 @@
|
|
|
1
|
+
## @visulima/email-verifier [1.0.3](https://github.com/visulima/visulima/compare/%40visulima%2Femail-verifier%401.0.2...%40visulima%2Femail-verifier%401.0.3) (2026-08-17)
|
|
2
|
+
|
|
3
|
+
## @visulima/email-verifier [1.0.2](https://github.com/visulima/visulima/compare/%40visulima%2Femail-verifier%401.0.1...%40visulima%2Femail-verifier%401.0.2) (2026-08-02)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Dependencies
|
|
7
|
+
|
|
8
|
+
* **@visulima/disposable-email-domains:** upgraded to 1.1.0
|
|
9
|
+
* **@visulima/email-provider-mx:** upgraded to 1.0.1
|
|
10
|
+
* **@visulima/free-email-domains:** upgraded to 1.0.1
|
|
11
|
+
|
|
1
12
|
## @visulima/email-verifier [1.0.1](https://github.com/visulima/visulima/compare/%40visulima%2Femail-verifier%401.0.0...%40visulima%2Femail-verifier%401.0.1) (2026-07-15)
|
|
2
13
|
|
|
3
14
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The result of local-part character analysis.
|
|
3
|
-
*/
|
|
2
|
+
* The result of local-part character analysis.
|
|
3
|
+
*/
|
|
4
4
|
interface CharacterResult {
|
|
5
5
|
/** Ratio of digits to total characters in the local part (0–1). */
|
|
6
6
|
digitRatio: number;
|
|
@@ -12,20 +12,20 @@ interface CharacterResult {
|
|
|
12
12
|
reasons: string[];
|
|
13
13
|
}
|
|
14
14
|
/**
|
|
15
|
-
* Analyzes the local part of an email for irregular characteristics that
|
|
16
|
-
* correlate with low-quality, spam-trap, or machine-generated addresses.
|
|
17
|
-
*
|
|
18
|
-
* Heuristic and intentionally conservative — it flags *patterns* (excessive
|
|
19
|
-
* length, digit-heavy locals, long unpronounceable consonant runs, long repeats)
|
|
20
|
-
* rather than asserting invalidity.
|
|
21
|
-
* @param email The email address to analyze.
|
|
22
|
-
* @returns The character analysis result.
|
|
23
|
-
* @example
|
|
24
|
-
* ```ts
|
|
25
|
-
* import { analyzeCharacters } from "@visulima/email-verifier/checks/character";
|
|
26
|
-
*
|
|
27
|
-
* analyzeCharacters("aaaaaaa@example.com").irregular; // long repeat ⇒ true
|
|
28
|
-
* ```
|
|
29
|
-
*/
|
|
15
|
+
* Analyzes the local part of an email for irregular characteristics that
|
|
16
|
+
* correlate with low-quality, spam-trap, or machine-generated addresses.
|
|
17
|
+
*
|
|
18
|
+
* Heuristic and intentionally conservative — it flags *patterns* (excessive
|
|
19
|
+
* length, digit-heavy locals, long unpronounceable consonant runs, long repeats)
|
|
20
|
+
* rather than asserting invalidity.
|
|
21
|
+
* @param email The email address to analyze.
|
|
22
|
+
* @returns The character analysis result.
|
|
23
|
+
* @example
|
|
24
|
+
* ```ts
|
|
25
|
+
* import { analyzeCharacters } from "@visulima/email-verifier/checks/character";
|
|
26
|
+
*
|
|
27
|
+
* analyzeCharacters("aaaaaaa@example.com").irregular; // long repeat ⇒ true
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
30
|
declare const analyzeCharacters: (email: string) => CharacterResult;
|
|
31
31
|
export { type CharacterResult, analyzeCharacters, analyzeCharacters as default };
|
package/dist/checks/character.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{splitAddress as
|
|
1
|
+
import{splitAddress as a}from"../packem_shared/extractDomain-C7YvhtJH.js";const i=30,c=.6,g=7,h=/\d/g,l=/[bcdfghj-np-tvwxz]{7,}/,u=/(.)\1{4,}/,R=r=>{const e=a(r);if(!e)return{digitRatio:0,irregular:!0,length:0,reasons:["invalid-format"]};const{localPart:t}=e,n=[],o=(t.match(h)??[]).length,s=t.length===0?0:o/t.length;return t.length>i&&n.push("excessive-length"),s>=c&&t.length>4&&n.push("digit-heavy"),l.test(t)&&n.push(`consonant-run-${String(g)}+`),u.test(t)&&n.push("repeated-character"),{digitRatio:s,irregular:n.length>0,length:t.length,reasons:n}};export{R as analyzeCharacters,R as default};
|
package/dist/checks/mx.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { type C as Cache, type I as InMemoryCache, type M as MxCheckOptions, type b as MxCheckResult, type c as MxRecord, type d as MxResolution, e as checkMxRecords, e as default } from "../packem_shared/mx.d-
|
|
1
|
+
export { type C as Cache, type I as InMemoryCache, type M as MxCheckOptions, type b as MxCheckResult, type c as MxRecord, type d as MxResolution, e as checkMxRecords, e as default } from "../packem_shared/mx.d-HxIDdxvR.js";
|
package/dist/checks/mx.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{createRequire as
|
|
1
|
+
import{createRequire as f}from"node:module";let h;const v=e=>(h??=f(import.meta.url))(e),o=typeof globalThis<"u"&&typeof globalThis.process<"u"?globalThis.process:process,g=e=>{if(typeof o<"u"&&o.versions&&o.versions.node){const[r,s]=o.versions.node.split(".").map(Number);if(r>22||r===22&&s>=3||r===20&&s>=16)return o.getBuiltinModule(e)}return v(e)},{resolveMx:_,resolve4:y,resolve6:E}=g("node:dns/promises"),R=new Set(["EAI_AGAIN","ECONNREFUSED","EREFUSED","ESERVFAIL","ETIMEDOUT","ETIMEOUT"]),p=e=>{const{code:r}=e??{};return r!==void 0&&R.has(r)},l=async e=>{try{if((await y(e)).length>0)return!0}catch{}try{return(await E(e)).length>0}catch{return!1}},u=e=>({domainResolves:!0,records:[{exchange:e,priority:0}],resolvedVia:"address",valid:!0}),m=async(e,r)=>{try{const c=(await _(e)).map(t=>({exchange:t.exchange,priority:t.priority}));return c.length>0?{domainResolves:!0,records:c.toSorted((t,a)=>t.priority-a.priority),resolvedVia:"mx",valid:!0}:r&&await l(e)?u(e):{domainResolves:!1,records:[],resolvedVia:"none",valid:!1}}catch(s){return r&&await l(e)?u(e):{deferred:p(s),domainResolves:!1,error:s instanceof Error?s.message:String(s),resolvedVia:"none",valid:!1}}},i=new Map,A=async(e,r={})=>{const{fallbackToAddress:s=!0}=r,c=r.ttl??36e5,t=`${e}:${String(s)}`;if(r.cache){const n=await r.cache.get(t);if(n!==void 0)return n}const a=i.get(t);if(a)return a;const d=(async()=>{const n=await m(e,s);return r.cache&&!n.deferred&&await r.cache.set(t,n,c),n})();i.set(t,d);try{return await d}finally{i.delete(t)}};export{A as checkMxRecords,A as default};
|
package/dist/checks/role.d.ts
CHANGED
|
@@ -1,41 +1,41 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Local-part prefixes that indicate a no-reply / do-not-reply mailbox.
|
|
3
|
-
* These are a strict subset of {@link ROLE_ACCOUNT_PREFIXES}.
|
|
4
|
-
*/
|
|
2
|
+
* Local-part prefixes that indicate a no-reply / do-not-reply mailbox.
|
|
3
|
+
* These are a strict subset of {@link ROLE_ACCOUNT_PREFIXES}.
|
|
4
|
+
*/
|
|
5
5
|
declare const NO_REPLY_PREFIXES: ReadonlySet<string>;
|
|
6
6
|
/**
|
|
7
|
-
* Local-part prefixes that identify a role-based (shared, function) mailbox
|
|
8
|
-
* rather than a personal one. Superset of RFC 2142 plus common real-world roles.
|
|
9
|
-
*/
|
|
7
|
+
* Local-part prefixes that identify a role-based (shared, function) mailbox
|
|
8
|
+
* rather than a personal one. Superset of RFC 2142 plus common real-world roles.
|
|
9
|
+
*/
|
|
10
10
|
declare const ROLE_ACCOUNT_PREFIXES: ReadonlySet<string>;
|
|
11
11
|
/**
|
|
12
|
-
* Determines whether an email address is a role-based account.
|
|
13
|
-
*
|
|
14
|
-
* Matches the whole local part, the part before any `+tag`, and each
|
|
15
|
-
* dot/dash/underscore-separated token (so `sales.john`, `info+news`, and
|
|
16
|
-
* `no-reply` are all caught).
|
|
17
|
-
* @param email The email address to check.
|
|
18
|
-
* @param customPrefixes Optional additional role prefixes to recognize.
|
|
19
|
-
* @returns True when the address is a role account.
|
|
20
|
-
* @example
|
|
21
|
-
* ```ts
|
|
22
|
-
* import { isRoleAccount } from "@visulima/email-verifier/checks/role";
|
|
23
|
-
*
|
|
24
|
-
* isRoleAccount("info@example.com"); // true
|
|
25
|
-
* isRoleAccount("john.doe@example.com"); // false
|
|
26
|
-
* ```
|
|
27
|
-
*/
|
|
12
|
+
* Determines whether an email address is a role-based account.
|
|
13
|
+
*
|
|
14
|
+
* Matches the whole local part, the part before any `+tag`, and each
|
|
15
|
+
* dot/dash/underscore-separated token (so `sales.john`, `info+news`, and
|
|
16
|
+
* `no-reply` are all caught).
|
|
17
|
+
* @param email The email address to check.
|
|
18
|
+
* @param customPrefixes Optional additional role prefixes to recognize.
|
|
19
|
+
* @returns True when the address is a role account.
|
|
20
|
+
* @example
|
|
21
|
+
* ```ts
|
|
22
|
+
* import { isRoleAccount } from "@visulima/email-verifier/checks/role";
|
|
23
|
+
*
|
|
24
|
+
* isRoleAccount("info@example.com"); // true
|
|
25
|
+
* isRoleAccount("john.doe@example.com"); // false
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
28
|
declare const isRoleAccount: (email: string, customPrefixes?: Iterable<string>) => boolean;
|
|
29
29
|
/**
|
|
30
|
-
* Determines whether an email address is a no-reply / do-not-reply mailbox.
|
|
31
|
-
* @param email The email address to check.
|
|
32
|
-
* @returns True when the address is a no-reply mailbox.
|
|
33
|
-
* @example
|
|
34
|
-
* ```ts
|
|
35
|
-
* import { isNoReply } from "@visulima/email-verifier/checks/role";
|
|
36
|
-
*
|
|
37
|
-
* isNoReply("no-reply@example.com"); // true
|
|
38
|
-
* ```
|
|
39
|
-
*/
|
|
30
|
+
* Determines whether an email address is a no-reply / do-not-reply mailbox.
|
|
31
|
+
* @param email The email address to check.
|
|
32
|
+
* @returns True when the address is a no-reply mailbox.
|
|
33
|
+
* @example
|
|
34
|
+
* ```ts
|
|
35
|
+
* import { isNoReply } from "@visulima/email-verifier/checks/role";
|
|
36
|
+
*
|
|
37
|
+
* isNoReply("no-reply@example.com"); // true
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
40
|
declare const isNoReply: (email: string) => boolean;
|
|
41
41
|
export { NO_REPLY_PREFIXES, ROLE_ACCOUNT_PREFIXES, isRoleAccount as default, isNoReply, isRoleAccount };
|
package/dist/checks/role.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{splitAddress as
|
|
1
|
+
import{splitAddress as m}from"../packem_shared/extractDomain-C7YvhtJH.js";const p=new Set(["do-not-reply","do_not_reply","donotreply","no-reply","no_reply","noreply","notification","notifications","notify"]),i=new Set(["abuse","accounting","accounts","admin","administrator","all","billing","board","career","careers","ceo","cfo","compliance","contact","contacts","cto","customercare","customerservice","dev","developer","devnull","do-not-reply","do_not_reply","donotreply","enquiries","enquiry","everyone","feedback","finance","ftp","hello","help","helpdesk","hi","hostmaster","hr","info","information","inquiries","inquiry","investor","investors","it","jobs","legal","list","list-request","mail","mailer-daemon","mailerdaemon","majordomo","marketing","media","members","newsletter","no-reply","no_reply","noc","noreply","notification","notifications","notify","office","operations","order","orders","postmaster","press","privacy","purchasing","recruitment","register","registration","root","sales","secretary","security","service","services","shop","spam","staff","subscribe","support","sysadmin","team","tech","test","unsubscribe","usenet","uucp","webmaster","welcome","www"]),u=/[.\-_+]/,r=(o,e,t)=>e.has(o)||(t?.has(o)??!1),d=(o,e)=>{const t=m(o);if(!t)return!1;const{localPart:a}=t,c=a.split("+")[0],s=e?new Set([...e].map(n=>n.toLowerCase())):void 0;if(r(a,i,s)||r(c,i,s))return!0;const l=c.split(u).filter(Boolean);return l.length>1&&l.some(n=>r(n,i,s))},y=o=>{const e=m(o);if(!e)return!1;const t=e.localPart.split("+")[0];return r(e.localPart,p)||r(t,p)};export{p as NO_REPLY_PREFIXES,i as ROLE_ACCOUNT_PREFIXES,d as default,y as isNoReply,d as isRoleAccount};
|
package/dist/checks/smtp.d.ts
CHANGED
|
@@ -1,43 +1,43 @@
|
|
|
1
|
-
import { b as MxCheckResult, C as Cache, c as MxRecord } from "../packem_shared/mx.d-
|
|
1
|
+
import { b as MxCheckResult, C as Cache, c as MxRecord } from "../packem_shared/mx.d-HxIDdxvR.js";
|
|
2
2
|
/**
|
|
3
|
-
* Options for SMTP verification.
|
|
4
|
-
*/
|
|
3
|
+
* Options for SMTP verification.
|
|
4
|
+
*/
|
|
5
5
|
interface SmtpVerificationOptions {
|
|
6
6
|
/** Cache for the underlying MX lookup. */
|
|
7
7
|
cache?: Cache<MxCheckResult>;
|
|
8
8
|
/**
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
9
|
+
* Number of random, almost-certainly-nonexistent addresses to probe for
|
|
10
|
+
* catch-all detection. More probes reduce false positives from
|
|
11
|
+
* deferred-rejection servers. Set to 0 to disable.
|
|
12
|
+
* @default 1
|
|
13
|
+
*/
|
|
14
14
|
catchAllProbes?: number;
|
|
15
15
|
/**
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
* MAIL FROM address used during the probe; defaults to `verify@` followed by
|
|
17
|
+
* the HELO host.
|
|
18
|
+
*/
|
|
19
19
|
fromEmail?: string;
|
|
20
20
|
/**
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
* HELO/EHLO hostname presented to the remote server.
|
|
22
|
+
* @default the address domain
|
|
23
|
+
*/
|
|
24
24
|
heloHost?: string;
|
|
25
25
|
/**
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
26
|
+
* Pre-resolved MX records to probe, in priority order. When provided, the
|
|
27
|
+
* probe skips its own DNS lookup — the orchestrator passes the records it
|
|
28
|
+
* already resolved so the domain is not queried twice.
|
|
29
|
+
*/
|
|
30
30
|
mxRecords?: MxRecord[];
|
|
31
31
|
port?: number;
|
|
32
32
|
/**
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
33
|
+
* Number of times to retry the whole probe on a temporary (greylist) failure.
|
|
34
|
+
* @default 1
|
|
35
|
+
*/
|
|
36
36
|
retries?: number;
|
|
37
37
|
/**
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
38
|
+
* Delay in milliseconds between greylist retries.
|
|
39
|
+
* @default 5000
|
|
40
|
+
*/
|
|
41
41
|
retryDelay?: number;
|
|
42
42
|
/** Cache for SMTP results. */
|
|
43
43
|
smtpCache?: Cache<SmtpVerificationResult>;
|
|
@@ -45,8 +45,8 @@ interface SmtpVerificationOptions {
|
|
|
45
45
|
ttl?: number;
|
|
46
46
|
}
|
|
47
47
|
/**
|
|
48
|
-
* Detailed result of an SMTP verification attempt.
|
|
49
|
-
*/
|
|
48
|
+
* Detailed result of an SMTP verification attempt.
|
|
49
|
+
*/
|
|
50
50
|
interface SmtpVerificationResult {
|
|
51
51
|
/** True when the server accepts a random, nonexistent recipient (catch-all). */
|
|
52
52
|
acceptAll?: boolean;
|
|
@@ -64,30 +64,5 @@ interface SmtpVerificationResult {
|
|
|
64
64
|
/** True when the real RCPT TO was accepted (250). */
|
|
65
65
|
valid: boolean;
|
|
66
66
|
}
|
|
67
|
-
/**
|
|
68
|
-
* Verifies an email address over SMTP without sending a message.
|
|
69
|
-
*
|
|
70
|
-
* Performs the full handshake (greeting → EHLO/HELO → MAIL FROM → RCPT TO),
|
|
71
|
-
* then — when the real recipient is accepted — issues additional RCPT TO probes
|
|
72
|
-
* for random addresses to detect catch-all (accept-all) servers. Temporary
|
|
73
|
-
* (4xx) failures are surfaced as `deferred` and retried up to `retries` times to
|
|
74
|
-
* survive greylisting, and over-quota responses set `mailboxFull`.
|
|
75
|
-
*
|
|
76
|
-
* Note: many networks block outbound port 25 and many servers refuse or tarpit
|
|
77
|
-
* verification probes, so treat a `deferred`/errored result as inconclusive
|
|
78
|
-
* rather than undeliverable.
|
|
79
|
-
* @param email The email address to verify.
|
|
80
|
-
* @param options Verification options.
|
|
81
|
-
* @returns The detailed SMTP verification result.
|
|
82
|
-
* @example
|
|
83
|
-
* ```ts
|
|
84
|
-
* import { verifySmtp } from "@visulima/email-verifier/checks/smtp";
|
|
85
|
-
*
|
|
86
|
-
* const result = await verifySmtp("user@example.com", { catchAllProbes: 2 });
|
|
87
|
-
* if (result.valid && !result.acceptAll) {
|
|
88
|
-
* console.log("Mailbox exists");
|
|
89
|
-
* }
|
|
90
|
-
* ```
|
|
91
|
-
*/
|
|
92
67
|
declare const verifySmtp: (email: string, options?: SmtpVerificationOptions) => Promise<SmtpVerificationResult>;
|
|
93
68
|
export { type SmtpVerificationOptions, type SmtpVerificationResult, verifySmtp as default, verifySmtp };
|
package/dist/checks/smtp.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import{createRequire as
|
|
1
|
+
import{createRequire as b}from"node:module";import{splitAddress as T}from"../packem_shared/extractDomain-C7YvhtJH.js";import{checkMxRecords as j}from"./mx.js";let _;const x=r=>(_??=b(import.meta.url))(r),h=typeof globalThis<"u"&&typeof globalThis.process<"u"?globalThis.process:process,L=r=>{if(typeof h<"u"&&h.versions&&h.versions.node){const[e,t]=h.versions.node.split(".").map(Number);if(e>22||e===22&&t>=3||e===20&&t>=16)return h.getBuiltinModule(r)}return x(r)},{Socket:C}=L("node:net"),E=/[\u0000-\u001F\u007F]/,M=/\b([245]\.\d{1,3}\.\d{1,3})\b/,P=/^(\d{3})(?: |$)/,$=/\r?\n/,R="abcdefghijklmnopqrstuvwxyz0123456789",A=(r=20)=>{let e="";for(let t=0;t<r;t+=1)e+=R[Math.floor(Math.random()*R.length)]??"";return e},S=async r=>new Promise(e=>{setTimeout(e,r)});class H{transcript="";buffer="";completed=[];failure;finished=!1;socket;waiter;constructor(e){this.socket=e,e.on("data",n=>{this.transcript+=n.toString(),this.buffer+=n.toString(),this.drain()});const t=n=>{this.finished=!0,this.failure=n??new Error("Connection closed by server"),this.completed.length===0&&this.waiter&&(this.waiter.reject(this.failure),this.waiter=void 0)};e.on("error",t),e.on("close",()=>{t()}),e.on("timeout",()=>{t(new Error("SMTP socket timeout")),e.destroy()})}async command(e){return this.transcript+=`${e}\r
|
|
2
2
|
`,this.socket.write(`${e}\r
|
|
3
3
|
`),this.readReply()}close(){try{this.socket.write(`QUIT\r
|
|
4
|
-
`)}catch{}this.socket.removeAllListeners(),this.socket.destroy()}async readReply(){if(this.completed.length>0)return this.completed.shift();if(this.finished)throw this.failure??new Error("Connection closed");return new Promise((e,t)=>{this.waiter={reject:t,resolve:e}})}drain(){const e=this.buffer.split(
|
|
5
|
-
`),
|
|
4
|
+
`)}catch{}this.socket.removeAllListeners(),this.socket.destroy()}async readReply(){if(this.completed.length>0)return this.completed.shift();if(this.finished)throw this.failure??new Error("Connection closed");return new Promise((e,t)=>{this.waiter={reject:t,resolve:e}})}drain(){const e=this.buffer.split($);this.buffer=e.pop()??"";let t=[];for(const n of e){t.push(n);const c=P.exec(n);if(c){const o=t.join(`
|
|
5
|
+
`),l=M.exec(o)?.[1];this.completed.push({code:Number.parseInt(c[1],10),enhanced:l,text:o}),t=[]}}if(t.length>0&&(this.buffer=`${t.join(`
|
|
6
6
|
`)}
|
|
7
|
-
${this.buffer}`),this.waiter&&this.completed.length>0){const{resolve:
|
|
7
|
+
${this.buffer}`),this.waiter&&this.completed.length>0){const{resolve:n}=this.waiter;this.waiter=void 0,n(this.completed.shift())}}}const I=r=>{const{code:e,enhanced:t}=r;return e>=200&&e<300?{code:e,enhancedCode:t,valid:!0}:e===452||e===552||t==="4.2.2"||t==="5.2.2"?{code:e,deferred:e===452,enhancedCode:t,mailboxFull:!0,valid:!1}:e>=400&&e<500?{code:e,deferred:!0,enhancedCode:t,valid:!1}:{code:e,enhancedCode:t,valid:!1}},O=async(r,e,t)=>new Promise((n,c)=>{const o=new C;o.setTimeout(t);const l=a=>{o.removeAllListeners(),o.destroy(),c(a)},i=()=>{l(new Error("SMTP connection timeout"))};o.once("error",l),o.once("timeout",i),o.connect(e,r,()=>{o.removeListener("error",l),o.removeListener("timeout",i),n(new H(o))})}),k=async(r,e,t,n)=>{const{catchAllProbes:c=1,port:o=25,timeout:l=5e3}=n,i=n.heloHost??e,a=n.fromEmail??`verify@${i}`;let d;try{d=await O(t.exchange,o,l);const m=await d.readReply();if(m.code!==220)return{connectionLevel:!0,deferred:!0,error:`Unexpected greeting: ${m.text}`,valid:!1};let s=await d.command(`EHLO ${i}`);if(s.code!==250&&(s=await d.command(`HELO ${i}`),s.code!==250))return{connectionLevel:!0,deferred:!0,error:`HELO rejected: ${s.text}`,valid:!1};const u=await d.command(`MAIL FROM:<${a}>`);if(u.code!==250)return{connectionLevel:!0,deferred:!0,error:`MAIL FROM rejected: ${u.text}`,valid:!1};const f=await d.command(`RCPT TO:<${r}>`),w=I(f);let p;if(w.valid&&c>0){p=!0;for(let g=0;g<c;g+=1){const y=await d.command(`RCPT TO:<${A()}@${e}>`);if(y.code<200||y.code>=300){p=!1;break}}}return{...w,acceptAll:p,smtpResponse:d.transcript}}finally{d?.close()}},N=async(r,e,t,n)=>{let c="SMTP verification did not complete",o;for(const l of t){let i;try{i=await k(r,e,l,n)}catch(a){c=a instanceof Error?a.message:String(a);continue}if(i.connectionLevel){o=i;continue}return i}if(o){const{connectionLevel:l,...i}=o;return i}return{deferred:!0,error:c,valid:!1}},F=r=>{if(r.heloHost!==void 0&&E.test(r.heloHost))return{error:"Invalid heloHost: control characters are not allowed",valid:!1};if(r.fromEmail!==void 0&&E.test(r.fromEmail))return{error:"Invalid fromEmail: control characters are not allowed",valid:!1}},v=new Map,B=async(r,e={})=>{const t=T(r);if(!t)return{error:"Invalid email format",valid:!1};const{domain:n}=t,c=F(e);if(c)return c;const{retries:o=1,retryDelay:l=5e3,ttl:i=36e5}=e,a=["smtp",t.address,e.fromEmail??"",String(e.port??25),e.heloHost??"",String(e.catchAllProbes??1),(e.mxRecords??[]).map(s=>s.exchange).join(",")].join("|");if(e.smtpCache){const s=await e.smtpCache.get(a);if(s!==void 0)return s}const d=v.get(a);if(d)return d;const m=(async()=>{let s=e.mxRecords;if(!s||s.length===0){const f=await j(n,{cache:e.cache,fallbackToAddress:!1});if(!f.valid||!f.records||f.records.length===0)return{error:f.error??"No MX records found",mxRecords:f.records,valid:!1};s=f.records}let u={error:"SMTP verification did not complete",valid:!1};for(let f=0;f<=o&&(u=await N(t.address,n,s,e),!(!u.deferred||f===o));f+=1)await S(l);return u={...u,mxRecords:s},e.smtpCache&&!u.deferred&&await e.smtpCache.set(a,u,i),u})();v.set(a,m);try{return await m}finally{v.delete(a)}};export{B as default,B as verifySmtp};
|
package/dist/checks/symbol.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The result of symbol / Unicode analysis.
|
|
3
|
-
*/
|
|
2
|
+
* The result of symbol / Unicode analysis.
|
|
3
|
+
*/
|
|
4
4
|
interface SymbolResult {
|
|
5
5
|
/** True when the address mixes Unicode scripts (a homoglyph-spoofing signal). */
|
|
6
6
|
hasMixedScripts: boolean;
|
|
@@ -12,18 +12,18 @@ interface SymbolResult {
|
|
|
12
12
|
scripts: string[];
|
|
13
13
|
}
|
|
14
14
|
/**
|
|
15
|
-
* Detects symbols, emoji, and mixed Unicode scripts in an email address.
|
|
16
|
-
*
|
|
17
|
-
* Mixed-script local parts (e.g. Latin + Cyrillic) are a classic homoglyph /
|
|
18
|
-
* spoofing signal; symbol or emoji characters indicate a non-standard address.
|
|
19
|
-
* @param email The email address to analyze.
|
|
20
|
-
* @returns The symbol analysis result.
|
|
21
|
-
* @example
|
|
22
|
-
* ```ts
|
|
23
|
-
* import { analyzeSymbols } from "@visulima/email-verifier/checks/symbol";
|
|
24
|
-
*
|
|
25
|
-
* analyzeSymbols("раypal@example.com").hasMixedScripts; // true (Cyrillic "ра")
|
|
26
|
-
* ```
|
|
27
|
-
*/
|
|
15
|
+
* Detects symbols, emoji, and mixed Unicode scripts in an email address.
|
|
16
|
+
*
|
|
17
|
+
* Mixed-script local parts (e.g. Latin + Cyrillic) are a classic homoglyph /
|
|
18
|
+
* spoofing signal; symbol or emoji characters indicate a non-standard address.
|
|
19
|
+
* @param email The email address to analyze.
|
|
20
|
+
* @returns The symbol analysis result.
|
|
21
|
+
* @example
|
|
22
|
+
* ```ts
|
|
23
|
+
* import { analyzeSymbols } from "@visulima/email-verifier/checks/symbol";
|
|
24
|
+
*
|
|
25
|
+
* analyzeSymbols("раypal@example.com").hasMixedScripts; // true (Cyrillic "ра")
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
28
|
declare const analyzeSymbols: (email: string) => SymbolResult;
|
|
29
29
|
export { type SymbolResult, analyzeSymbols, analyzeSymbols as default };
|
package/dist/checks/symbol.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{splitAddress as
|
|
1
|
+
import{splitAddress as r}from"../packem_shared/extractDomain-C7YvhtJH.js";const c=new RegExp("\\P{ASCII}","u"),l=new RegExp("\\p{S}","u"),a=[["Latin",new RegExp("\\p{Script=Latin}","u")],["Cyrillic",new RegExp("\\p{Script=Cyrillic}","u")],["Greek",new RegExp("\\p{Script=Greek}","u")],["Han",new RegExp("\\p{Script=Han}","u")],["Hiragana",new RegExp("\\p{Script=Hiragana}","u")],["Katakana",new RegExp("\\p{Script=Katakana}","u")],["Hangul",new RegExp("\\p{Script=Hangul}","u")],["Arabic",new RegExp("\\p{Script=Arabic}","u")],["Hebrew",new RegExp("\\p{Script=Hebrew}","u")]],E=n=>{const e=r(n);if(!e)return{hasMixedScripts:!1,hasNonAscii:!1,hasSymbols:!1,scripts:[]};const s=`${e.localPart}${e.domain}`,p=a.filter(([,t])=>t.test(s)).map(([t])=>t);return{hasMixedScripts:[e.localPart,...e.domain.split(".").filter(Boolean)].some(t=>a.filter(([,i])=>i.test(t)).length>1),hasNonAscii:c.test(e.address),hasSymbols:l.test(s),scripts:p}};export{E as analyzeSymbols,E as default};
|
package/dist/checks/syntax.d.ts
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Validates an email address format according to basic RFC standards.
|
|
3
|
-
*
|
|
4
|
-
* This is intentionally pragmatic rather than a full RFC 5322 parser: it rejects
|
|
5
|
-
* the address shapes that never deliver (missing parts, consecutive dots, leading
|
|
6
|
-
* or trailing dots, hyphen-bounded domain labels) while accepting the long tail
|
|
7
|
-
* of legitimate real-world addresses.
|
|
8
|
-
* @param email The email address string to validate.
|
|
9
|
-
* @returns True if the email address is syntactically valid, false otherwise.
|
|
10
|
-
* @example
|
|
11
|
-
* ```ts
|
|
12
|
-
* import { validateSyntax } from "@visulima/email-verifier/checks/syntax";
|
|
13
|
-
*
|
|
14
|
-
* validateSyntax("user@example.com"); // true
|
|
15
|
-
* validateSyntax("user@@example.com"); // false
|
|
16
|
-
* ```
|
|
17
|
-
*/
|
|
2
|
+
* Validates an email address format according to basic RFC standards.
|
|
3
|
+
*
|
|
4
|
+
* This is intentionally pragmatic rather than a full RFC 5322 parser: it rejects
|
|
5
|
+
* the address shapes that never deliver (missing parts, consecutive dots, leading
|
|
6
|
+
* or trailing dots, hyphen-bounded domain labels) while accepting the long tail
|
|
7
|
+
* of legitimate real-world addresses.
|
|
8
|
+
* @param email The email address string to validate.
|
|
9
|
+
* @returns True if the email address is syntactically valid, false otherwise.
|
|
10
|
+
* @example
|
|
11
|
+
* ```ts
|
|
12
|
+
* import { validateSyntax } from "@visulima/email-verifier/checks/syntax";
|
|
13
|
+
*
|
|
14
|
+
* validateSyntax("user@example.com"); // true
|
|
15
|
+
* validateSyntax("user@@example.com"); // false
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
18
|
declare const validateSyntax: (email: string) => boolean;
|
|
19
19
|
export { validateSyntax as default, validateSyntax };
|
package/dist/checks/syntax.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{splitAddress as
|
|
1
|
+
import{splitAddress as i}from"../packem_shared/extractDomain-C7YvhtJH.js";const f=/^[^\s@]+@[^\s@][^\s.@]*\.[^\s@]+$/,a=/^[\p{L}\p{N}-]+$/u,u=t=>{if(!t||typeof t!="string"||!f.test(t)||t.includes(".."))return!1;const e=i(t);if(!e)return!1;const{domain:s,localPart:n}=e;return n.startsWith(".")||n.endsWith(".")||!s.includes(".")||s.startsWith("-")||s.endsWith("-")?!1:s.split(".").every(r=>r.length>0&&!r.startsWith("-")&&!r.endsWith("-")&&a.test(r))};export{u as default,u as validateSyntax};
|
package/dist/checks/tag.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The result of sub-address (tag) detection.
|
|
3
|
-
*/
|
|
2
|
+
* The result of sub-address (tag) detection.
|
|
3
|
+
*/
|
|
4
4
|
interface TagResult {
|
|
5
5
|
/** The local part with the tag and separator removed (the "real" mailbox). */
|
|
6
6
|
baseLocalPart: string;
|
|
@@ -12,20 +12,20 @@ interface TagResult {
|
|
|
12
12
|
tag?: string;
|
|
13
13
|
}
|
|
14
14
|
/**
|
|
15
|
-
* Detects plus-addressing / sub-addressing tags in an email address.
|
|
16
|
-
*
|
|
17
|
-
* Most providers (Gmail, Outlook, iCloud, Proton, …) delimit the tag with `+`;
|
|
18
|
-
* a few (Fastmail, Yahoo) use `-`. The returned {@link TagResult.baseLocalPart}
|
|
19
|
-
* is the canonical mailbox with the tag stripped.
|
|
20
|
-
* @param email The email address to inspect.
|
|
21
|
-
* @returns The tag detection result.
|
|
22
|
-
* @example
|
|
23
|
-
* ```ts
|
|
24
|
-
* import { detectTag } from "@visulima/email-verifier/checks/tag";
|
|
25
|
-
*
|
|
26
|
-
* detectTag("user+newsletter@gmail.com");
|
|
27
|
-
* // { hasTag: true, tag: "newsletter", separator: "+", baseLocalPart: "user" }
|
|
28
|
-
* ```
|
|
29
|
-
*/
|
|
15
|
+
* Detects plus-addressing / sub-addressing tags in an email address.
|
|
16
|
+
*
|
|
17
|
+
* Most providers (Gmail, Outlook, iCloud, Proton, …) delimit the tag with `+`;
|
|
18
|
+
* a few (Fastmail, Yahoo) use `-`. The returned {@link TagResult.baseLocalPart}
|
|
19
|
+
* is the canonical mailbox with the tag stripped.
|
|
20
|
+
* @param email The email address to inspect.
|
|
21
|
+
* @returns The tag detection result.
|
|
22
|
+
* @example
|
|
23
|
+
* ```ts
|
|
24
|
+
* import { detectTag } from "@visulima/email-verifier/checks/tag";
|
|
25
|
+
*
|
|
26
|
+
* detectTag("user+newsletter@gmail.com");
|
|
27
|
+
* // { hasTag: true, tag: "newsletter", separator: "+", baseLocalPart: "user" }
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
30
|
declare const detectTag: (email: string) => TagResult;
|
|
31
31
|
export { type TagResult, detectTag as default, detectTag };
|
package/dist/checks/tag.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{splitAddress as c}from"../packem_shared/extractDomain-
|
|
1
|
+
import{splitAddress as c}from"../packem_shared/extractDomain-C7YvhtJH.js";const l=new Set(["fastmail.com","fastmail.fm","yahoo.co.uk","yahoo.com"]),i=o=>{const e=c(o);if(!e)return{baseLocalPart:"",hasTag:!1};const{domain:r,localPart:a}=e,s=a.indexOf("+");if(s>0)return{baseLocalPart:a.slice(0,s),hasTag:!0,separator:"+",tag:a.slice(s+1)};if(l.has(r)){const t=a.indexOf("-");if(t>0)return{baseLocalPart:a.slice(0,t),hasTag:!0,separator:"-",tag:a.slice(t+1)}}return{baseLocalPart:a,hasTag:!1}};export{i as default,i as detectTag};
|
package/dist/enrich/name.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* A name parsed from an email's local part.
|
|
3
|
-
*/
|
|
2
|
+
* A name parsed from an email's local part.
|
|
3
|
+
*/
|
|
4
4
|
interface NameResult {
|
|
5
5
|
/** Confidence in the parse: `high` (clear separator), `medium` (camelCase), `low` (heuristic), `none`. */
|
|
6
6
|
confidence: "high" | "low" | "medium" | "none";
|
|
@@ -12,21 +12,21 @@ interface NameResult {
|
|
|
12
12
|
lastName?: string;
|
|
13
13
|
}
|
|
14
14
|
/**
|
|
15
|
-
* Heuristically parses a person's name from the local part of an email address.
|
|
16
|
-
*
|
|
17
|
-
* Handles separator-delimited (`john.doe`), camelCase (`johnDoe`), and
|
|
18
|
-
* single-token local parts, stripping trailing digits. This is best-effort name
|
|
19
|
-
* parsing only — no gender detection — and confidence is reported so callers
|
|
20
|
-
* can decide how much to trust it.
|
|
21
|
-
* @param email The email address to parse.
|
|
22
|
-
* @returns The parsed name and a confidence level.
|
|
23
|
-
* @example
|
|
24
|
-
* ```ts
|
|
25
|
-
* import { parseName } from "@visulima/email-verifier/enrich/name";
|
|
26
|
-
*
|
|
27
|
-
* parseName("john.doe@example.com");
|
|
28
|
-
* // { firstName: "John", lastName: "Doe", fullName: "John Doe", confidence: "high" }
|
|
29
|
-
* ```
|
|
30
|
-
*/
|
|
15
|
+
* Heuristically parses a person's name from the local part of an email address.
|
|
16
|
+
*
|
|
17
|
+
* Handles separator-delimited (`john.doe`), camelCase (`johnDoe`), and
|
|
18
|
+
* single-token local parts, stripping trailing digits. This is best-effort name
|
|
19
|
+
* parsing only — no gender detection — and confidence is reported so callers
|
|
20
|
+
* can decide how much to trust it.
|
|
21
|
+
* @param email The email address to parse.
|
|
22
|
+
* @returns The parsed name and a confidence level.
|
|
23
|
+
* @example
|
|
24
|
+
* ```ts
|
|
25
|
+
* import { parseName } from "@visulima/email-verifier/enrich/name";
|
|
26
|
+
*
|
|
27
|
+
* parseName("john.doe@example.com");
|
|
28
|
+
* // { firstName: "John", lastName: "Doe", fullName: "John Doe", confidence: "high" }
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
31
|
declare const parseName: (email: string) => NameResult;
|
|
32
32
|
export { type NameResult, parseName as default, parseName };
|
package/dist/enrich/name.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{splitAddress as
|
|
1
|
+
import{splitAddress as m}from"../packem_shared/extractDomain-C7YvhtJH.js";const f=/[.\-_]/,u=/^[a-z]+(?:[A-Z][a-z]+)+$/,d=/\d+$/,A=/\d/,r=e=>e.length===0?e:e.charAt(0).toUpperCase()+e.slice(1).toLowerCase(),E=e=>e.replaceAll(/([a-z])([A-Z])/g,"$1 $2").split(" "),_=e=>{const l=m(e);if(!l)return{confidence:"none"};const a=e.trim().lastIndexOf("@"),t=(a>0?e.trim().slice(0,a):l.localPart).split("+")[0].replace(d,"");if(t.length===0)return{confidence:"none"};let s,c;if(f.test(t))s=t.split(f).filter(Boolean),c="high";else if(u.test(t))s=E(t),c="medium";else return A.test(t)?{confidence:"none"}:{confidence:"low",firstName:r(t),fullName:r(t)};const n=s.map(p=>p.replace(d,"")).filter(Boolean);if(n.length===0)return{confidence:"none"};const o=r(n[0]);if(n.length===1)return{confidence:"low",firstName:o,fullName:o};const i=r(n.at(-1));return{confidence:c,firstName:o,fullName:`${o} ${i}`,lastName:i}};export{_ as default,_ as parseName};
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { MxProviderInfo } from '@visulima/email-provider-mx';
|
|
2
2
|
export { type MxProviderInfo, classifyMx, classifyMxRecords, isSecureEmailGateway } from '@visulima/email-provider-mx';
|
|
3
|
-
import { c as MxRecord, b as MxCheckResult, C as Cache } from "../packem_shared/mx.d-
|
|
3
|
+
import { c as MxRecord, b as MxCheckResult, C as Cache } from "../packem_shared/mx.d-HxIDdxvR.js";
|
|
4
4
|
/**
|
|
5
|
-
* The enriched provider details for an email address.
|
|
6
|
-
*/
|
|
5
|
+
* The enriched provider details for an email address.
|
|
6
|
+
*/
|
|
7
7
|
interface ProviderDetails {
|
|
8
8
|
/** True when the resolving MX is a Secure Email Gateway (Proofpoint, Mimecast, …). */
|
|
9
9
|
isSecureEmailGateway: boolean;
|
|
@@ -13,28 +13,28 @@ interface ProviderDetails {
|
|
|
13
13
|
provider?: MxProviderInfo;
|
|
14
14
|
}
|
|
15
15
|
/**
|
|
16
|
-
* Options for provider enrichment.
|
|
17
|
-
*/
|
|
16
|
+
* Options for provider enrichment.
|
|
17
|
+
*/
|
|
18
18
|
interface ProviderEnrichOptions {
|
|
19
19
|
cache?: Cache<MxCheckResult>;
|
|
20
20
|
ttl?: number;
|
|
21
21
|
}
|
|
22
22
|
/**
|
|
23
|
-
* Resolves an email address's mailbox/SEG provider from its MX records.
|
|
24
|
-
*
|
|
25
|
-
* Looks up the domain's MX records, then classifies the highest-priority host
|
|
26
|
-
* via `@visulima/email-provider-mx` — emailable's "SMTP Provider Details" plus
|
|
27
|
-
* Secure-Email-Gateway detection.
|
|
28
|
-
* @param email The email address to enrich.
|
|
29
|
-
* @param options Caching options for the MX lookup.
|
|
30
|
-
* @returns The provider details, including the MX records used.
|
|
31
|
-
* @example
|
|
32
|
-
* ```ts
|
|
33
|
-
* import { enrichProvider } from "@visulima/email-verifier/enrich/provider";
|
|
34
|
-
*
|
|
35
|
-
* const details = await enrichProvider("user@gmail.com");
|
|
36
|
-
* console.log(details.provider?.display); // "Google"
|
|
37
|
-
* ```
|
|
38
|
-
*/
|
|
23
|
+
* Resolves an email address's mailbox/SEG provider from its MX records.
|
|
24
|
+
*
|
|
25
|
+
* Looks up the domain's MX records, then classifies the highest-priority host
|
|
26
|
+
* via `@visulima/email-provider-mx` — emailable's "SMTP Provider Details" plus
|
|
27
|
+
* Secure-Email-Gateway detection.
|
|
28
|
+
* @param email The email address to enrich.
|
|
29
|
+
* @param options Caching options for the MX lookup.
|
|
30
|
+
* @returns The provider details, including the MX records used.
|
|
31
|
+
* @example
|
|
32
|
+
* ```ts
|
|
33
|
+
* import { enrichProvider } from "@visulima/email-verifier/enrich/provider";
|
|
34
|
+
*
|
|
35
|
+
* const details = await enrichProvider("user@gmail.com");
|
|
36
|
+
* console.log(details.provider?.display); // "Google"
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
39
|
declare const enrichProvider: (email: string, options?: ProviderEnrichOptions) => Promise<ProviderDetails>;
|
|
40
40
|
export { type ProviderDetails, type ProviderEnrichOptions, enrichProvider as default, enrichProvider };
|
package/dist/enrich/provider.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{classifyMxRecords as t}from"@visulima/email-provider-mx";import{classifyMx as
|
|
1
|
+
import{classifyMxRecords as t}from"@visulima/email-provider-mx";import{classifyMx as u,classifyMxRecords as h,isSecureEmailGateway as p}from"@visulima/email-provider-mx";import{checkMxRecords as o}from"../checks/mx.js";import{extractDomain as i}from"../packem_shared/extractDomain-C7YvhtJH.js";const n=async(s,r={})=>{const a=i(s);if(!a)return{isSecureEmailGateway:!1,mxRecords:[]};const e=(await o(a,{cache:r.cache,fallbackToAddress:!1,ttl:r.ttl})).records??[];if(e.length===0)return{isSecureEmailGateway:!1,mxRecords:e};const c=t(e);return{isSecureEmailGateway:c?.type==="seg",mxRecords:e,provider:c}};export{u as classifyMx,h as classifyMxRecords,n as default,n as enrichProvider,p as isSecureEmailGateway};
|