mailintel 0.2.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/LICENSE +21 -0
- package/README.md +240 -0
- package/dist/cli.js +728 -0
- package/dist/index.cjs +573 -0
- package/dist/index.d.cts +70 -0
- package/dist/index.d.ts +70 -0
- package/dist/index.js +569 -0
- package/package.json +62 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,573 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// src/dns.ts
|
|
4
|
+
var RESOLVERS = {
|
|
5
|
+
cloudflare: "https://cloudflare-dns.com/dns-query",
|
|
6
|
+
google: "https://dns.google/resolve"
|
|
7
|
+
};
|
|
8
|
+
async function lookupMx(domain, options = {}) {
|
|
9
|
+
const resolver = options.resolver ?? "cloudflare";
|
|
10
|
+
const timeout = options.timeout ?? 5e3;
|
|
11
|
+
const fetchFn = options.fetch ?? globalThis.fetch;
|
|
12
|
+
const url = `${RESOLVERS[resolver]}?name=${encodeURIComponent(domain)}&type=MX`;
|
|
13
|
+
const controller = new AbortController();
|
|
14
|
+
const timer = setTimeout(() => controller.abort(), timeout);
|
|
15
|
+
try {
|
|
16
|
+
const response = await fetchFn(url, {
|
|
17
|
+
headers: { Accept: "application/dns-json" },
|
|
18
|
+
signal: controller.signal
|
|
19
|
+
});
|
|
20
|
+
if (!response.ok) {
|
|
21
|
+
return { records: [], raw: {} };
|
|
22
|
+
}
|
|
23
|
+
const data = await response.json();
|
|
24
|
+
const records = (data.Answer ?? []).filter((r) => r.type === 15).map((r) => {
|
|
25
|
+
const parts = r.data.split(" ");
|
|
26
|
+
return {
|
|
27
|
+
priority: parseInt(parts[0], 10),
|
|
28
|
+
exchange: parts[1]?.replace(/\.$/, "") ?? ""
|
|
29
|
+
};
|
|
30
|
+
}).sort((a, b) => a.priority - b.priority);
|
|
31
|
+
return { records, raw: data };
|
|
32
|
+
} catch {
|
|
33
|
+
return { records: [], raw: {} };
|
|
34
|
+
} finally {
|
|
35
|
+
clearTimeout(timer);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// src/ispdb.ts
|
|
40
|
+
var ISPDB_URL = "https://autoconfig.thunderbird.net/v1.1";
|
|
41
|
+
async function lookupIspdb(domain, options = {}) {
|
|
42
|
+
const timeout = options.timeout ?? 5e3;
|
|
43
|
+
const fetchFn = options.fetch ?? globalThis.fetch;
|
|
44
|
+
const url = `${ISPDB_URL}/${encodeURIComponent(domain)}`;
|
|
45
|
+
const controller = new AbortController();
|
|
46
|
+
const timer = setTimeout(() => controller.abort(), timeout);
|
|
47
|
+
try {
|
|
48
|
+
const response = await fetchFn(url, { signal: controller.signal });
|
|
49
|
+
if (!response.ok) {
|
|
50
|
+
return { connection: null, raw: null };
|
|
51
|
+
}
|
|
52
|
+
const xml = await response.text();
|
|
53
|
+
const connection = parseIspdbXml(xml);
|
|
54
|
+
return { connection, raw: xml };
|
|
55
|
+
} catch {
|
|
56
|
+
return { connection: null, raw: null };
|
|
57
|
+
} finally {
|
|
58
|
+
clearTimeout(timer);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
function parseIspdbXml(xml) {
|
|
62
|
+
const imapMatch = xml.match(/<incomingServer type="imap">([\s\S]*?)<\/incomingServer>/);
|
|
63
|
+
const smtpMatch = xml.match(/<outgoingServer type="smtp">([\s\S]*?)<\/outgoingServer>/);
|
|
64
|
+
if (!imapMatch || !smtpMatch) return null;
|
|
65
|
+
const imapBlock = imapMatch[1];
|
|
66
|
+
const smtpBlock = smtpMatch[1];
|
|
67
|
+
const imapHost = imapBlock.match(/<hostname>(.*?)<\/hostname>/)?.[1];
|
|
68
|
+
const imapPort = imapBlock.match(/<port>(.*?)<\/port>/)?.[1];
|
|
69
|
+
const imapSocket = imapBlock.match(/<socketType>(.*?)<\/socketType>/)?.[1];
|
|
70
|
+
const smtpHost = smtpBlock.match(/<hostname>(.*?)<\/hostname>/)?.[1];
|
|
71
|
+
const smtpPort = smtpBlock.match(/<port>(.*?)<\/port>/)?.[1];
|
|
72
|
+
const smtpSocket = smtpBlock.match(/<socketType>(.*?)<\/socketType>/)?.[1];
|
|
73
|
+
const username = xml.match(/<username>(.*?)<\/username>/)?.[1] ?? "%EMAILADDRESS%";
|
|
74
|
+
if (!imapHost || !imapPort || !smtpHost || !smtpPort) return null;
|
|
75
|
+
return {
|
|
76
|
+
imap: {
|
|
77
|
+
host: imapHost,
|
|
78
|
+
port: parseInt(imapPort, 10),
|
|
79
|
+
secure: imapSocket === "SSL"
|
|
80
|
+
},
|
|
81
|
+
smtp: {
|
|
82
|
+
host: smtpHost,
|
|
83
|
+
port: parseInt(smtpPort, 10),
|
|
84
|
+
secure: smtpSocket === "SSL" || smtpSocket === "STARTTLS"
|
|
85
|
+
},
|
|
86
|
+
username
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// src/data/domains.ts
|
|
91
|
+
var KNOWN_DOMAINS = {
|
|
92
|
+
// Google
|
|
93
|
+
"gmail.com": "google",
|
|
94
|
+
"googlemail.com": "google",
|
|
95
|
+
// Microsoft
|
|
96
|
+
"outlook.com": "microsoft",
|
|
97
|
+
"hotmail.com": "microsoft",
|
|
98
|
+
"live.com": "microsoft",
|
|
99
|
+
"msn.com": "microsoft",
|
|
100
|
+
"hotmail.co.uk": "microsoft",
|
|
101
|
+
"hotmail.fr": "microsoft",
|
|
102
|
+
"outlook.co.uk": "microsoft",
|
|
103
|
+
// Yahoo
|
|
104
|
+
"yahoo.com": "yahoo",
|
|
105
|
+
"yahoo.co.uk": "yahoo",
|
|
106
|
+
"yahoo.fr": "yahoo",
|
|
107
|
+
"yahoo.de": "yahoo",
|
|
108
|
+
"yahoo.co.jp": "yahoo",
|
|
109
|
+
"ymail.com": "yahoo",
|
|
110
|
+
"rocketmail.com": "yahoo",
|
|
111
|
+
// Zoho
|
|
112
|
+
"zoho.com": "zoho",
|
|
113
|
+
"zohomail.com": "zoho",
|
|
114
|
+
"zoho.eu": "zoho",
|
|
115
|
+
"zoho.in": "zoho",
|
|
116
|
+
"zoho.com.au": "zoho",
|
|
117
|
+
"zoho.jp": "zoho",
|
|
118
|
+
// iCloud
|
|
119
|
+
"icloud.com": "icloud",
|
|
120
|
+
"me.com": "icloud",
|
|
121
|
+
"mac.com": "icloud",
|
|
122
|
+
// Fastmail
|
|
123
|
+
"fastmail.com": "fastmail",
|
|
124
|
+
"fastmail.fm": "fastmail",
|
|
125
|
+
// Proton
|
|
126
|
+
"protonmail.com": "protonmail",
|
|
127
|
+
"proton.me": "protonmail",
|
|
128
|
+
"pm.me": "protonmail",
|
|
129
|
+
// Others
|
|
130
|
+
"aol.com": "aol",
|
|
131
|
+
"yandex.com": "yandex",
|
|
132
|
+
"yandex.ru": "yandex",
|
|
133
|
+
"ya.ru": "yandex",
|
|
134
|
+
"mail.ru": "mailru",
|
|
135
|
+
"gmx.com": "gmx",
|
|
136
|
+
"gmx.de": "gmx",
|
|
137
|
+
"gmx.net": "gmx",
|
|
138
|
+
"web.de": "webde",
|
|
139
|
+
"tutanota.com": "tutanota",
|
|
140
|
+
"tuta.io": "tutanota",
|
|
141
|
+
"hey.com": "hey",
|
|
142
|
+
"mail.com": "mailcom"
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
// src/data/mx.ts
|
|
146
|
+
var KNOWN_MX = {
|
|
147
|
+
// Google
|
|
148
|
+
"google.com": "google",
|
|
149
|
+
"googlemail.com": "google",
|
|
150
|
+
// Microsoft
|
|
151
|
+
"outlook.com": "microsoft",
|
|
152
|
+
"microsoft.com": "microsoft",
|
|
153
|
+
"pphosted.com": "microsoft",
|
|
154
|
+
// Zoho
|
|
155
|
+
"zoho.com": "zoho",
|
|
156
|
+
"zoho.eu": "zoho",
|
|
157
|
+
"zoho.in": "zoho",
|
|
158
|
+
"zoho.com.au": "zoho",
|
|
159
|
+
"zoho.jp": "zoho",
|
|
160
|
+
// Yahoo
|
|
161
|
+
"yahoodns.net": "yahoo",
|
|
162
|
+
// Apple
|
|
163
|
+
"icloud.com": "icloud",
|
|
164
|
+
"apple.com": "icloud",
|
|
165
|
+
// Hosting providers
|
|
166
|
+
"secureserver.net": "godaddy",
|
|
167
|
+
"titan.email": "titan",
|
|
168
|
+
"hostinger.com": "hostinger",
|
|
169
|
+
"ovh.net": "ovh",
|
|
170
|
+
"ionos.com": "ionos",
|
|
171
|
+
"emailsrvr.com": "rackspace",
|
|
172
|
+
"dreamhost.com": "dreamhost",
|
|
173
|
+
"awsapps.com": "amazon_workmail",
|
|
174
|
+
// Email-focused providers
|
|
175
|
+
"fastmail.com": "fastmail",
|
|
176
|
+
"protonmail.ch": "protonmail",
|
|
177
|
+
"yandex.net": "yandex",
|
|
178
|
+
"yandex.ru": "yandex",
|
|
179
|
+
"migadu.com": "migadu",
|
|
180
|
+
"improvmx.com": "improvmx",
|
|
181
|
+
"forwardemail.net": "forwardemail",
|
|
182
|
+
// Sending-only (no IMAP)
|
|
183
|
+
"mailgun.org": "mailgun",
|
|
184
|
+
"sendgrid.net": "sendgrid"
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
// src/data/providers.ts
|
|
188
|
+
var KNOWN_PROVIDERS = {
|
|
189
|
+
google: {
|
|
190
|
+
imap: { host: "imap.gmail.com", port: 993, secure: true },
|
|
191
|
+
smtp: { host: "smtp.gmail.com", port: 465, secure: true },
|
|
192
|
+
username: "%EMAILADDRESS%"
|
|
193
|
+
},
|
|
194
|
+
microsoft: {
|
|
195
|
+
imap: { host: "outlook.office365.com", port: 993, secure: true },
|
|
196
|
+
smtp: { host: "smtp-mail.outlook.com", port: 587, secure: false },
|
|
197
|
+
username: "%EMAILADDRESS%"
|
|
198
|
+
},
|
|
199
|
+
zoho: {
|
|
200
|
+
imap: { host: "imappro.zoho.com", port: 993, secure: true },
|
|
201
|
+
smtp: { host: "smtppro.zoho.com", port: 465, secure: true },
|
|
202
|
+
username: "%EMAILADDRESS%"
|
|
203
|
+
},
|
|
204
|
+
yahoo: {
|
|
205
|
+
imap: { host: "imap.mail.yahoo.com", port: 993, secure: true },
|
|
206
|
+
smtp: { host: "smtp.mail.yahoo.com", port: 465, secure: true },
|
|
207
|
+
username: "%EMAILADDRESS%"
|
|
208
|
+
},
|
|
209
|
+
icloud: {
|
|
210
|
+
imap: { host: "imap.mail.me.com", port: 993, secure: true },
|
|
211
|
+
smtp: { host: "smtp.mail.me.com", port: 587, secure: false },
|
|
212
|
+
username: "%EMAILADDRESS%"
|
|
213
|
+
},
|
|
214
|
+
fastmail: {
|
|
215
|
+
imap: { host: "imap.fastmail.com", port: 993, secure: true },
|
|
216
|
+
smtp: { host: "smtp.fastmail.com", port: 465, secure: true },
|
|
217
|
+
username: "%EMAILADDRESS%"
|
|
218
|
+
},
|
|
219
|
+
protonmail: {
|
|
220
|
+
imap: { host: "127.0.0.1", port: 1143, secure: false },
|
|
221
|
+
smtp: { host: "127.0.0.1", port: 1025, secure: false },
|
|
222
|
+
username: "%EMAILADDRESS%"
|
|
223
|
+
},
|
|
224
|
+
godaddy: {
|
|
225
|
+
imap: { host: "imap.secureserver.net", port: 993, secure: true },
|
|
226
|
+
smtp: { host: "smtpout.secureserver.net", port: 465, secure: true },
|
|
227
|
+
username: "%EMAILADDRESS%"
|
|
228
|
+
},
|
|
229
|
+
titan: {
|
|
230
|
+
imap: { host: "imap.titan.email", port: 993, secure: true },
|
|
231
|
+
smtp: { host: "smtp.titan.email", port: 465, secure: true },
|
|
232
|
+
username: "%EMAILADDRESS%"
|
|
233
|
+
},
|
|
234
|
+
ovh: {
|
|
235
|
+
imap: { host: "ssl0.ovh.net", port: 993, secure: true },
|
|
236
|
+
smtp: { host: "ssl0.ovh.net", port: 465, secure: true },
|
|
237
|
+
username: "%EMAILADDRESS%"
|
|
238
|
+
},
|
|
239
|
+
ionos: {
|
|
240
|
+
imap: { host: "imap.ionos.com", port: 993, secure: true },
|
|
241
|
+
smtp: { host: "smtp.ionos.com", port: 465, secure: true },
|
|
242
|
+
username: "%EMAILADDRESS%"
|
|
243
|
+
},
|
|
244
|
+
hostinger: {
|
|
245
|
+
imap: { host: "imap.hostinger.com", port: 993, secure: true },
|
|
246
|
+
smtp: { host: "smtp.hostinger.com", port: 465, secure: true },
|
|
247
|
+
username: "%EMAILADDRESS%"
|
|
248
|
+
},
|
|
249
|
+
yandex: {
|
|
250
|
+
imap: { host: "imap.yandex.com", port: 993, secure: true },
|
|
251
|
+
smtp: { host: "smtp.yandex.com", port: 465, secure: true },
|
|
252
|
+
username: "%EMAILADDRESS%"
|
|
253
|
+
},
|
|
254
|
+
aol: {
|
|
255
|
+
imap: { host: "imap.aol.com", port: 993, secure: true },
|
|
256
|
+
smtp: { host: "smtp.aol.com", port: 465, secure: true },
|
|
257
|
+
username: "%EMAILADDRESS%"
|
|
258
|
+
},
|
|
259
|
+
rackspace: {
|
|
260
|
+
imap: { host: "secure.emailsrvr.com", port: 993, secure: true },
|
|
261
|
+
smtp: { host: "secure.emailsrvr.com", port: 465, secure: true },
|
|
262
|
+
username: "%EMAILADDRESS%"
|
|
263
|
+
},
|
|
264
|
+
dreamhost: {
|
|
265
|
+
imap: { host: "imap.dreamhost.com", port: 993, secure: true },
|
|
266
|
+
smtp: { host: "smtp.dreamhost.com", port: 465, secure: true },
|
|
267
|
+
username: "%EMAILADDRESS%"
|
|
268
|
+
}
|
|
269
|
+
};
|
|
270
|
+
var REGIONAL_PROVIDERS = {
|
|
271
|
+
zoho: {
|
|
272
|
+
"zoho.eu": { imapHost: "imappro.zoho.eu", smtpHost: "smtppro.zoho.eu" },
|
|
273
|
+
"zoho.in": { imapHost: "imappro.zoho.in", smtpHost: "smtppro.zoho.in" },
|
|
274
|
+
"zoho.com.au": { imapHost: "imappro.zoho.com.au", smtpHost: "smtppro.zoho.com.au" },
|
|
275
|
+
"zoho.jp": { imapHost: "imappro.zoho.jp", smtpHost: "smtppro.zoho.jp" }
|
|
276
|
+
}
|
|
277
|
+
};
|
|
278
|
+
|
|
279
|
+
// src/data/free.ts
|
|
280
|
+
var FREE_DOMAINS = /* @__PURE__ */ new Set([
|
|
281
|
+
"gmail.com",
|
|
282
|
+
"googlemail.com",
|
|
283
|
+
"outlook.com",
|
|
284
|
+
"hotmail.com",
|
|
285
|
+
"live.com",
|
|
286
|
+
"msn.com",
|
|
287
|
+
"hotmail.co.uk",
|
|
288
|
+
"hotmail.fr",
|
|
289
|
+
"yahoo.com",
|
|
290
|
+
"yahoo.co.uk",
|
|
291
|
+
"yahoo.fr",
|
|
292
|
+
"yahoo.de",
|
|
293
|
+
"ymail.com",
|
|
294
|
+
"icloud.com",
|
|
295
|
+
"me.com",
|
|
296
|
+
"mac.com",
|
|
297
|
+
"protonmail.com",
|
|
298
|
+
"proton.me",
|
|
299
|
+
"pm.me",
|
|
300
|
+
"aol.com",
|
|
301
|
+
"yandex.com",
|
|
302
|
+
"yandex.ru",
|
|
303
|
+
"ya.ru",
|
|
304
|
+
"mail.ru",
|
|
305
|
+
"gmx.com",
|
|
306
|
+
"gmx.de",
|
|
307
|
+
"gmx.net",
|
|
308
|
+
"web.de",
|
|
309
|
+
"zoho.com",
|
|
310
|
+
"tutanota.com",
|
|
311
|
+
"tuta.io",
|
|
312
|
+
"mail.com"
|
|
313
|
+
]);
|
|
314
|
+
|
|
315
|
+
// src/mailintel.ts
|
|
316
|
+
function resolveUsername(template, email, domain) {
|
|
317
|
+
return template.replace("%EMAILADDRESS%", email).replace("%EMAILLOCALPART%", email.split("@")[0] ?? "").replace("%EMAILDOMAIN%", domain);
|
|
318
|
+
}
|
|
319
|
+
function resolveConnection(raw, email, domain) {
|
|
320
|
+
return {
|
|
321
|
+
imap: raw.imap,
|
|
322
|
+
smtp: raw.smtp,
|
|
323
|
+
username: email ? resolveUsername(raw.username, email, domain) : raw.username,
|
|
324
|
+
usernameTemplate: raw.username
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
async function mailintelCore(input, options, cache, cacheTtl) {
|
|
328
|
+
const atIndex = input.lastIndexOf("@");
|
|
329
|
+
const isDomainOnly = atIndex === -1;
|
|
330
|
+
const email = isDomainOnly ? "" : input;
|
|
331
|
+
const domain = isDomainOnly ? input.toLowerCase() : input.slice(atIndex + 1).toLowerCase();
|
|
332
|
+
if (!domain) {
|
|
333
|
+
return emptyResult(email, "");
|
|
334
|
+
}
|
|
335
|
+
if (cache) {
|
|
336
|
+
const cached = cache.get(domain);
|
|
337
|
+
if (cached) {
|
|
338
|
+
return { ...cached, email };
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
if (options.providers?.[domain]) {
|
|
342
|
+
const override = options.providers[domain];
|
|
343
|
+
const result2 = {
|
|
344
|
+
email,
|
|
345
|
+
domain,
|
|
346
|
+
provider: override.provider,
|
|
347
|
+
mx: null,
|
|
348
|
+
type: FREE_DOMAINS.has(domain) ? "free" : "business",
|
|
349
|
+
isFree: FREE_DOMAINS.has(domain),
|
|
350
|
+
hasMx: false,
|
|
351
|
+
connection: resolveConnection(
|
|
352
|
+
{ imap: override.imap, smtp: override.smtp, username: override.username ?? "%EMAILADDRESS%" },
|
|
353
|
+
email,
|
|
354
|
+
domain
|
|
355
|
+
),
|
|
356
|
+
confidence: "high",
|
|
357
|
+
source: "override",
|
|
358
|
+
raw: { mx: null, dns: null, ispdb: null }
|
|
359
|
+
};
|
|
360
|
+
cache?.set(domain, result2, cacheTtl);
|
|
361
|
+
return result2;
|
|
362
|
+
}
|
|
363
|
+
const knownProvider = KNOWN_DOMAINS[domain];
|
|
364
|
+
if (knownProvider) {
|
|
365
|
+
const connection2 = KNOWN_PROVIDERS[knownProvider] ?? null;
|
|
366
|
+
const result2 = {
|
|
367
|
+
email,
|
|
368
|
+
domain,
|
|
369
|
+
provider: knownProvider,
|
|
370
|
+
mx: null,
|
|
371
|
+
type: FREE_DOMAINS.has(domain) ? "free" : "business",
|
|
372
|
+
isFree: FREE_DOMAINS.has(domain),
|
|
373
|
+
hasMx: false,
|
|
374
|
+
connection: connection2 ? resolveConnection(connection2, email, domain) : null,
|
|
375
|
+
confidence: "high",
|
|
376
|
+
source: "known-domain",
|
|
377
|
+
raw: { mx: null, dns: null, ispdb: null }
|
|
378
|
+
};
|
|
379
|
+
cache?.set(domain, result2, cacheTtl);
|
|
380
|
+
return result2;
|
|
381
|
+
}
|
|
382
|
+
if (options.mxLookup === false) {
|
|
383
|
+
const result2 = emptyResult(email, domain);
|
|
384
|
+
cache?.set(domain, result2, cacheTtl);
|
|
385
|
+
return result2;
|
|
386
|
+
}
|
|
387
|
+
const resolver = options.mxLookup === "google" ? "google" : "cloudflare";
|
|
388
|
+
const { records: mxRecords, raw: dnsRaw } = await lookupMx(domain, {
|
|
389
|
+
resolver,
|
|
390
|
+
timeout: options.timeout,
|
|
391
|
+
fetch: options.fetch
|
|
392
|
+
});
|
|
393
|
+
if (mxRecords.length === 0) {
|
|
394
|
+
const result2 = {
|
|
395
|
+
email,
|
|
396
|
+
domain,
|
|
397
|
+
provider: null,
|
|
398
|
+
mx: null,
|
|
399
|
+
type: "unknown",
|
|
400
|
+
isFree: false,
|
|
401
|
+
hasMx: false,
|
|
402
|
+
connection: null,
|
|
403
|
+
confidence: "low",
|
|
404
|
+
source: null,
|
|
405
|
+
raw: { mx: [], dns: dnsRaw, ispdb: null }
|
|
406
|
+
};
|
|
407
|
+
cache?.set(domain, result2, cacheTtl);
|
|
408
|
+
return result2;
|
|
409
|
+
}
|
|
410
|
+
const primaryMx = mxRecords[0].exchange;
|
|
411
|
+
if (options.mxOverrides) {
|
|
412
|
+
for (const [suffix, override] of Object.entries(options.mxOverrides)) {
|
|
413
|
+
if (primaryMx === suffix || primaryMx.endsWith("." + suffix)) {
|
|
414
|
+
const result2 = {
|
|
415
|
+
email,
|
|
416
|
+
domain,
|
|
417
|
+
provider: override.provider,
|
|
418
|
+
mx: primaryMx,
|
|
419
|
+
type: FREE_DOMAINS.has(domain) ? "free" : "business",
|
|
420
|
+
isFree: FREE_DOMAINS.has(domain),
|
|
421
|
+
hasMx: true,
|
|
422
|
+
connection: resolveConnection(
|
|
423
|
+
{ imap: override.imap, smtp: override.smtp, username: override.username ?? "%EMAILADDRESS%" },
|
|
424
|
+
email,
|
|
425
|
+
domain
|
|
426
|
+
),
|
|
427
|
+
confidence: "high",
|
|
428
|
+
source: "mx-lookup",
|
|
429
|
+
raw: { mx: mxRecords, dns: dnsRaw, ispdb: null }
|
|
430
|
+
};
|
|
431
|
+
cache?.set(domain, result2, cacheTtl);
|
|
432
|
+
return result2;
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
let mxProvider = null;
|
|
437
|
+
let matchedMxSuffix = null;
|
|
438
|
+
for (const [suffix, provider] of Object.entries(KNOWN_MX)) {
|
|
439
|
+
if (primaryMx === suffix || primaryMx.endsWith("." + suffix)) {
|
|
440
|
+
mxProvider = provider;
|
|
441
|
+
matchedMxSuffix = suffix;
|
|
442
|
+
break;
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
if (mxProvider) {
|
|
446
|
+
let connection2 = KNOWN_PROVIDERS[mxProvider] ?? null;
|
|
447
|
+
let ispdbRaw2 = null;
|
|
448
|
+
let confidence = connection2 ? "high" : "low";
|
|
449
|
+
if (connection2 && matchedMxSuffix) {
|
|
450
|
+
const regional = REGIONAL_PROVIDERS[mxProvider];
|
|
451
|
+
if (regional) {
|
|
452
|
+
for (const [regionSuffix, regionConfig] of Object.entries(regional)) {
|
|
453
|
+
if (matchedMxSuffix === regionSuffix || matchedMxSuffix.endsWith("." + regionSuffix)) {
|
|
454
|
+
connection2 = {
|
|
455
|
+
...connection2,
|
|
456
|
+
imap: { ...connection2.imap, host: regionConfig.imapHost },
|
|
457
|
+
smtp: { ...connection2.smtp, host: regionConfig.smtpHost }
|
|
458
|
+
};
|
|
459
|
+
break;
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
if (!connection2 && options.ispdb !== false) {
|
|
465
|
+
const ispdbResult = await lookupIspdb(domain, {
|
|
466
|
+
timeout: options.timeout,
|
|
467
|
+
fetch: options.fetch
|
|
468
|
+
});
|
|
469
|
+
connection2 = ispdbResult.connection;
|
|
470
|
+
ispdbRaw2 = ispdbResult.raw;
|
|
471
|
+
if (connection2) {
|
|
472
|
+
confidence = "medium";
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
const result2 = {
|
|
476
|
+
email,
|
|
477
|
+
domain,
|
|
478
|
+
provider: mxProvider,
|
|
479
|
+
mx: primaryMx,
|
|
480
|
+
type: FREE_DOMAINS.has(domain) ? "free" : "business",
|
|
481
|
+
isFree: FREE_DOMAINS.has(domain),
|
|
482
|
+
hasMx: true,
|
|
483
|
+
connection: connection2 ? resolveConnection(connection2, email, domain) : null,
|
|
484
|
+
confidence,
|
|
485
|
+
source: "mx-lookup",
|
|
486
|
+
raw: { mx: mxRecords, dns: dnsRaw, ispdb: ispdbRaw2 }
|
|
487
|
+
};
|
|
488
|
+
cache?.set(domain, result2, cacheTtl);
|
|
489
|
+
return result2;
|
|
490
|
+
}
|
|
491
|
+
let connection = null;
|
|
492
|
+
let ispdbRaw = null;
|
|
493
|
+
if (options.ispdb !== false) {
|
|
494
|
+
const ispdbResult = await lookupIspdb(domain, {
|
|
495
|
+
timeout: options.timeout,
|
|
496
|
+
fetch: options.fetch
|
|
497
|
+
});
|
|
498
|
+
connection = ispdbResult.connection;
|
|
499
|
+
ispdbRaw = ispdbResult.raw;
|
|
500
|
+
}
|
|
501
|
+
const result = {
|
|
502
|
+
email,
|
|
503
|
+
domain,
|
|
504
|
+
provider: null,
|
|
505
|
+
mx: primaryMx,
|
|
506
|
+
type: FREE_DOMAINS.has(domain) ? "free" : "business",
|
|
507
|
+
isFree: FREE_DOMAINS.has(domain),
|
|
508
|
+
hasMx: true,
|
|
509
|
+
connection: connection ? resolveConnection(connection, email, domain) : null,
|
|
510
|
+
confidence: connection ? "medium" : "low",
|
|
511
|
+
source: connection ? "mx-lookup" : null,
|
|
512
|
+
raw: { mx: mxRecords, dns: dnsRaw, ispdb: ispdbRaw }
|
|
513
|
+
};
|
|
514
|
+
cache?.set(domain, result, cacheTtl);
|
|
515
|
+
return result;
|
|
516
|
+
}
|
|
517
|
+
function emptyResult(email, domain) {
|
|
518
|
+
return {
|
|
519
|
+
email,
|
|
520
|
+
domain,
|
|
521
|
+
provider: null,
|
|
522
|
+
mx: null,
|
|
523
|
+
type: "unknown",
|
|
524
|
+
isFree: false,
|
|
525
|
+
hasMx: false,
|
|
526
|
+
connection: null,
|
|
527
|
+
confidence: "low",
|
|
528
|
+
source: null,
|
|
529
|
+
raw: { mx: null, dns: null, ispdb: null }
|
|
530
|
+
};
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
// src/cache.ts
|
|
534
|
+
var Cache = class {
|
|
535
|
+
store = /* @__PURE__ */ new Map();
|
|
536
|
+
get(key) {
|
|
537
|
+
const entry = this.store.get(key);
|
|
538
|
+
if (!entry) return null;
|
|
539
|
+
if (Date.now() > entry.expires) {
|
|
540
|
+
this.store.delete(key);
|
|
541
|
+
return null;
|
|
542
|
+
}
|
|
543
|
+
return entry.value;
|
|
544
|
+
}
|
|
545
|
+
set(key, value, ttl) {
|
|
546
|
+
this.store.set(key, { value, expires: Date.now() + ttl });
|
|
547
|
+
}
|
|
548
|
+
clear() {
|
|
549
|
+
this.store.clear();
|
|
550
|
+
}
|
|
551
|
+
};
|
|
552
|
+
|
|
553
|
+
// src/factory.ts
|
|
554
|
+
function createMailintel(options = {}) {
|
|
555
|
+
const cache = options.cache !== false ? new Cache() : null;
|
|
556
|
+
const cacheTtl = options.cacheTtl ?? 30 * 60 * 1e3;
|
|
557
|
+
async function mailintel2(input, callOptions) {
|
|
558
|
+
const mergedOptions = { ...options, ...callOptions };
|
|
559
|
+
if (Array.isArray(input)) {
|
|
560
|
+
return Promise.all(input.map((email) => mailintelCore(email, mergedOptions, cache, cacheTtl)));
|
|
561
|
+
}
|
|
562
|
+
return mailintelCore(input, mergedOptions, cache, cacheTtl);
|
|
563
|
+
}
|
|
564
|
+
mailintel2.clearCache = () => cache?.clear();
|
|
565
|
+
return mailintel2;
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
// src/index.ts
|
|
569
|
+
var mailintel = createMailintel();
|
|
570
|
+
|
|
571
|
+
exports.createMailintel = createMailintel;
|
|
572
|
+
exports.mailintel = mailintel;
|
|
573
|
+
exports.mailintelCore = mailintelCore;
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
interface ServerConfig {
|
|
2
|
+
host: string;
|
|
3
|
+
port: number;
|
|
4
|
+
secure: boolean;
|
|
5
|
+
}
|
|
6
|
+
interface ConnectionInfo {
|
|
7
|
+
imap: ServerConfig;
|
|
8
|
+
smtp: ServerConfig;
|
|
9
|
+
username: string;
|
|
10
|
+
usernameTemplate: string;
|
|
11
|
+
}
|
|
12
|
+
interface MxRecord {
|
|
13
|
+
priority: number;
|
|
14
|
+
exchange: string;
|
|
15
|
+
}
|
|
16
|
+
interface MailintelResult {
|
|
17
|
+
email: string;
|
|
18
|
+
domain: string;
|
|
19
|
+
provider: string | null;
|
|
20
|
+
mx: string | null;
|
|
21
|
+
type: 'free' | 'business' | 'unknown';
|
|
22
|
+
isFree: boolean;
|
|
23
|
+
hasMx: boolean;
|
|
24
|
+
connection: ConnectionInfo | null;
|
|
25
|
+
confidence: 'high' | 'medium' | 'low';
|
|
26
|
+
source: 'override' | 'known-domain' | 'mx-lookup' | null;
|
|
27
|
+
raw: {
|
|
28
|
+
mx: MxRecord[] | null;
|
|
29
|
+
dns: object | null;
|
|
30
|
+
ispdb: string | null;
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
interface ProviderOverride {
|
|
34
|
+
provider: string;
|
|
35
|
+
imap: ServerConfig;
|
|
36
|
+
smtp: ServerConfig;
|
|
37
|
+
username?: string;
|
|
38
|
+
}
|
|
39
|
+
interface MailintelOptions {
|
|
40
|
+
timeout?: number;
|
|
41
|
+
cache?: boolean;
|
|
42
|
+
cacheTtl?: number;
|
|
43
|
+
mxLookup?: boolean | 'cloudflare' | 'google';
|
|
44
|
+
ispdb?: boolean;
|
|
45
|
+
fetch?: typeof globalThis.fetch;
|
|
46
|
+
providers?: Record<string, ProviderOverride>;
|
|
47
|
+
mxOverrides?: Record<string, ProviderOverride>;
|
|
48
|
+
}
|
|
49
|
+
type MailintelCallOptions = Pick<MailintelOptions, 'timeout'>;
|
|
50
|
+
|
|
51
|
+
declare function createMailintel(options?: MailintelOptions): {
|
|
52
|
+
(input: string | string[], callOptions?: MailintelCallOptions): Promise<MailintelResult | MailintelResult[]>;
|
|
53
|
+
clearCache(): void | undefined;
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
declare class Cache<T> {
|
|
57
|
+
private store;
|
|
58
|
+
get(key: string): T | null;
|
|
59
|
+
set(key: string, value: T, ttl: number): void;
|
|
60
|
+
clear(): void;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
declare function mailintelCore(input: string, options: MailintelOptions, cache: Cache<MailintelResult> | null, cacheTtl: number): Promise<MailintelResult>;
|
|
64
|
+
|
|
65
|
+
declare const mailintel: {
|
|
66
|
+
(input: string | string[], callOptions?: MailintelCallOptions): Promise<MailintelResult | MailintelResult[]>;
|
|
67
|
+
clearCache(): void | undefined;
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
export { type ConnectionInfo, type MailintelCallOptions, type MailintelOptions, type MailintelResult, type MxRecord, type ProviderOverride, type ServerConfig, createMailintel, mailintel, mailintelCore };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
interface ServerConfig {
|
|
2
|
+
host: string;
|
|
3
|
+
port: number;
|
|
4
|
+
secure: boolean;
|
|
5
|
+
}
|
|
6
|
+
interface ConnectionInfo {
|
|
7
|
+
imap: ServerConfig;
|
|
8
|
+
smtp: ServerConfig;
|
|
9
|
+
username: string;
|
|
10
|
+
usernameTemplate: string;
|
|
11
|
+
}
|
|
12
|
+
interface MxRecord {
|
|
13
|
+
priority: number;
|
|
14
|
+
exchange: string;
|
|
15
|
+
}
|
|
16
|
+
interface MailintelResult {
|
|
17
|
+
email: string;
|
|
18
|
+
domain: string;
|
|
19
|
+
provider: string | null;
|
|
20
|
+
mx: string | null;
|
|
21
|
+
type: 'free' | 'business' | 'unknown';
|
|
22
|
+
isFree: boolean;
|
|
23
|
+
hasMx: boolean;
|
|
24
|
+
connection: ConnectionInfo | null;
|
|
25
|
+
confidence: 'high' | 'medium' | 'low';
|
|
26
|
+
source: 'override' | 'known-domain' | 'mx-lookup' | null;
|
|
27
|
+
raw: {
|
|
28
|
+
mx: MxRecord[] | null;
|
|
29
|
+
dns: object | null;
|
|
30
|
+
ispdb: string | null;
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
interface ProviderOverride {
|
|
34
|
+
provider: string;
|
|
35
|
+
imap: ServerConfig;
|
|
36
|
+
smtp: ServerConfig;
|
|
37
|
+
username?: string;
|
|
38
|
+
}
|
|
39
|
+
interface MailintelOptions {
|
|
40
|
+
timeout?: number;
|
|
41
|
+
cache?: boolean;
|
|
42
|
+
cacheTtl?: number;
|
|
43
|
+
mxLookup?: boolean | 'cloudflare' | 'google';
|
|
44
|
+
ispdb?: boolean;
|
|
45
|
+
fetch?: typeof globalThis.fetch;
|
|
46
|
+
providers?: Record<string, ProviderOverride>;
|
|
47
|
+
mxOverrides?: Record<string, ProviderOverride>;
|
|
48
|
+
}
|
|
49
|
+
type MailintelCallOptions = Pick<MailintelOptions, 'timeout'>;
|
|
50
|
+
|
|
51
|
+
declare function createMailintel(options?: MailintelOptions): {
|
|
52
|
+
(input: string | string[], callOptions?: MailintelCallOptions): Promise<MailintelResult | MailintelResult[]>;
|
|
53
|
+
clearCache(): void | undefined;
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
declare class Cache<T> {
|
|
57
|
+
private store;
|
|
58
|
+
get(key: string): T | null;
|
|
59
|
+
set(key: string, value: T, ttl: number): void;
|
|
60
|
+
clear(): void;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
declare function mailintelCore(input: string, options: MailintelOptions, cache: Cache<MailintelResult> | null, cacheTtl: number): Promise<MailintelResult>;
|
|
64
|
+
|
|
65
|
+
declare const mailintel: {
|
|
66
|
+
(input: string | string[], callOptions?: MailintelCallOptions): Promise<MailintelResult | MailintelResult[]>;
|
|
67
|
+
clearCache(): void | undefined;
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
export { type ConnectionInfo, type MailintelCallOptions, type MailintelOptions, type MailintelResult, type MxRecord, type ProviderOverride, type ServerConfig, createMailintel, mailintel, mailintelCore };
|