@mikkelscheike/email-provider-links 1.0.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 ADDED
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Email Provider Links
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.
22
+
package/README.md ADDED
@@ -0,0 +1,111 @@
1
+ # Email Provider Links
2
+
3
+ A TypeScript package that provides direct links to email providers based on email addresses to streamline login and password reset flows.
4
+
5
+ ## Features
6
+
7
+ - 🚀 **Fast & Lightweight**: Zero dependencies, minimal footprint
8
+ - 📧 **55+ Email Providers**: Gmail, Outlook, Yahoo, ProtonMail, and more
9
+ - 🏢 **Business Domain Detection**: DNS-based detection for custom domains
10
+ - 🔒 **Type Safe**: Full TypeScript support
11
+ - ⚡ **Performance Optimized**: Smart DNS fallback with configurable timeouts
12
+
13
+ ## Installation
14
+
15
+ ```bash
16
+ npm install @mikkelscheike/email-provider-links
17
+ ```
18
+
19
+ ## Quick Start
20
+
21
+ ```typescript
22
+ import { getEmailProviderLinkWithDNS } from '@mikkelscheike/email-provider-links';
23
+
24
+ // Works for any email address
25
+ const result = await getEmailProviderLinkWithDNS('user@gmail.com');
26
+ console.log(result.loginUrl); // "https://mail.google.com/mail/"
27
+
28
+ // Business domains too
29
+ const business = await getEmailProviderLinkWithDNS('user@mycompany.com');
30
+ console.log(business.provider?.companyProvider); // "Google Workspace" (if detected)
31
+ ```
32
+
33
+ ## Supported Providers
34
+
35
+ **Consumer Email:**
36
+ Gmail, Outlook, Yahoo Mail, iCloud, ProtonMail, Zoho, AOL, GMX, Web.de, Mail.ru, QQ Mail, NetEase, Yandex, and more.
37
+
38
+ **Business Email (via DNS detection):**
39
+ Microsoft 365, Google Workspace, ProtonMail Business, FastMail, Tutanota, Zoho Workplace, and others.
40
+
41
+ ## API
42
+
43
+ ### `getEmailProviderLinkWithDNS(email, timeout?)`
44
+ **Recommended** - Detects any email provider including business domains.
45
+
46
+ ```typescript
47
+ const result = await getEmailProviderLinkWithDNS('user@gmail.com', 3000);
48
+ // Returns: { provider, loginUrl, detectionMethod, email }
49
+ ```
50
+
51
+ ### `getEmailProviderLink(email)`
52
+ **Synchronous** - Only checks predefined domains (no DNS lookup).
53
+
54
+ ```typescript
55
+ const result = getEmailProviderLink('user@gmail.com');
56
+ // Returns: { provider, loginUrl, email }
57
+ ```
58
+
59
+ ## Real-World Example
60
+
61
+ ```typescript
62
+ async function handlePasswordReset(email: string) {
63
+ const result = await getEmailProviderLinkWithDNS(email);
64
+
65
+ return {
66
+ providerUrl: result.loginUrl,
67
+ providerName: result.provider?.companyProvider || null,
68
+ isSupported: result.provider !== null
69
+ };
70
+ }
71
+ ```
72
+
73
+ ## Configuration
74
+
75
+ ```typescript
76
+ // Custom DNS timeout (default: 5000ms)
77
+ const result = await getEmailProviderLinkWithDNS(email, 2000);
78
+
79
+ // Check if provider is supported
80
+ import { isEmailProviderSupported } from '@mikkelscheike/email-provider-links';
81
+ const supported = isEmailProviderSupported('user@gmail.com');
82
+ ```
83
+
84
+ ## TypeScript Support
85
+
86
+ ```typescript
87
+ interface EmailProviderResult {
88
+ provider: EmailProvider | null;
89
+ email: string;
90
+ loginUrl: string | null;
91
+ detectionMethod?: 'domain_match' | 'mx_record' | 'txt_record' | 'proxy_detected';
92
+ proxyService?: string;
93
+ }
94
+ ```
95
+
96
+ ## Contributing
97
+
98
+ We welcome contributions! See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines on adding new email providers.
99
+
100
+ ## Security
101
+
102
+ For security concerns, see our [Security Policy](SECURITY.md).
103
+
104
+ ## License
105
+
106
+ MIT License - see [LICENSE](LICENSE) file for details.
107
+
108
+ ---
109
+
110
+ **Zero dependencies • TypeScript-first • Production ready**
111
+
@@ -0,0 +1,317 @@
1
+ /**
2
+ * Email Provider Links
3
+ *
4
+ * A TypeScript package that provides direct links to email providers
5
+ * based on email addresses to streamline login and password reset flows.
6
+ *
7
+ * The package uses a two-tier detection system:
8
+ * 1. Fast domain lookup against a JSON database of known providers
9
+ * 2. DNS-based detection for custom business domains using MX/TXT record analysis
10
+ *
11
+ * @packageDocumentation
12
+ */
13
+ /**
14
+ * Represents an email provider with its associated domains and login URL.
15
+ *
16
+ * @interface EmailProvider
17
+ * @example
18
+ * ```typescript
19
+ * {
20
+ * companyProvider: "Gmail",
21
+ * loginUrl: "https://mail.google.com/mail/",
22
+ * domains: ["gmail.com", "googlemail.com"],
23
+ * customDomainDetection: {
24
+ * mxPatterns: ["aspmx.l.google.com"],
25
+ * txtPatterns: ["v=spf1 include:_spf.google.com"]
26
+ * }
27
+ * }
28
+ * ```
29
+ */
30
+ export interface EmailProvider {
31
+ /** Human-readable name of the email provider company */
32
+ companyProvider: string;
33
+ /** Direct URL to the provider's login/webmail page */
34
+ loginUrl: string;
35
+ /** Array of email domains this provider handles (e.g., ['gmail.com', 'googlemail.com']) */
36
+ domains: string[];
37
+ /** Optional DNS-based detection patterns for custom business domains */
38
+ customDomainDetection?: {
39
+ /** MX record patterns to match against (e.g., ['aspmx.l.google.com']) */
40
+ mxPatterns?: string[];
41
+ /** TXT record patterns to match against (e.g., ['v=spf1 include:_spf.google.com']) */
42
+ txtPatterns?: string[];
43
+ };
44
+ }
45
+ /**
46
+ * Result object returned by email provider detection functions.
47
+ *
48
+ * @interface EmailProviderResult
49
+ * @example
50
+ * ```typescript
51
+ * {
52
+ * provider: { companyProvider: "Gmail", loginUrl: "https://mail.google.com/mail/", domains: ["gmail.com"] },
53
+ * email: "user@gmail.com",
54
+ * loginUrl: "https://mail.google.com/mail/",
55
+ * detectionMethod: "domain_match"
56
+ * }
57
+ * ```
58
+ */
59
+ export interface EmailProviderResult {
60
+ /** The detected email provider, or null if not found/behind proxy */
61
+ provider: EmailProvider | null;
62
+ /** The original email address that was analyzed */
63
+ email: string;
64
+ /** Direct URL to the email provider's login page, or null if unknown */
65
+ loginUrl: string | null;
66
+ /** Method used to detect the provider */
67
+ detectionMethod?: 'domain_match' | 'mx_record' | 'txt_record' | 'proxy_detected';
68
+ /** If a proxy service was detected, which service (e.g., 'Cloudflare') */
69
+ proxyService?: string;
70
+ }
71
+ /**
72
+ * Result object returned by DNS-based provider detection.
73
+ *
74
+ * @interface DNSDetectionResult
75
+ * @example
76
+ * ```typescript
77
+ * {
78
+ * provider: { companyProvider: "Google Workspace", ... },
79
+ * detectionMethod: "mx_record",
80
+ * proxyService: undefined
81
+ * }
82
+ * ```
83
+ */
84
+ export interface DNSDetectionResult {
85
+ /** The detected email provider, or null if not found/behind proxy */
86
+ provider: EmailProvider | null;
87
+ /** Method used for DNS-based detection */
88
+ detectionMethod: 'mx_record' | 'txt_record' | 'proxy_detected' | null;
89
+ /** If a proxy service was detected, which service (e.g., 'Cloudflare') */
90
+ proxyService?: string;
91
+ }
92
+ /**
93
+ * Validates if a string is a valid email address using a basic regex pattern.
94
+ *
95
+ * @param email - The string to validate as an email address
96
+ * @returns true if the string matches basic email format, false otherwise
97
+ *
98
+ * @example
99
+ * ```typescript
100
+ * isValidEmail('user@gmail.com'); // true
101
+ * isValidEmail('invalid-email'); // false
102
+ * isValidEmail('user@domain'); // false
103
+ * ```
104
+ *
105
+ * @remarks
106
+ * This uses a simple regex pattern that covers most common email formats.
107
+ * It may not catch all edge cases defined in RFC 5322, but works for
108
+ * standard email addresses.
109
+ */
110
+ export declare function isValidEmail(email: string): boolean;
111
+ /**
112
+ * Extracts the domain portion from an email address.
113
+ *
114
+ * @param email - The email address to extract the domain from
115
+ * @returns The domain in lowercase, or null if the email is invalid
116
+ *
117
+ * @example
118
+ * ```typescript
119
+ * extractDomain('user@Gmail.com'); // 'gmail.com'
120
+ * extractDomain('test@yahoo.co.uk'); // 'yahoo.co.uk'
121
+ * extractDomain('invalid-email'); // null
122
+ * ```
123
+ *
124
+ * @remarks
125
+ * The domain is automatically normalized to lowercase for consistent matching.
126
+ */
127
+ export declare function extractDomain(email: string): string | null;
128
+ /**
129
+ * Finds an email provider by matching the domain against the known providers database.
130
+ * Uses an optimized Map for O(1) lookup performance.
131
+ *
132
+ * @param domain - The email domain to look up (e.g., 'gmail.com')
133
+ * @returns The matching EmailProvider object, or null if not found
134
+ *
135
+ * @example
136
+ * ```typescript
137
+ * const provider = findEmailProvider('gmail.com');
138
+ * console.log(provider?.companyProvider); // 'Gmail'
139
+ * console.log(provider?.loginUrl); // 'https://mail.google.com/mail/'
140
+ * ```
141
+ *
142
+ * @remarks
143
+ * This function performs a case-insensitive O(1) lookup using a pre-built Map.
144
+ * It only checks the predefined JSON database, not DNS records.
145
+ * Performance optimized from O(n*m) to O(1) where n=providers, m=domains per provider.
146
+ */
147
+ export declare function findEmailProvider(domain: string): EmailProvider | null;
148
+ /**
149
+ * Gets email provider information and login URL for a given email address.
150
+ * This is the basic/synchronous version that only checks predefined domains.
151
+ *
152
+ * @param email - The email address to analyze
153
+ * @returns EmailProviderResult containing provider info and login URL
154
+ *
155
+ * @example
156
+ * ```typescript
157
+ * const result = getEmailProviderLink('user@gmail.com');
158
+ * console.log(result.loginUrl); // 'https://mail.google.com/mail/'
159
+ * console.log(result.provider?.companyProvider); // 'Gmail'
160
+ * ```
161
+ *
162
+ * @remarks
163
+ * This function only checks against the predefined JSON database of known domains.
164
+ * It will NOT detect business domains that use major email providers (e.g.,
165
+ * mycompany.com using Google Workspace). For comprehensive detection including
166
+ * business domains, use {@link getEmailProviderLinkWithDNS} instead.
167
+ *
168
+ * **Limitations:**
169
+ * - Only synchronous operation (no DNS lookups)
170
+ * - Limited to domains in the JSON database
171
+ * - Won't detect custom business domains
172
+ * - No proxy service detection
173
+ */
174
+ export declare function getEmailProviderLink(email: string): EmailProviderResult;
175
+ /**
176
+ * Returns an array of all supported email providers.
177
+ *
178
+ * @returns A copy of the EMAIL_PROVIDERS array
179
+ *
180
+ * @example
181
+ * ```typescript
182
+ * const providers = getSupportedProviders();
183
+ * console.log(providers.length); // 55+
184
+ * console.log(providers[0].companyProvider); // 'Gmail'
185
+ * ```
186
+ *
187
+ * @remarks
188
+ * Returns a shallow copy to prevent external modification of the internal
189
+ * providers array. The returned array includes both consumer email providers
190
+ * (gmail.com, yahoo.com) and business email providers with DNS detection patterns.
191
+ */
192
+ export declare function getSupportedProviders(): EmailProvider[];
193
+ /**
194
+ * Checks if an email address uses a supported email provider.
195
+ *
196
+ * @param email - The email address to check
197
+ * @returns true if the provider is supported, false otherwise
198
+ *
199
+ * @example
200
+ * ```typescript
201
+ * isEmailProviderSupported('user@gmail.com'); // true
202
+ * isEmailProviderSupported('user@unknown.com'); // false
203
+ * ```
204
+ *
205
+ * @remarks
206
+ * This is a convenience function that uses {@link getEmailProviderLink} internally.
207
+ * It only checks predefined domains, not DNS-based detection. For business
208
+ * domain support checking, you would need to use {@link getEmailProviderLinkWithDNS}.
209
+ */
210
+ export declare function isEmailProviderSupported(email: string): boolean;
211
+ /**
212
+ * Performs DNS-based detection for custom business domains using MX and TXT record analysis.
213
+ * This function is used internally by {@link getEmailProviderLinkWithDNS} but can also be
214
+ * called directly to analyze domain email configuration.
215
+ *
216
+ * @param domain - The domain to analyze (e.g., 'mycompany.com')
217
+ * @param timeoutMs - Optional timeout for DNS queries in milliseconds (default: 5000ms)
218
+ * @returns Promise resolving to DNSDetectionResult with provider info or proxy detection
219
+ *
220
+ * @example
221
+ * ```typescript
222
+ * const result = await detectProviderByDNS('microsoft.com');
223
+ * console.log(result.provider?.companyProvider); // 'Microsoft 365 (Business)'
224
+ * console.log(result.detectionMethod); // 'mx_record'
225
+ * ```
226
+ *
227
+ * @remarks
228
+ * **Detection Algorithm:**
229
+ * 1. Performs MX record lookup for the domain
230
+ * 2. Checks if MX records match known proxy services (Cloudflare, etc.)
231
+ * 3. If proxy detected, returns null provider with proxy info
232
+ * 4. Otherwise, matches MX records against business email provider patterns
233
+ * 5. If no MX match, falls back to TXT record analysis (SPF records, etc.)
234
+ * 6. Returns the first matching provider or null if none found
235
+ *
236
+ * **Provider Patterns Checked:**
237
+ * - Google Workspace: aspmx.l.google.com, aspmx2.googlemail.com, etc.
238
+ * - Microsoft 365: *.protection.outlook.com, *.outlook.com
239
+ * - ProtonMail: mail.protonmail.ch, mailsec.protonmail.ch
240
+ * - FastMail: *.messagingengine.com
241
+ * - And many others...
242
+ *
243
+ * **Error Handling:**
244
+ * DNS lookup failures are caught and the function gracefully falls back
245
+ * to the next detection method or returns null if all methods fail.
246
+ */
247
+ export declare function detectProviderByDNS(domain: string, timeoutMs?: number): Promise<DNSDetectionResult>;
248
+ /**
249
+ * Enhanced email provider detection with automatic DNS-based custom domain detection.
250
+ * This is the recommended function for most use cases as it provides comprehensive
251
+ * detection coverage including business domains and proxy services.
252
+ *
253
+ * @param email - The email address to analyze
254
+ * @param timeoutMs - Optional timeout for DNS queries in milliseconds (default: 5000ms)
255
+ * @returns Promise resolving to EmailProviderResult with provider info and detection method
256
+ *
257
+ * @example
258
+ * ```typescript
259
+ * // Consumer email (fast domain match)
260
+ * const gmail = await getEmailProviderLinkWithDNS('user@gmail.com');
261
+ * console.log(gmail.provider?.companyProvider); // 'Gmail'
262
+ * console.log(gmail.detectionMethod); // 'domain_match'
263
+ *
264
+ * // Business domain (DNS detection)
265
+ * const business = await getEmailProviderLinkWithDNS('user@mycompany.com');
266
+ * console.log(business.provider?.companyProvider); // 'Google Workspace' (if detected)
267
+ * console.log(business.detectionMethod); // 'mx_record'
268
+ *
269
+ * // Proxied domain (proxy detection)
270
+ * const proxied = await getEmailProviderLinkWithDNS('user@proxied-domain.com');
271
+ * console.log(proxied.provider); // null
272
+ * console.log(proxied.proxyService); // 'Cloudflare'
273
+ * console.log(proxied.detectionMethod); // 'proxy_detected'
274
+ * ```
275
+ *
276
+ * @remarks
277
+ * **Detection Hierarchy (in order):**
278
+ * 1. **Domain Match**: Fast lookup against predefined domains (gmail.com, yahoo.com, etc.)
279
+ * 2. **DNS MX Records**: Analyzes mail exchange records for business email providers
280
+ * 3. **DNS TXT Records**: Checks SPF and verification records as fallback
281
+ * 4. **Proxy Detection**: Identifies when domains are behind CDN/proxy services
282
+ *
283
+ * **Supported Detection Cases:**
284
+ * - ✅ Consumer emails: gmail.com, yahoo.com, outlook.com, etc.
285
+ * - ✅ Business domains: Google Workspace, Microsoft 365, ProtonMail Business, etc.
286
+ * - ✅ Proxy services: Cloudflare, CloudFront, Fastly, etc.
287
+ * - ✅ International providers: QQ Mail, NetEase, Yandex, etc.
288
+ *
289
+ * **Performance:**
290
+ * - Fast for known consumer domains (synchronous JSON lookup)
291
+ * - Additional DNS lookup time for unknown domains (~100-500ms)
292
+ * - Graceful degradation if DNS lookups fail
293
+ *
294
+ * **Error Handling:**
295
+ * - Invalid email addresses return null provider
296
+ * - DNS lookup failures are caught and don't throw errors
297
+ * - Network timeouts gracefully fall back to null detection
298
+ *
299
+ * **Use Cases:**
300
+ * - Password reset flows ("Check your Gmail inbox")
301
+ * - Login form enhancements (direct links to email providers)
302
+ * - Email client detection for support purposes
303
+ * - Business domain analysis for enterprise features
304
+ */
305
+ export declare function getEmailProviderLinkWithDNS(email: string, timeoutMs?: number): Promise<EmailProviderResult>;
306
+ declare const _default: {
307
+ getEmailProviderLink: typeof getEmailProviderLink;
308
+ getEmailProviderLinkWithDNS: typeof getEmailProviderLinkWithDNS;
309
+ detectProviderByDNS: typeof detectProviderByDNS;
310
+ isValidEmail: typeof isValidEmail;
311
+ extractDomain: typeof extractDomain;
312
+ findEmailProvider: typeof findEmailProvider;
313
+ getSupportedProviders: typeof getSupportedProviders;
314
+ isEmailProviderSupported: typeof isEmailProviderSupported;
315
+ };
316
+ export default _default;
317
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAyCH;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,WAAW,aAAa;IAC5B,wDAAwD;IACxD,eAAe,EAAE,MAAM,CAAC;IACxB,sDAAsD;IACtD,QAAQ,EAAE,MAAM,CAAC;IACjB,2FAA2F;IAC3F,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,wEAAwE;IACxE,qBAAqB,CAAC,EAAE;QACtB,yEAAyE;QACzE,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;QACtB,sFAAsF;QACtF,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;KACxB,CAAC;CACH;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,mBAAmB;IAClC,qEAAqE;IACrE,QAAQ,EAAE,aAAa,GAAG,IAAI,CAAC;IAC/B,mDAAmD;IACnD,KAAK,EAAE,MAAM,CAAC;IACd,wEAAwE;IACxE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,yCAAyC;IACzC,eAAe,CAAC,EAAE,cAAc,GAAG,WAAW,GAAG,YAAY,GAAG,gBAAgB,CAAC;IACjF,0EAA0E;IAC1E,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,kBAAkB;IACjC,qEAAqE;IACrE,QAAQ,EAAE,aAAa,GAAG,IAAI,CAAC;IAC/B,0CAA0C;IAC1C,eAAe,EAAE,WAAW,GAAG,YAAY,GAAG,gBAAgB,GAAG,IAAI,CAAC;IACtE,0EAA0E;IAC1E,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAuDD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAGnD;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAO1D;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CAGtE;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,mBAAmB,CAkBvE;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,qBAAqB,IAAI,aAAa,EAAE,CAEvD;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAG/D;AAsDD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,wBAAsB,mBAAmB,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,GAAE,MAA4B,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAwE9H;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwDG;AACH,wBAAsB,2BAA2B,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,GAAE,MAA4B,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAmDtI;;;;;;;;;;;AAGD,wBASE"}