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/dist/cli.js ADDED
@@ -0,0 +1,728 @@
1
+ #!/usr/bin/env node
2
+ // src/dns.ts
3
+ var RESOLVERS = {
4
+ cloudflare: "https://cloudflare-dns.com/dns-query",
5
+ google: "https://dns.google/resolve"
6
+ };
7
+ async function lookupMx(domain, options = {}) {
8
+ const resolver = options.resolver ?? "cloudflare";
9
+ const timeout = options.timeout ?? 5e3;
10
+ const fetchFn = options.fetch ?? globalThis.fetch;
11
+ const url = `${RESOLVERS[resolver]}?name=${encodeURIComponent(domain)}&type=MX`;
12
+ const controller = new AbortController();
13
+ const timer = setTimeout(() => controller.abort(), timeout);
14
+ try {
15
+ const response = await fetchFn(url, {
16
+ headers: { Accept: "application/dns-json" },
17
+ signal: controller.signal
18
+ });
19
+ if (!response.ok) {
20
+ return { records: [], raw: {} };
21
+ }
22
+ const data = await response.json();
23
+ const records = (data.Answer ?? []).filter((r) => r.type === 15).map((r) => {
24
+ const parts = r.data.split(" ");
25
+ return {
26
+ priority: parseInt(parts[0], 10),
27
+ exchange: parts[1]?.replace(/\.$/, "") ?? ""
28
+ };
29
+ }).sort((a, b) => a.priority - b.priority);
30
+ return { records, raw: data };
31
+ } catch {
32
+ return { records: [], raw: {} };
33
+ } finally {
34
+ clearTimeout(timer);
35
+ }
36
+ }
37
+
38
+ // src/ispdb.ts
39
+ var ISPDB_URL = "https://autoconfig.thunderbird.net/v1.1";
40
+ async function lookupIspdb(domain, options = {}) {
41
+ const timeout = options.timeout ?? 5e3;
42
+ const fetchFn = options.fetch ?? globalThis.fetch;
43
+ const url = `${ISPDB_URL}/${encodeURIComponent(domain)}`;
44
+ const controller = new AbortController();
45
+ const timer = setTimeout(() => controller.abort(), timeout);
46
+ try {
47
+ const response = await fetchFn(url, { signal: controller.signal });
48
+ if (!response.ok) {
49
+ return { connection: null, raw: null };
50
+ }
51
+ const xml = await response.text();
52
+ const connection = parseIspdbXml(xml);
53
+ return { connection, raw: xml };
54
+ } catch {
55
+ return { connection: null, raw: null };
56
+ } finally {
57
+ clearTimeout(timer);
58
+ }
59
+ }
60
+ function parseIspdbXml(xml) {
61
+ const imapMatch = xml.match(/<incomingServer type="imap">([\s\S]*?)<\/incomingServer>/);
62
+ const smtpMatch = xml.match(/<outgoingServer type="smtp">([\s\S]*?)<\/outgoingServer>/);
63
+ if (!imapMatch || !smtpMatch) return null;
64
+ const imapBlock = imapMatch[1];
65
+ const smtpBlock = smtpMatch[1];
66
+ const imapHost = imapBlock.match(/<hostname>(.*?)<\/hostname>/)?.[1];
67
+ const imapPort = imapBlock.match(/<port>(.*?)<\/port>/)?.[1];
68
+ const imapSocket = imapBlock.match(/<socketType>(.*?)<\/socketType>/)?.[1];
69
+ const smtpHost = smtpBlock.match(/<hostname>(.*?)<\/hostname>/)?.[1];
70
+ const smtpPort = smtpBlock.match(/<port>(.*?)<\/port>/)?.[1];
71
+ const smtpSocket = smtpBlock.match(/<socketType>(.*?)<\/socketType>/)?.[1];
72
+ const username = xml.match(/<username>(.*?)<\/username>/)?.[1] ?? "%EMAILADDRESS%";
73
+ if (!imapHost || !imapPort || !smtpHost || !smtpPort) return null;
74
+ return {
75
+ imap: {
76
+ host: imapHost,
77
+ port: parseInt(imapPort, 10),
78
+ secure: imapSocket === "SSL"
79
+ },
80
+ smtp: {
81
+ host: smtpHost,
82
+ port: parseInt(smtpPort, 10),
83
+ secure: smtpSocket === "SSL" || smtpSocket === "STARTTLS"
84
+ },
85
+ username
86
+ };
87
+ }
88
+
89
+ // src/data/domains.ts
90
+ var KNOWN_DOMAINS = {
91
+ // Google
92
+ "gmail.com": "google",
93
+ "googlemail.com": "google",
94
+ // Microsoft
95
+ "outlook.com": "microsoft",
96
+ "hotmail.com": "microsoft",
97
+ "live.com": "microsoft",
98
+ "msn.com": "microsoft",
99
+ "hotmail.co.uk": "microsoft",
100
+ "hotmail.fr": "microsoft",
101
+ "outlook.co.uk": "microsoft",
102
+ // Yahoo
103
+ "yahoo.com": "yahoo",
104
+ "yahoo.co.uk": "yahoo",
105
+ "yahoo.fr": "yahoo",
106
+ "yahoo.de": "yahoo",
107
+ "yahoo.co.jp": "yahoo",
108
+ "ymail.com": "yahoo",
109
+ "rocketmail.com": "yahoo",
110
+ // Zoho
111
+ "zoho.com": "zoho",
112
+ "zohomail.com": "zoho",
113
+ "zoho.eu": "zoho",
114
+ "zoho.in": "zoho",
115
+ "zoho.com.au": "zoho",
116
+ "zoho.jp": "zoho",
117
+ // iCloud
118
+ "icloud.com": "icloud",
119
+ "me.com": "icloud",
120
+ "mac.com": "icloud",
121
+ // Fastmail
122
+ "fastmail.com": "fastmail",
123
+ "fastmail.fm": "fastmail",
124
+ // Proton
125
+ "protonmail.com": "protonmail",
126
+ "proton.me": "protonmail",
127
+ "pm.me": "protonmail",
128
+ // Others
129
+ "aol.com": "aol",
130
+ "yandex.com": "yandex",
131
+ "yandex.ru": "yandex",
132
+ "ya.ru": "yandex",
133
+ "mail.ru": "mailru",
134
+ "gmx.com": "gmx",
135
+ "gmx.de": "gmx",
136
+ "gmx.net": "gmx",
137
+ "web.de": "webde",
138
+ "tutanota.com": "tutanota",
139
+ "tuta.io": "tutanota",
140
+ "hey.com": "hey",
141
+ "mail.com": "mailcom"
142
+ };
143
+
144
+ // src/data/mx.ts
145
+ var KNOWN_MX = {
146
+ // Google
147
+ "google.com": "google",
148
+ "googlemail.com": "google",
149
+ // Microsoft
150
+ "outlook.com": "microsoft",
151
+ "microsoft.com": "microsoft",
152
+ "pphosted.com": "microsoft",
153
+ // Zoho
154
+ "zoho.com": "zoho",
155
+ "zoho.eu": "zoho",
156
+ "zoho.in": "zoho",
157
+ "zoho.com.au": "zoho",
158
+ "zoho.jp": "zoho",
159
+ // Yahoo
160
+ "yahoodns.net": "yahoo",
161
+ // Apple
162
+ "icloud.com": "icloud",
163
+ "apple.com": "icloud",
164
+ // Hosting providers
165
+ "secureserver.net": "godaddy",
166
+ "titan.email": "titan",
167
+ "hostinger.com": "hostinger",
168
+ "ovh.net": "ovh",
169
+ "ionos.com": "ionos",
170
+ "emailsrvr.com": "rackspace",
171
+ "dreamhost.com": "dreamhost",
172
+ "awsapps.com": "amazon_workmail",
173
+ // Email-focused providers
174
+ "fastmail.com": "fastmail",
175
+ "protonmail.ch": "protonmail",
176
+ "yandex.net": "yandex",
177
+ "yandex.ru": "yandex",
178
+ "migadu.com": "migadu",
179
+ "improvmx.com": "improvmx",
180
+ "forwardemail.net": "forwardemail",
181
+ // Sending-only (no IMAP)
182
+ "mailgun.org": "mailgun",
183
+ "sendgrid.net": "sendgrid"
184
+ };
185
+
186
+ // src/data/providers.ts
187
+ var KNOWN_PROVIDERS = {
188
+ google: {
189
+ imap: { host: "imap.gmail.com", port: 993, secure: true },
190
+ smtp: { host: "smtp.gmail.com", port: 465, secure: true },
191
+ username: "%EMAILADDRESS%"
192
+ },
193
+ microsoft: {
194
+ imap: { host: "outlook.office365.com", port: 993, secure: true },
195
+ smtp: { host: "smtp-mail.outlook.com", port: 587, secure: false },
196
+ username: "%EMAILADDRESS%"
197
+ },
198
+ zoho: {
199
+ imap: { host: "imappro.zoho.com", port: 993, secure: true },
200
+ smtp: { host: "smtppro.zoho.com", port: 465, secure: true },
201
+ username: "%EMAILADDRESS%"
202
+ },
203
+ yahoo: {
204
+ imap: { host: "imap.mail.yahoo.com", port: 993, secure: true },
205
+ smtp: { host: "smtp.mail.yahoo.com", port: 465, secure: true },
206
+ username: "%EMAILADDRESS%"
207
+ },
208
+ icloud: {
209
+ imap: { host: "imap.mail.me.com", port: 993, secure: true },
210
+ smtp: { host: "smtp.mail.me.com", port: 587, secure: false },
211
+ username: "%EMAILADDRESS%"
212
+ },
213
+ fastmail: {
214
+ imap: { host: "imap.fastmail.com", port: 993, secure: true },
215
+ smtp: { host: "smtp.fastmail.com", port: 465, secure: true },
216
+ username: "%EMAILADDRESS%"
217
+ },
218
+ protonmail: {
219
+ imap: { host: "127.0.0.1", port: 1143, secure: false },
220
+ smtp: { host: "127.0.0.1", port: 1025, secure: false },
221
+ username: "%EMAILADDRESS%"
222
+ },
223
+ godaddy: {
224
+ imap: { host: "imap.secureserver.net", port: 993, secure: true },
225
+ smtp: { host: "smtpout.secureserver.net", port: 465, secure: true },
226
+ username: "%EMAILADDRESS%"
227
+ },
228
+ titan: {
229
+ imap: { host: "imap.titan.email", port: 993, secure: true },
230
+ smtp: { host: "smtp.titan.email", port: 465, secure: true },
231
+ username: "%EMAILADDRESS%"
232
+ },
233
+ ovh: {
234
+ imap: { host: "ssl0.ovh.net", port: 993, secure: true },
235
+ smtp: { host: "ssl0.ovh.net", port: 465, secure: true },
236
+ username: "%EMAILADDRESS%"
237
+ },
238
+ ionos: {
239
+ imap: { host: "imap.ionos.com", port: 993, secure: true },
240
+ smtp: { host: "smtp.ionos.com", port: 465, secure: true },
241
+ username: "%EMAILADDRESS%"
242
+ },
243
+ hostinger: {
244
+ imap: { host: "imap.hostinger.com", port: 993, secure: true },
245
+ smtp: { host: "smtp.hostinger.com", port: 465, secure: true },
246
+ username: "%EMAILADDRESS%"
247
+ },
248
+ yandex: {
249
+ imap: { host: "imap.yandex.com", port: 993, secure: true },
250
+ smtp: { host: "smtp.yandex.com", port: 465, secure: true },
251
+ username: "%EMAILADDRESS%"
252
+ },
253
+ aol: {
254
+ imap: { host: "imap.aol.com", port: 993, secure: true },
255
+ smtp: { host: "smtp.aol.com", port: 465, secure: true },
256
+ username: "%EMAILADDRESS%"
257
+ },
258
+ rackspace: {
259
+ imap: { host: "secure.emailsrvr.com", port: 993, secure: true },
260
+ smtp: { host: "secure.emailsrvr.com", port: 465, secure: true },
261
+ username: "%EMAILADDRESS%"
262
+ },
263
+ dreamhost: {
264
+ imap: { host: "imap.dreamhost.com", port: 993, secure: true },
265
+ smtp: { host: "smtp.dreamhost.com", port: 465, secure: true },
266
+ username: "%EMAILADDRESS%"
267
+ }
268
+ };
269
+ var REGIONAL_PROVIDERS = {
270
+ zoho: {
271
+ "zoho.eu": { imapHost: "imappro.zoho.eu", smtpHost: "smtppro.zoho.eu" },
272
+ "zoho.in": { imapHost: "imappro.zoho.in", smtpHost: "smtppro.zoho.in" },
273
+ "zoho.com.au": { imapHost: "imappro.zoho.com.au", smtpHost: "smtppro.zoho.com.au" },
274
+ "zoho.jp": { imapHost: "imappro.zoho.jp", smtpHost: "smtppro.zoho.jp" }
275
+ }
276
+ };
277
+
278
+ // src/data/free.ts
279
+ var FREE_DOMAINS = /* @__PURE__ */ new Set([
280
+ "gmail.com",
281
+ "googlemail.com",
282
+ "outlook.com",
283
+ "hotmail.com",
284
+ "live.com",
285
+ "msn.com",
286
+ "hotmail.co.uk",
287
+ "hotmail.fr",
288
+ "yahoo.com",
289
+ "yahoo.co.uk",
290
+ "yahoo.fr",
291
+ "yahoo.de",
292
+ "ymail.com",
293
+ "icloud.com",
294
+ "me.com",
295
+ "mac.com",
296
+ "protonmail.com",
297
+ "proton.me",
298
+ "pm.me",
299
+ "aol.com",
300
+ "yandex.com",
301
+ "yandex.ru",
302
+ "ya.ru",
303
+ "mail.ru",
304
+ "gmx.com",
305
+ "gmx.de",
306
+ "gmx.net",
307
+ "web.de",
308
+ "zoho.com",
309
+ "tutanota.com",
310
+ "tuta.io",
311
+ "mail.com"
312
+ ]);
313
+
314
+ // src/mailintel.ts
315
+ function resolveUsername(template, email, domain) {
316
+ return template.replace("%EMAILADDRESS%", email).replace("%EMAILLOCALPART%", email.split("@")[0] ?? "").replace("%EMAILDOMAIN%", domain);
317
+ }
318
+ function resolveConnection(raw, email, domain) {
319
+ return {
320
+ imap: raw.imap,
321
+ smtp: raw.smtp,
322
+ username: email ? resolveUsername(raw.username, email, domain) : raw.username,
323
+ usernameTemplate: raw.username
324
+ };
325
+ }
326
+ async function mailintelCore(input, options, cache, cacheTtl) {
327
+ const atIndex = input.lastIndexOf("@");
328
+ const isDomainOnly = atIndex === -1;
329
+ const email = isDomainOnly ? "" : input;
330
+ const domain = isDomainOnly ? input.toLowerCase() : input.slice(atIndex + 1).toLowerCase();
331
+ if (!domain) {
332
+ return emptyResult(email, "");
333
+ }
334
+ if (cache) {
335
+ const cached = cache.get(domain);
336
+ if (cached) {
337
+ return { ...cached, email };
338
+ }
339
+ }
340
+ if (options.providers?.[domain]) {
341
+ const override = options.providers[domain];
342
+ const result2 = {
343
+ email,
344
+ domain,
345
+ provider: override.provider,
346
+ mx: null,
347
+ type: FREE_DOMAINS.has(domain) ? "free" : "business",
348
+ isFree: FREE_DOMAINS.has(domain),
349
+ hasMx: false,
350
+ connection: resolveConnection(
351
+ { imap: override.imap, smtp: override.smtp, username: override.username ?? "%EMAILADDRESS%" },
352
+ email,
353
+ domain
354
+ ),
355
+ confidence: "high",
356
+ source: "override",
357
+ raw: { mx: null, dns: null, ispdb: null }
358
+ };
359
+ cache?.set(domain, result2, cacheTtl);
360
+ return result2;
361
+ }
362
+ const knownProvider = KNOWN_DOMAINS[domain];
363
+ if (knownProvider) {
364
+ const connection2 = KNOWN_PROVIDERS[knownProvider] ?? null;
365
+ const result2 = {
366
+ email,
367
+ domain,
368
+ provider: knownProvider,
369
+ mx: null,
370
+ type: FREE_DOMAINS.has(domain) ? "free" : "business",
371
+ isFree: FREE_DOMAINS.has(domain),
372
+ hasMx: false,
373
+ connection: connection2 ? resolveConnection(connection2, email, domain) : null,
374
+ confidence: "high",
375
+ source: "known-domain",
376
+ raw: { mx: null, dns: null, ispdb: null }
377
+ };
378
+ cache?.set(domain, result2, cacheTtl);
379
+ return result2;
380
+ }
381
+ if (options.mxLookup === false) {
382
+ const result2 = emptyResult(email, domain);
383
+ cache?.set(domain, result2, cacheTtl);
384
+ return result2;
385
+ }
386
+ const resolver = options.mxLookup === "google" ? "google" : "cloudflare";
387
+ const { records: mxRecords, raw: dnsRaw } = await lookupMx(domain, {
388
+ resolver,
389
+ timeout: options.timeout,
390
+ fetch: options.fetch
391
+ });
392
+ if (mxRecords.length === 0) {
393
+ const result2 = {
394
+ email,
395
+ domain,
396
+ provider: null,
397
+ mx: null,
398
+ type: "unknown",
399
+ isFree: false,
400
+ hasMx: false,
401
+ connection: null,
402
+ confidence: "low",
403
+ source: null,
404
+ raw: { mx: [], dns: dnsRaw, ispdb: null }
405
+ };
406
+ cache?.set(domain, result2, cacheTtl);
407
+ return result2;
408
+ }
409
+ const primaryMx = mxRecords[0].exchange;
410
+ if (options.mxOverrides) {
411
+ for (const [suffix, override] of Object.entries(options.mxOverrides)) {
412
+ if (primaryMx === suffix || primaryMx.endsWith("." + suffix)) {
413
+ const result2 = {
414
+ email,
415
+ domain,
416
+ provider: override.provider,
417
+ mx: primaryMx,
418
+ type: FREE_DOMAINS.has(domain) ? "free" : "business",
419
+ isFree: FREE_DOMAINS.has(domain),
420
+ hasMx: true,
421
+ connection: resolveConnection(
422
+ { imap: override.imap, smtp: override.smtp, username: override.username ?? "%EMAILADDRESS%" },
423
+ email,
424
+ domain
425
+ ),
426
+ confidence: "high",
427
+ source: "mx-lookup",
428
+ raw: { mx: mxRecords, dns: dnsRaw, ispdb: null }
429
+ };
430
+ cache?.set(domain, result2, cacheTtl);
431
+ return result2;
432
+ }
433
+ }
434
+ }
435
+ let mxProvider = null;
436
+ let matchedMxSuffix = null;
437
+ for (const [suffix, provider] of Object.entries(KNOWN_MX)) {
438
+ if (primaryMx === suffix || primaryMx.endsWith("." + suffix)) {
439
+ mxProvider = provider;
440
+ matchedMxSuffix = suffix;
441
+ break;
442
+ }
443
+ }
444
+ if (mxProvider) {
445
+ let connection2 = KNOWN_PROVIDERS[mxProvider] ?? null;
446
+ let ispdbRaw2 = null;
447
+ let confidence = connection2 ? "high" : "low";
448
+ if (connection2 && matchedMxSuffix) {
449
+ const regional = REGIONAL_PROVIDERS[mxProvider];
450
+ if (regional) {
451
+ for (const [regionSuffix, regionConfig] of Object.entries(regional)) {
452
+ if (matchedMxSuffix === regionSuffix || matchedMxSuffix.endsWith("." + regionSuffix)) {
453
+ connection2 = {
454
+ ...connection2,
455
+ imap: { ...connection2.imap, host: regionConfig.imapHost },
456
+ smtp: { ...connection2.smtp, host: regionConfig.smtpHost }
457
+ };
458
+ break;
459
+ }
460
+ }
461
+ }
462
+ }
463
+ if (!connection2 && options.ispdb !== false) {
464
+ const ispdbResult = await lookupIspdb(domain, {
465
+ timeout: options.timeout,
466
+ fetch: options.fetch
467
+ });
468
+ connection2 = ispdbResult.connection;
469
+ ispdbRaw2 = ispdbResult.raw;
470
+ if (connection2) {
471
+ confidence = "medium";
472
+ }
473
+ }
474
+ const result2 = {
475
+ email,
476
+ domain,
477
+ provider: mxProvider,
478
+ mx: primaryMx,
479
+ type: FREE_DOMAINS.has(domain) ? "free" : "business",
480
+ isFree: FREE_DOMAINS.has(domain),
481
+ hasMx: true,
482
+ connection: connection2 ? resolveConnection(connection2, email, domain) : null,
483
+ confidence,
484
+ source: "mx-lookup",
485
+ raw: { mx: mxRecords, dns: dnsRaw, ispdb: ispdbRaw2 }
486
+ };
487
+ cache?.set(domain, result2, cacheTtl);
488
+ return result2;
489
+ }
490
+ let connection = null;
491
+ let ispdbRaw = null;
492
+ if (options.ispdb !== false) {
493
+ const ispdbResult = await lookupIspdb(domain, {
494
+ timeout: options.timeout,
495
+ fetch: options.fetch
496
+ });
497
+ connection = ispdbResult.connection;
498
+ ispdbRaw = ispdbResult.raw;
499
+ }
500
+ const result = {
501
+ email,
502
+ domain,
503
+ provider: null,
504
+ mx: primaryMx,
505
+ type: FREE_DOMAINS.has(domain) ? "free" : "business",
506
+ isFree: FREE_DOMAINS.has(domain),
507
+ hasMx: true,
508
+ connection: connection ? resolveConnection(connection, email, domain) : null,
509
+ confidence: connection ? "medium" : "low",
510
+ source: connection ? "mx-lookup" : null,
511
+ raw: { mx: mxRecords, dns: dnsRaw, ispdb: ispdbRaw }
512
+ };
513
+ cache?.set(domain, result, cacheTtl);
514
+ return result;
515
+ }
516
+ function emptyResult(email, domain) {
517
+ return {
518
+ email,
519
+ domain,
520
+ provider: null,
521
+ mx: null,
522
+ type: "unknown",
523
+ isFree: false,
524
+ hasMx: false,
525
+ connection: null,
526
+ confidence: "low",
527
+ source: null,
528
+ raw: { mx: null, dns: null, ispdb: null }
529
+ };
530
+ }
531
+
532
+ // src/cache.ts
533
+ var Cache = class {
534
+ store = /* @__PURE__ */ new Map();
535
+ get(key) {
536
+ const entry = this.store.get(key);
537
+ if (!entry) return null;
538
+ if (Date.now() > entry.expires) {
539
+ this.store.delete(key);
540
+ return null;
541
+ }
542
+ return entry.value;
543
+ }
544
+ set(key, value, ttl) {
545
+ this.store.set(key, { value, expires: Date.now() + ttl });
546
+ }
547
+ clear() {
548
+ this.store.clear();
549
+ }
550
+ };
551
+
552
+ // src/factory.ts
553
+ function createMailintel(options = {}) {
554
+ const cache = options.cache !== false ? new Cache() : null;
555
+ const cacheTtl = options.cacheTtl ?? 30 * 60 * 1e3;
556
+ async function mailintel(input, callOptions) {
557
+ const mergedOptions = { ...options, ...callOptions };
558
+ if (Array.isArray(input)) {
559
+ return Promise.all(input.map((email) => mailintelCore(email, mergedOptions, cache, cacheTtl)));
560
+ }
561
+ return mailintelCore(input, mergedOptions, cache, cacheTtl);
562
+ }
563
+ mailintel.clearCache = () => cache?.clear();
564
+ return mailintel;
565
+ }
566
+
567
+ // src/cli.ts
568
+ var HELP = `
569
+ mailintel - Resolve email providers and IMAP/SMTP settings
570
+
571
+ Usage
572
+ $ mailintel <email> [email...]
573
+
574
+ Options
575
+ --json Output raw JSON
576
+ --timeout <ms> Network timeout (default: 5000)
577
+ --resolver <name> DNS resolver: cloudflare (default) or google
578
+ --no-cache Disable caching (useful for multiple lookups)
579
+ --no-ispdb Skip Thunderbird ISPDB fallback
580
+ --help, -h Show this help
581
+ --version, -v Show version
582
+
583
+ Examples
584
+ $ mailintel user@gmail.com
585
+ $ mailintel ceo@acme-corp.com admin@corp.com --json
586
+ $ npx mailintel user@example.com --resolver google
587
+ `.trimStart();
588
+ function parseArgs(argv) {
589
+ const args = {
590
+ emails: [],
591
+ json: false,
592
+ timeout: 5e3,
593
+ resolver: "cloudflare",
594
+ cache: true,
595
+ ispdb: true,
596
+ help: false,
597
+ version: false
598
+ };
599
+ for (let i = 0; i < argv.length; i++) {
600
+ const arg = argv[i];
601
+ switch (arg) {
602
+ case "--json":
603
+ args.json = true;
604
+ break;
605
+ case "--timeout":
606
+ args.timeout = parseInt(argv[++i], 10) || 5e3;
607
+ break;
608
+ case "--resolver":
609
+ args.resolver = argv[++i] === "google" ? "google" : "cloudflare";
610
+ break;
611
+ case "--no-cache":
612
+ args.cache = false;
613
+ break;
614
+ case "--no-ispdb":
615
+ args.ispdb = false;
616
+ break;
617
+ case "--help":
618
+ case "-h":
619
+ args.help = true;
620
+ break;
621
+ case "--version":
622
+ case "-v":
623
+ args.version = true;
624
+ break;
625
+ default:
626
+ if (!arg.startsWith("-")) {
627
+ args.emails.push(arg);
628
+ }
629
+ break;
630
+ }
631
+ }
632
+ return args;
633
+ }
634
+ function dim(text) {
635
+ return `\x1B[2m${text}\x1B[0m`;
636
+ }
637
+ function bold(text) {
638
+ return `\x1B[1m${text}\x1B[0m`;
639
+ }
640
+ function green(text) {
641
+ return `\x1B[32m${text}\x1B[0m`;
642
+ }
643
+ function yellow(text) {
644
+ return `\x1B[33m${text}\x1B[0m`;
645
+ }
646
+ function red(text) {
647
+ return `\x1B[31m${text}\x1B[0m`;
648
+ }
649
+ function cyan(text) {
650
+ return `\x1B[36m${text}\x1B[0m`;
651
+ }
652
+ function confidenceColor(confidence) {
653
+ switch (confidence) {
654
+ case "high":
655
+ return green(confidence);
656
+ case "medium":
657
+ return yellow(confidence);
658
+ default:
659
+ return red(confidence);
660
+ }
661
+ }
662
+ function formatResult(result) {
663
+ const lines = [];
664
+ lines.push(bold(result.email || result.domain));
665
+ lines.push("");
666
+ if (result.provider) {
667
+ lines.push(` provider ${cyan(result.provider)}`);
668
+ } else {
669
+ lines.push(` provider ${dim("unknown")}`);
670
+ }
671
+ lines.push(` domain ${result.domain}`);
672
+ lines.push(` type ${result.type}${result.isFree ? dim(" (free)") : ""}`);
673
+ lines.push(` confidence ${confidenceColor(result.confidence)}`);
674
+ if (result.mx) {
675
+ lines.push(` mx ${result.mx}`);
676
+ }
677
+ if (result.source) {
678
+ lines.push(` source ${dim(result.source)}`);
679
+ }
680
+ if (result.connection) {
681
+ const { imap, smtp, username } = result.connection;
682
+ lines.push("");
683
+ lines.push(` ${bold("IMAP")} ${imap.host}:${imap.port} ${imap.secure ? green("SSL") : yellow("STARTTLS")}`);
684
+ lines.push(` ${bold("SMTP")} ${smtp.host}:${smtp.port} ${smtp.secure ? green("SSL") : yellow("STARTTLS")}`);
685
+ lines.push(` ${bold("Username")} ${dim(username)}`);
686
+ } else {
687
+ lines.push("");
688
+ lines.push(` ${dim("No connection settings found")}`);
689
+ }
690
+ return lines.join("\n");
691
+ }
692
+ async function main() {
693
+ const args = parseArgs(process.argv.slice(2));
694
+ if (args.version) {
695
+ process.stdout.write("0.2.0\n");
696
+ return;
697
+ }
698
+ if (args.help || args.emails.length === 0) {
699
+ process.stdout.write(HELP);
700
+ process.exitCode = args.help ? 0 : 1;
701
+ return;
702
+ }
703
+ const options = {
704
+ timeout: args.timeout,
705
+ cache: args.cache,
706
+ ispdb: args.ispdb,
707
+ mxLookup: args.resolver === "google" ? "google" : true
708
+ };
709
+ const mailintel = createMailintel(options);
710
+ const results = [];
711
+ for (const email of args.emails) {
712
+ const result = await mailintel(email);
713
+ results.push(result);
714
+ }
715
+ if (args.json) {
716
+ process.stdout.write(JSON.stringify(results.length === 1 ? results[0] : results, null, 2) + "\n");
717
+ return;
718
+ }
719
+ for (let i = 0; i < results.length; i++) {
720
+ if (i > 0) process.stdout.write("\n" + dim("---") + "\n\n");
721
+ process.stdout.write(formatResult(results[i]) + "\n");
722
+ }
723
+ }
724
+ main().catch((err) => {
725
+ process.stderr.write(`Error: ${err.message}
726
+ `);
727
+ process.exitCode = 1;
728
+ });