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/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Ahmed Atef
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
# Mailintel
|
|
2
|
+
|
|
3
|
+
Resolve email providers and IMAP/SMTP settings from any email address or domain. Zero npm dependencies.
|
|
4
|
+
|
|
5
|
+
If you're building an app where users connect their email - a CRM, helpdesk, mail client, or anything that sends/receives on their behalf - you normally have to ask them to manually enter their SMTP host, IMAP port, SSL toggle, and username. Mailintel does this automatically. Give it an email or domain and it returns everything you need to connect.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install mailintel
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## API
|
|
14
|
+
|
|
15
|
+
```typescript
|
|
16
|
+
import { mailintel } from 'mailintel';
|
|
17
|
+
|
|
18
|
+
// With an email - username is resolved automatically
|
|
19
|
+
const result = await mailintel('ahmed@atef.dev');
|
|
20
|
+
// result.provider => 'google'
|
|
21
|
+
// result.connection.imap => { host: 'imap.gmail.com', port: 993, secure: true }
|
|
22
|
+
// result.connection.username => 'ahmed@atef.dev'
|
|
23
|
+
// result.type => 'business'
|
|
24
|
+
// result.confidence => 'high'
|
|
25
|
+
|
|
26
|
+
// With just a domain - same result, username stays as template
|
|
27
|
+
const result = await mailintel('atef.dev');
|
|
28
|
+
// result.connection.username => '%EMAILADDRESS%'
|
|
29
|
+
|
|
30
|
+
// Multiple inputs at once
|
|
31
|
+
const results = await mailintel(['ahmed@atef.dev', 'example.com', 'user@gmail.com']);
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
<details>
|
|
35
|
+
<summary>Full result example</summary>
|
|
36
|
+
|
|
37
|
+
```json
|
|
38
|
+
{
|
|
39
|
+
"email": "ahmed@atef.dev",
|
|
40
|
+
"domain": "atef.dev",
|
|
41
|
+
"provider": "google",
|
|
42
|
+
"mx": "smtp.google.com",
|
|
43
|
+
"type": "business",
|
|
44
|
+
"isFree": false,
|
|
45
|
+
"hasMx": true,
|
|
46
|
+
"connection": {
|
|
47
|
+
"imap": { "host": "imap.gmail.com", "port": 993, "secure": true },
|
|
48
|
+
"smtp": { "host": "smtp.gmail.com", "port": 465, "secure": true },
|
|
49
|
+
"username": "ahmed@atef.dev",
|
|
50
|
+
"usernameTemplate": "%EMAILADDRESS%"
|
|
51
|
+
},
|
|
52
|
+
"confidence": "high",
|
|
53
|
+
"source": "mx-lookup",
|
|
54
|
+
"raw": {
|
|
55
|
+
"mx": [{ "priority": 1, "exchange": "smtp.google.com" }],
|
|
56
|
+
"dns": { "Status": 0, "Answer": [{ "name": "atef.dev", "type": 15, "TTL": 300, "data": "1 smtp.google.com." }] },
|
|
57
|
+
"ispdb": null
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
The API and CLI return the same structure. The CLI's `--json` flag outputs this exact format.
|
|
63
|
+
|
|
64
|
+
</details>
|
|
65
|
+
|
|
66
|
+
### Factory
|
|
67
|
+
|
|
68
|
+
Use `createMailintel()` for reusable config, custom overrides, or a shared cache:
|
|
69
|
+
|
|
70
|
+
```typescript
|
|
71
|
+
import { createMailintel } from 'mailintel';
|
|
72
|
+
|
|
73
|
+
const lookup = createMailintel({
|
|
74
|
+
timeout: 3000,
|
|
75
|
+
providers: {
|
|
76
|
+
'megacorp.io': {
|
|
77
|
+
provider: 'internal',
|
|
78
|
+
imap: { host: 'imap.megacorp.io', port: 993, secure: true },
|
|
79
|
+
smtp: { host: 'smtp.megacorp.io', port: 465, secure: true },
|
|
80
|
+
},
|
|
81
|
+
},
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
await lookup('admin@megacorp.io'); // uses override, no network call
|
|
85
|
+
lookup.clearCache();
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Options
|
|
89
|
+
|
|
90
|
+
| Option | Type | Default | Description |
|
|
91
|
+
|--------|------|---------|-------------|
|
|
92
|
+
| `timeout` | `number` | `5000` | Network request timeout (ms) |
|
|
93
|
+
| `cache` | `boolean` | `true` | In-memory domain caching |
|
|
94
|
+
| `cacheTtl` | `number` | `1800000` | Cache TTL in ms (30 min) |
|
|
95
|
+
| `mxLookup` | `boolean \| 'cloudflare' \| 'google'` | `true` | `true` or `'cloudflare'` = Cloudflare DNS, `'google'` = Google DNS, `false` = disabled |
|
|
96
|
+
| `ispdb` | `boolean` | `true` | Thunderbird ISPDB fallback |
|
|
97
|
+
| `fetch` | `typeof fetch` | `globalThis.fetch` | Custom fetch (useful for proxies or testing) |
|
|
98
|
+
| `providers` | `Record<string, ProviderOverride>` | - | Domain-to-provider overrides |
|
|
99
|
+
| `mxOverrides` | `Record<string, ProviderOverride>` | - | MX suffix-to-provider overrides |
|
|
100
|
+
|
|
101
|
+
## CLI
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
npx mailintel ahmed@atef.dev
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
```
|
|
108
|
+
ahmed@atef.dev
|
|
109
|
+
|
|
110
|
+
provider google
|
|
111
|
+
domain atef.dev
|
|
112
|
+
type business
|
|
113
|
+
confidence high
|
|
114
|
+
mx smtp.google.com
|
|
115
|
+
source mx-lookup
|
|
116
|
+
|
|
117
|
+
IMAP imap.gmail.com:993 SSL
|
|
118
|
+
SMTP smtp.gmail.com:465 SSL
|
|
119
|
+
Username ahmed@atef.dev
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Supports multiple emails, domain-only lookups, and JSON output:
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
mailintel user@gmail.com admin@example.com # multiple emails
|
|
126
|
+
mailintel atef.dev # domain-only lookup
|
|
127
|
+
mailintel ahmed@atef.dev --json # machine-readable JSON
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### CLI options
|
|
131
|
+
|
|
132
|
+
| Flag | Description |
|
|
133
|
+
|------|-------------|
|
|
134
|
+
| `--json` | Output raw JSON |
|
|
135
|
+
| `--timeout <ms>` | Network timeout (default: 5000) |
|
|
136
|
+
| `--resolver <name>` | DNS resolver: `cloudflare` (default) or `google` |
|
|
137
|
+
| `--no-cache` | Disable caching |
|
|
138
|
+
| `--no-ispdb` | Skip Thunderbird ISPDB fallback |
|
|
139
|
+
| `-h, --help` | Show help |
|
|
140
|
+
| `-v, --version` | Show version |
|
|
141
|
+
|
|
142
|
+
## How it works
|
|
143
|
+
|
|
144
|
+
```mermaid
|
|
145
|
+
flowchart TD
|
|
146
|
+
classDef external fill:#dbeafe,stroke:#3b82f6,color:#1e3a5f
|
|
147
|
+
|
|
148
|
+
A(["ahmed@atef.dev"]) --> B[Check cache]
|
|
149
|
+
|
|
150
|
+
B -->|hit| Z1([return cached result])
|
|
151
|
+
B -->|miss| C{User domain override?}
|
|
152
|
+
|
|
153
|
+
C -->|hit| Z2(["return — confidence: high, source: override"])
|
|
154
|
+
C -->|miss| D{"Known domain?<br/>gmail.com, outlook.com<br/>~50 built-in"}
|
|
155
|
+
|
|
156
|
+
D -->|hit| Z3(["return — confidence: high, source: known-domain"])
|
|
157
|
+
D -->|miss| E["🌐 DNS MX lookup<br/>cloudflare-dns.com or dns.google"]
|
|
158
|
+
|
|
159
|
+
E --> F{User MX override?}
|
|
160
|
+
F -->|hit| Z4(["return — confidence: high, source: mx-lookup"])
|
|
161
|
+
F -->|miss| G{"Known MX pattern?<br/>*.google.com, *.zoho.com<br/>~30 built-in"}
|
|
162
|
+
|
|
163
|
+
G -->|hit| H["Get provider settings<br/>apply regional variant if needed"]
|
|
164
|
+
G -->|miss| I["🌐 Thunderbird ISPDB<br/>autoconfig.thunderbird.net"]
|
|
165
|
+
|
|
166
|
+
H --> J(["return — confidence: high, source: mx-lookup"])
|
|
167
|
+
I -->|found| K(["return — confidence: medium, source: mx-lookup"])
|
|
168
|
+
I -->|not found| L(["return — connection: null, confidence: low"])
|
|
169
|
+
|
|
170
|
+
class E,I external
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
At most 2 HTTP requests per uncached lookup - one DNS query and one ISPDB fetch. Known domains resolve instantly with zero network calls.
|
|
174
|
+
|
|
175
|
+
### How it gets the data
|
|
176
|
+
|
|
177
|
+
Every email domain has **MX records** in DNS that say which mail server handles its email. `atef.dev` points to `smtp.google.com` (Google Workspace), another domain might point to `mx.zoho.com` (Zoho).
|
|
178
|
+
|
|
179
|
+
Mailintel queries these using **DNS-over-HTTPS** - plain HTTPS requests to public DNS resolvers, not system-level DNS calls. Works in serverless functions, edge runtimes, and anywhere `fetch` is available. No native modules, no UDP sockets, no special permissions.
|
|
180
|
+
|
|
181
|
+
| Service | URL | What it returns |
|
|
182
|
+
|---------|-----|-----------------|
|
|
183
|
+
| **Cloudflare DNS** (default) | `cloudflare-dns.com/dns-query?name=atef.dev&type=MX` * | MX records - which mail server handles the domain |
|
|
184
|
+
| **Google DNS** (alternative) | `dns.google/resolve?name=atef.dev&type=MX` | Same MX records, different resolver |
|
|
185
|
+
| **Thunderbird ISPDB** (fallback) | `autoconfig.thunderbird.net/v1.1/{domain}` | IMAP/SMTP settings from Mozilla's open database |
|
|
186
|
+
|
|
187
|
+
\* Requires an `Accept: application/dns-json` header. Opening this URL in a browser returns an HTML page, not JSON. Mailintel sets this header automatically.
|
|
188
|
+
|
|
189
|
+
**Rate limits**: Cloudflare DNS has no published limits and is free ([docs](https://developers.cloudflare.com/1.1.1.1/encryption/dns-over-https/make-api-requests/dns-json/)). Google DNS has undisclosed limits and returns HTTP 429 when exceeded ([docs](https://developers.google.com/speed/public-dns/docs/doh)). Thunderbird ISPDB is a static file server with no published limits. The built-in cache means you'll rarely hit any of these more than once per domain.
|
|
190
|
+
|
|
191
|
+
Once the MX server is known, it's matched against ~30 provider patterns. For well-known free domains like `gmail.com`, the network is skipped entirely - settings come from a built-in map of [~50 known domains](src/data/domains.ts).
|
|
192
|
+
|
|
193
|
+
## Result type
|
|
194
|
+
|
|
195
|
+
```typescript
|
|
196
|
+
interface MailintelResult {
|
|
197
|
+
email: string; // input email, or '' for domain-only lookups
|
|
198
|
+
domain: string;
|
|
199
|
+
provider: string | null; // 'google', 'microsoft', 'zoho', etc.
|
|
200
|
+
mx: string | null; // primary MX hostname
|
|
201
|
+
type: 'free' | 'business' | 'unknown';
|
|
202
|
+
isFree: boolean;
|
|
203
|
+
hasMx: boolean;
|
|
204
|
+
connection: { // null when settings can't be determined
|
|
205
|
+
imap: { host: string; port: number; secure: boolean };
|
|
206
|
+
smtp: { host: string; port: number; secure: boolean };
|
|
207
|
+
username: string; // resolved: 'ahmed@atef.dev'
|
|
208
|
+
usernameTemplate: string; // raw template: '%EMAILADDRESS%'
|
|
209
|
+
} | null;
|
|
210
|
+
confidence: 'high' | 'medium' | 'low';
|
|
211
|
+
source: 'override' | 'known-domain' | 'mx-lookup' | null;
|
|
212
|
+
raw: { mx, dns, ispdb }; // raw data for debugging
|
|
213
|
+
}
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
### Username
|
|
217
|
+
|
|
218
|
+
`username` is the resolved value you pass directly to the mail server. When the input is a domain (no email), it stays as the raw template since there's no email to resolve.
|
|
219
|
+
|
|
220
|
+
`usernameTemplate` is the raw template, useful if you're building a config UI. Templates follow the [Thunderbird ISPDB convention](https://wiki.mozilla.org/Thunderbird:Autoconfiguration:ConfigFileFormat):
|
|
221
|
+
|
|
222
|
+
| Template | Resolves to | Used by |
|
|
223
|
+
|----------|------------|---------|
|
|
224
|
+
| `%EMAILADDRESS%` | `ahmed@atef.dev` | Nearly all modern providers |
|
|
225
|
+
| `%EMAILLOCALPART%` | `ahmed` | Some older/self-hosted setups |
|
|
226
|
+
| `%EMAILDOMAIN%` | `atef.dev` | Rare |
|
|
227
|
+
|
|
228
|
+
All built-in providers use `%EMAILADDRESS%`. The ISPDB fallback may return any of the three depending on what Thunderbird's database has for that provider.
|
|
229
|
+
|
|
230
|
+
## Supported providers
|
|
231
|
+
|
|
232
|
+
Google, Microsoft, Yahoo, Zoho (with EU/IN/AU/JP regional variants), iCloud, Fastmail, ProtonMail, GoDaddy, Titan, OVH, IONOS, Hostinger, Yandex, AOL, Rackspace, DreamHost - plus any provider discoverable via MX records or Thunderbird ISPDB.
|
|
233
|
+
|
|
234
|
+
## Contributing
|
|
235
|
+
|
|
236
|
+
Missing a provider or found incorrect settings? [Open an issue](https://github.com/AhmedAtef07/mailintel/issues) or submit a PR.
|
|
237
|
+
|
|
238
|
+
## License
|
|
239
|
+
|
|
240
|
+
MIT
|