@mikkelscheike/email-provider-links 2.6.1 β 2.7.1
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/README.md +138 -126
- package/dist/alias-detection.d.ts +1 -0
- package/dist/alias-detection.js +74 -13
- package/dist/api.d.ts +6 -5
- package/dist/api.js +18 -13
- package/dist/concurrent-dns.d.ts +2 -1
- package/dist/concurrent-dns.js +20 -9
- package/dist/hash-verifier.d.ts +1 -0
- package/dist/hash-verifier.js +2 -1
- package/dist/idn.d.ts +1 -0
- package/dist/idn.js +1 -0
- package/dist/index.d.ts +158 -10
- package/dist/index.js +300 -22
- package/dist/loader.d.ts +1 -0
- package/dist/loader.js +1 -0
- package/dist/schema.d.ts +1 -0
- package/dist/schema.js +1 -0
- package/dist/secure-loader.d.ts +1 -0
- package/dist/secure-loader.js +1 -0
- package/dist/url-validator.d.ts +1 -0
- package/dist/url-validator.js +1 -0
- package/package.json +4 -3
package/README.md
CHANGED
|
@@ -1,16 +1,26 @@
|
|
|
1
1
|
# Email Provider Links
|
|
2
2
|
|
|
3
|
-
π **Modern email provider detection library with
|
|
3
|
+
π **Modern email provider detection library with enhanced TypeScript support and enterprise security**
|
|
4
4
|
|
|
5
|
-
A TypeScript library providing direct links to **93 email providers** (178 domains) with **concurrent DNS resolution**, **optimized performance**, **email
|
|
5
|
+
A robust TypeScript library providing direct links to **93 email providers** (178 domains) with **concurrent DNS resolution**, **optimized performance**, **comprehensive email validation**, and advanced security features for login and password reset flows.
|
|
6
6
|
|
|
7
|
-
## β¨
|
|
7
|
+
## β¨ New in Version 2.7.0
|
|
8
|
+
|
|
9
|
+
- π **Modern TypeScript**: Updated to latest TypeScript 2025 standards with strict type checking
|
|
10
|
+
- π **Enhanced International Support**: Improved IDN validation and Punycode handling
|
|
11
|
+
- π§ **Advanced Email Validation**: Comprehensive validation with detailed error reporting
|
|
12
|
+
- π **Batch Processing**: Efficiently process multiple emails with deduplication
|
|
13
|
+
- π‘οΈ **Improved Security**: Enhanced cryptographic integrity verification
|
|
14
|
+
- β‘ **Better Performance**: Optimized concurrent DNS with smart caching
|
|
15
|
+
- π― **Developer Experience**: Enhanced error messages and debugging information
|
|
16
|
+
|
|
17
|
+
## β¨ Core Features
|
|
8
18
|
|
|
9
19
|
- π **Fast & Lightweight**: Zero dependencies, ultra-low memory (~0.39MB initial, ~0.02MB per 1000 ops)
|
|
10
20
|
- π§ **93 Email Providers**: Gmail, Outlook, Yahoo, ProtonMail, iCloud, and many more
|
|
11
21
|
- π **178 Domains Supported**: Comprehensive international coverage
|
|
12
|
-
- π **IDN Support**:
|
|
13
|
-
- β
**Email Validation**: International email validation
|
|
22
|
+
- π **Full IDN Support**: International domain names with RFC compliance and Punycode
|
|
23
|
+
- β
**Advanced Email Validation**: International email validation with detailed error reporting
|
|
14
24
|
- π’ **Business Domain Detection**: DNS-based detection for custom domains (Google Workspace, Microsoft 365, etc.)
|
|
15
25
|
- π **Enterprise Security**: Multi-layer protection against malicious URLs and supply chain attacks
|
|
16
26
|
- π‘οΈ **URL Validation**: HTTPS-only enforcement with domain allowlisting
|
|
@@ -20,7 +30,8 @@ A TypeScript library providing direct links to **93 email providers** (178 domai
|
|
|
20
30
|
- π¦ **Rate Limiting**: Built-in DNS query rate limiting to prevent abuse
|
|
21
31
|
- π **Email Alias Detection**: Normalize Gmail dots, plus addressing, and provider-specific aliases
|
|
22
32
|
- π‘οΈ **Fraud Prevention**: Detect duplicate accounts through email alias manipulation
|
|
23
|
-
-
|
|
33
|
+
- π¦ **Batch Processing**: Efficiently process multiple emails with deduplication
|
|
34
|
+
- π§ͺ **Thoroughly Tested**: 396 tests with comprehensive code coverage
|
|
24
35
|
|
|
25
36
|
## Installation
|
|
26
37
|
|
|
@@ -32,7 +43,7 @@ npm install @mikkelscheike/email-provider-links
|
|
|
32
43
|
## Requirements
|
|
33
44
|
|
|
34
45
|
- **Node.js**: `>=18.0.0` (Tested on 18.x, 20.x, 22.x, **24.x**)
|
|
35
|
-
- **TypeScript**: `>=4.0.0` (optional)
|
|
46
|
+
- **TypeScript**: `>=4.0.0` (optional, but recommended)
|
|
36
47
|
- **Zero runtime dependencies** - No external packages required
|
|
37
48
|
|
|
38
49
|
### Node.js 24 Support β¨
|
|
@@ -64,6 +75,59 @@ const unknown = await getEmailProvider('user@unknown.com');
|
|
|
64
75
|
console.log(unknown.loginUrl); // null
|
|
65
76
|
```
|
|
66
77
|
|
|
78
|
+
## Enhanced Email Validation
|
|
79
|
+
|
|
80
|
+
**New in 2.7.0**: Comprehensive email validation with international support:
|
|
81
|
+
|
|
82
|
+
```typescript
|
|
83
|
+
import { validateEmailAddress, validateInternationalEmail } from '@mikkelscheike/email-provider-links';
|
|
84
|
+
|
|
85
|
+
// Enhanced validation with detailed error reporting
|
|
86
|
+
const result = validateEmailAddress('user@example.com');
|
|
87
|
+
if (result.isValid) {
|
|
88
|
+
console.log('Valid email:', result.normalizedEmail);
|
|
89
|
+
} else {
|
|
90
|
+
console.log('Error:', result.error?.message);
|
|
91
|
+
console.log('Error code:', result.error?.code);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// International domain validation
|
|
95
|
+
const intlResult = validateInternationalEmail('user@mΓΌnchen.de');
|
|
96
|
+
if (!intlResult) {
|
|
97
|
+
console.log('Valid international email');
|
|
98
|
+
} else {
|
|
99
|
+
console.log('Validation error:', intlResult.message);
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Batch Processing
|
|
104
|
+
|
|
105
|
+
**New in 2.7.0**: Process multiple emails efficiently with deduplication:
|
|
106
|
+
|
|
107
|
+
```typescript
|
|
108
|
+
import { batchProcessEmails } from '@mikkelscheike/email-provider-links';
|
|
109
|
+
|
|
110
|
+
const emails = [
|
|
111
|
+
'user@gmail.com',
|
|
112
|
+
'u.s.e.r+work@gmail.com', // Alias of the first email
|
|
113
|
+
'test@yahoo.com',
|
|
114
|
+
'invalid-email'
|
|
115
|
+
];
|
|
116
|
+
|
|
117
|
+
const results = batchProcessEmails(emails, {
|
|
118
|
+
includeProviderInfo: true,
|
|
119
|
+
normalizeEmails: true,
|
|
120
|
+
deduplicateAliases: true
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
results.forEach(result => {
|
|
124
|
+
console.log(`${result.email}: ${result.isValid ? 'Valid' : 'Invalid'}`);
|
|
125
|
+
if (result.isDuplicate) {
|
|
126
|
+
console.log(' π Duplicate detected');
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
```
|
|
130
|
+
|
|
67
131
|
## Supported Providers
|
|
68
132
|
|
|
69
133
|
**π Current Coverage: 93 providers supporting 178 domains**
|
|
@@ -95,7 +159,7 @@ console.log(unknown.loginUrl); // null
|
|
|
95
159
|
- **Eastern Europe**: Centrum (Czech/Slovak), Interia, Onet (Poland), Rambler (Russia)
|
|
96
160
|
- **Other Regions**: UOL, Terra (Brazil), Telkom (South Africa), Xtra (New Zealand)
|
|
97
161
|
|
|
98
|
-
## API
|
|
162
|
+
## API Reference
|
|
99
163
|
|
|
100
164
|
### `getEmailProvider(email, timeout?)`
|
|
101
165
|
**Recommended** - Detects any email provider including business domains.
|
|
@@ -128,21 +192,42 @@ const result = getEmailProviderSync('user@gmail.com');
|
|
|
128
192
|
// Returns: { provider, loginUrl, email }
|
|
129
193
|
```
|
|
130
194
|
|
|
195
|
+
### `getEmailProviderFast(email, options?)`
|
|
196
|
+
**High-performance** - Concurrent DNS with detailed timing information.
|
|
197
|
+
|
|
198
|
+
```typescript
|
|
199
|
+
const result = await getEmailProviderFast('user@mycompany.com', {
|
|
200
|
+
enableParallel: true,
|
|
201
|
+
collectDebugInfo: true,
|
|
202
|
+
timeout: 3000
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
console.log(result.timing); // { mx: 120, txt: 95, total: 125 }
|
|
206
|
+
console.log(result.confidence); // 0.9
|
|
207
|
+
```
|
|
208
|
+
|
|
131
209
|
## Real-World Example
|
|
132
210
|
|
|
133
211
|
```typescript
|
|
134
212
|
async function handlePasswordReset(email: string) {
|
|
135
|
-
|
|
213
|
+
// Validate email first
|
|
214
|
+
const validation = validateEmailAddress(email);
|
|
215
|
+
if (!validation.isValid) {
|
|
216
|
+
throw new Error(`Invalid email: ${validation.error?.message}`);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// Get provider information
|
|
220
|
+
const result = await getEmailProvider(validation.normalizedEmail);
|
|
136
221
|
|
|
137
222
|
return {
|
|
138
223
|
providerUrl: result.loginUrl,
|
|
139
224
|
providerName: result.provider?.companyProvider || null,
|
|
140
|
-
isSupported: result.provider !== null
|
|
225
|
+
isSupported: result.provider !== null,
|
|
226
|
+
detectionMethod: result.detectionMethod
|
|
141
227
|
};
|
|
142
228
|
}
|
|
143
229
|
```
|
|
144
230
|
|
|
145
|
-
|
|
146
231
|
## Configuration
|
|
147
232
|
|
|
148
233
|
```typescript
|
|
@@ -155,97 +240,24 @@ console.log('Max requests:', Config.MAX_DNS_REQUESTS_PER_MINUTE); // 10
|
|
|
155
240
|
console.log('Default timeout:', Config.DEFAULT_DNS_TIMEOUT); // 5000ms
|
|
156
241
|
```
|
|
157
242
|
|
|
158
|
-
## Email Validation
|
|
159
|
-
|
|
160
|
-
The library includes comprehensive email validation following international standards:
|
|
161
|
-
|
|
162
|
-
```typescript
|
|
163
|
-
import { validateInternationalEmail } from '@mikkelscheike/email-provider-links';
|
|
164
|
-
|
|
165
|
-
// Validate any email address
|
|
166
|
-
const result = validateInternationalEmail('user@example.com');
|
|
167
|
-
|
|
168
|
-
// Returns undefined for valid emails
|
|
169
|
-
console.log(result); // undefined
|
|
170
|
-
|
|
171
|
-
// Returns detailed error information for invalid emails
|
|
172
|
-
const invalid = validateInternationalEmail('user@mΓΌnchen.com');
|
|
173
|
-
if (invalid) {
|
|
174
|
-
console.log(invalid.code); // IDN_VALIDATION_ERROR
|
|
175
|
-
console.log(invalid.message); // Human-readable error message
|
|
176
|
-
}
|
|
177
|
-
```
|
|
178
|
-
|
|
179
|
-
### Validation Features
|
|
180
|
-
|
|
181
|
-
- β
**RFC Compliance**: Follows RFC 5321, 5322, and 6530 standards
|
|
182
|
-
- π **International Support**: Full IDN (Punycode) validation
|
|
183
|
-
- π **Detailed Errors**: Clear, translatable error messages
|
|
184
|
-
- π **Comprehensive Checks**:
|
|
185
|
-
- Local part validation (username)
|
|
186
|
-
- Domain format validation
|
|
187
|
-
- IDN encoding validation
|
|
188
|
-
- Length limits (local part, domain, total)
|
|
189
|
-
- TLD validation
|
|
190
|
-
|
|
191
243
|
## Advanced Usage
|
|
192
244
|
|
|
193
245
|
<details>
|
|
194
|
-
<summary><strong>π
|
|
195
|
-
|
|
196
|
-
### Synchronous Provider Detection (No DNS)
|
|
246
|
+
<summary><strong>π Advanced Features & Specialized Use Cases</strong></summary>
|
|
197
247
|
|
|
198
|
-
|
|
248
|
+
### Library Statistics
|
|
199
249
|
|
|
200
250
|
```typescript
|
|
201
|
-
import {
|
|
251
|
+
import { getLibraryStats, getSupportedProviders } from '@mikkelscheike/email-provider-links';
|
|
202
252
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
console.log(result.loginUrl); // Works for known domains only
|
|
206
|
-
```
|
|
253
|
+
const stats = getLibraryStats();
|
|
254
|
+
console.log(`Version ${stats.version} supports ${stats.providerCount} providers`);
|
|
207
255
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
```typescript
|
|
211
|
-
import { isEmailProviderSupported, getSupportedProviders } from '@mikkelscheike/email-provider-links';
|
|
212
|
-
|
|
213
|
-
// Check if provider is supported
|
|
214
|
-
const supported = isEmailProviderSupported('user@gmail.com');
|
|
215
|
-
|
|
216
|
-
// Get all supported providers
|
|
217
|
-
const allProviders = getSupportedProviders();
|
|
218
|
-
console.log(`Supports ${allProviders.length} providers`);
|
|
256
|
+
const providers = getSupportedProviders();
|
|
257
|
+
console.log(`Total providers: ${providers.length}`);
|
|
219
258
|
```
|
|
220
259
|
|
|
221
|
-
###
|
|
222
|
-
|
|
223
|
-
```typescript
|
|
224
|
-
import { getEmailProviderFast, detectProviderConcurrent } from '@mikkelscheike/email-provider-links';
|
|
225
|
-
|
|
226
|
-
// High-performance detection with concurrent DNS
|
|
227
|
-
const fastResult = await getEmailProviderFast('user@mycompany.com', {
|
|
228
|
-
enableParallel: true,
|
|
229
|
-
collectDebugInfo: true
|
|
230
|
-
});
|
|
231
|
-
console.log(fastResult.provider?.companyProvider); // "Google Workspace"
|
|
232
|
-
console.log(fastResult.timing); // Performance metrics
|
|
233
|
-
```
|
|
234
|
-
|
|
235
|
-
### Configuration Options
|
|
236
|
-
|
|
237
|
-
```typescript
|
|
238
|
-
import { Config } from '@mikkelscheike/email-provider-links';
|
|
239
|
-
|
|
240
|
-
// Access configuration constants
|
|
241
|
-
console.log(Config.DEFAULT_DNS_TIMEOUT); // 5000ms
|
|
242
|
-
console.log(Config.MAX_DNS_REQUESTS_PER_MINUTE); // 10
|
|
243
|
-
console.log(Config.SUPPORTED_PROVIDERS_COUNT); // 93
|
|
244
|
-
```
|
|
245
|
-
|
|
246
|
-
### π Email Alias Detection & Normalization
|
|
247
|
-
|
|
248
|
-
**Specialized feature** for preventing duplicate accounts and fraud detection:
|
|
260
|
+
### Email Alias Detection & Normalization
|
|
249
261
|
|
|
250
262
|
```typescript
|
|
251
263
|
import {
|
|
@@ -274,27 +286,38 @@ const canonical = normalizeEmail('u.s.e.r+work@gmail.com');
|
|
|
274
286
|
console.log(canonical); // 'user@gmail.com'
|
|
275
287
|
```
|
|
276
288
|
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
289
|
+
### Provider Support Checking
|
|
290
|
+
|
|
291
|
+
```typescript
|
|
292
|
+
import { isEmailProviderSupported, extractDomain } from '@mikkelscheike/email-provider-links';
|
|
293
|
+
|
|
294
|
+
// Check if provider is supported
|
|
295
|
+
const supported = isEmailProviderSupported('user@gmail.com');
|
|
296
|
+
|
|
297
|
+
// Extract domain safely
|
|
298
|
+
const domain = extractDomain('USER@EXAMPLE.COM');
|
|
299
|
+
console.log(domain); // 'example.com'
|
|
300
|
+
```
|
|
281
301
|
|
|
282
302
|
</details>
|
|
283
303
|
|
|
284
304
|
## TypeScript Support
|
|
285
305
|
|
|
306
|
+
Full TypeScript support with comprehensive interfaces:
|
|
307
|
+
|
|
286
308
|
```typescript
|
|
287
309
|
interface EmailProviderResult {
|
|
288
310
|
provider: EmailProvider | null;
|
|
289
311
|
email: string;
|
|
290
312
|
loginUrl: string | null;
|
|
291
|
-
detectionMethod?: 'domain_match' | 'mx_record' | 'txt_record' | 'proxy_detected';
|
|
313
|
+
detectionMethod?: 'domain_match' | 'mx_record' | 'txt_record' | 'both' | 'proxy_detected';
|
|
292
314
|
proxyService?: string;
|
|
293
315
|
error?: {
|
|
294
316
|
type: 'INVALID_EMAIL' | 'DNS_TIMEOUT' | 'RATE_LIMITED' | 'UNKNOWN_DOMAIN' |
|
|
295
317
|
'NETWORK_ERROR' | 'IDN_VALIDATION_ERROR';
|
|
296
318
|
message: string;
|
|
297
|
-
|
|
319
|
+
retryAfter?: number; // seconds until retry allowed (for rate limiting)
|
|
320
|
+
idnError?: string; // specific IDN validation error message
|
|
298
321
|
};
|
|
299
322
|
}
|
|
300
323
|
|
|
@@ -332,49 +355,39 @@ Protects against common attack vectors:
|
|
|
332
355
|
|
|
333
356
|
### π§ͺ Security Testing
|
|
334
357
|
|
|
335
|
-
- **
|
|
336
|
-
- **
|
|
358
|
+
- **396 comprehensive tests** covering all functionality and edge cases
|
|
359
|
+
- **92+ dedicated security tests** covering all attack vectors
|
|
337
360
|
- **Automated security validation** in CI/CD pipeline
|
|
338
361
|
- **Regular security audits** of provider database
|
|
339
362
|
|
|
340
|
-
### π For Security Teams
|
|
341
|
-
|
|
342
|
-
Security validation can be integrated into your workflow:
|
|
343
|
-
|
|
344
|
-
```typescript
|
|
345
|
-
import { secureLoadProviders } from '@mikkelscheike/email-provider-links/security';
|
|
346
|
-
|
|
347
|
-
// Secure loading with integrity verification
|
|
348
|
-
const result = secureLoadProviders();
|
|
349
|
-
if (result.securityReport.securityLevel === 'CRITICAL') {
|
|
350
|
-
// Handle security incident
|
|
351
|
-
console.error('Security validation failed:', result.securityReport.issues);
|
|
352
|
-
}
|
|
353
|
-
```
|
|
354
|
-
|
|
355
363
|
## Performance Benchmarks
|
|
356
364
|
|
|
357
|
-
This package is designed to be extremely memory efficient and fast
|
|
365
|
+
This package is designed to be extremely memory efficient and fast:
|
|
358
366
|
|
|
359
|
-
|
|
360
|
-
-
|
|
361
|
-
-
|
|
362
|
-
-
|
|
363
|
-
-
|
|
364
|
-
- Cache effectiveness: ~0.01MB impact on subsequent loads
|
|
367
|
+
- **Provider loading**: ~0.39MB heap usage, <0.5ms
|
|
368
|
+
- **Email lookups**: ~0.02MB heap usage per 100 operations
|
|
369
|
+
- **Concurrent DNS**: ~0.03MB heap usage, ~110ms for 10 lookups
|
|
370
|
+
- **Large scale (1000 ops)**: ~0.02MB heap usage, <3ms total
|
|
371
|
+
- **International validation**: <1ms for complex IDN domains
|
|
365
372
|
|
|
366
373
|
To run benchmarks locally:
|
|
367
374
|
```bash
|
|
368
375
|
npm run benchmark
|
|
369
376
|
```
|
|
370
377
|
|
|
371
|
-
|
|
378
|
+
## Examples
|
|
379
|
+
|
|
380
|
+
Run the modern example to see all features in action:
|
|
381
|
+
|
|
382
|
+
```bash
|
|
383
|
+
npx tsx examples/modern-example.ts
|
|
384
|
+
```
|
|
372
385
|
|
|
373
386
|
## Contributing
|
|
374
387
|
|
|
375
388
|
We welcome contributions! See [CONTRIBUTING.md](docs/CONTRIBUTING.md) for guidelines on adding new email providers.
|
|
376
389
|
|
|
377
|
-
**Quality Assurance**: This project maintains high standards with
|
|
390
|
+
**Quality Assurance**: This project maintains high standards with 396 comprehensive tests achieving excellent code coverage.
|
|
378
391
|
**Security Note**: All new providers undergo security validation and must pass our allowlist verification.
|
|
379
392
|
|
|
380
393
|
## Security
|
|
@@ -387,5 +400,4 @@ MIT License - see [LICENSE](LICENSE) file for details.
|
|
|
387
400
|
|
|
388
401
|
---
|
|
389
402
|
|
|
390
|
-
**Zero dependencies β’ TypeScript-first β’ Production ready**
|
|
391
|
-
|
|
403
|
+
**Zero dependencies β’ TypeScript-first β’ Production ready β’ International support**
|
package/dist/alias-detection.js
CHANGED
|
@@ -18,7 +18,12 @@ const ALIAS_RULES = [
|
|
|
18
18
|
supportsPlusAddressing: true,
|
|
19
19
|
ignoresDots: true,
|
|
20
20
|
normalize: (email) => {
|
|
21
|
-
const
|
|
21
|
+
const parts = email.toLowerCase().split('@');
|
|
22
|
+
const username = parts[0];
|
|
23
|
+
const domain = parts[1];
|
|
24
|
+
if (!username || !domain) {
|
|
25
|
+
return email.toLowerCase();
|
|
26
|
+
}
|
|
22
27
|
// Remove dots and everything after +
|
|
23
28
|
const cleanUsername = username.replace(/\./g, '').split('+')[0];
|
|
24
29
|
return `${cleanUsername}@${domain}`;
|
|
@@ -29,7 +34,12 @@ const ALIAS_RULES = [
|
|
|
29
34
|
supportsPlusAddressing: true,
|
|
30
35
|
ignoresDots: false,
|
|
31
36
|
normalize: (email) => {
|
|
32
|
-
const
|
|
37
|
+
const parts = email.toLowerCase().split('@');
|
|
38
|
+
const username = parts[0];
|
|
39
|
+
const domain = parts[1];
|
|
40
|
+
if (!username || !domain) {
|
|
41
|
+
return email.toLowerCase();
|
|
42
|
+
}
|
|
33
43
|
// Only remove plus addressing for Outlook
|
|
34
44
|
const cleanUsername = username.split('+')[0];
|
|
35
45
|
return `${cleanUsername}@${domain}`;
|
|
@@ -40,7 +50,12 @@ const ALIAS_RULES = [
|
|
|
40
50
|
supportsPlusAddressing: true,
|
|
41
51
|
ignoresDots: false,
|
|
42
52
|
normalize: (email) => {
|
|
43
|
-
const
|
|
53
|
+
const parts = email.toLowerCase().split('@');
|
|
54
|
+
const username = parts[0];
|
|
55
|
+
const domain = parts[1];
|
|
56
|
+
if (!username || !domain) {
|
|
57
|
+
return email.toLowerCase();
|
|
58
|
+
}
|
|
44
59
|
const cleanUsername = username.split('+')[0];
|
|
45
60
|
return `${cleanUsername}@${domain}`;
|
|
46
61
|
}
|
|
@@ -50,7 +65,12 @@ const ALIAS_RULES = [
|
|
|
50
65
|
supportsPlusAddressing: true,
|
|
51
66
|
ignoresDots: false,
|
|
52
67
|
normalize: (email) => {
|
|
53
|
-
const
|
|
68
|
+
const parts = email.toLowerCase().split('@');
|
|
69
|
+
const username = parts[0];
|
|
70
|
+
const domain = parts[1];
|
|
71
|
+
if (!username || !domain) {
|
|
72
|
+
return email.toLowerCase();
|
|
73
|
+
}
|
|
54
74
|
const cleanUsername = username.split('+')[0];
|
|
55
75
|
return `${cleanUsername}@${domain}`;
|
|
56
76
|
}
|
|
@@ -60,7 +80,12 @@ const ALIAS_RULES = [
|
|
|
60
80
|
supportsPlusAddressing: true,
|
|
61
81
|
ignoresDots: false,
|
|
62
82
|
normalize: (email) => {
|
|
63
|
-
const
|
|
83
|
+
const parts = email.toLowerCase().split('@');
|
|
84
|
+
const username = parts[0];
|
|
85
|
+
const domain = parts[1];
|
|
86
|
+
if (!username || !domain) {
|
|
87
|
+
return email.toLowerCase();
|
|
88
|
+
}
|
|
64
89
|
const cleanUsername = username.split('+')[0];
|
|
65
90
|
return `${cleanUsername}@${domain}`;
|
|
66
91
|
}
|
|
@@ -70,7 +95,12 @@ const ALIAS_RULES = [
|
|
|
70
95
|
supportsPlusAddressing: true,
|
|
71
96
|
ignoresDots: false,
|
|
72
97
|
normalize: (email) => {
|
|
73
|
-
const
|
|
98
|
+
const parts = email.toLowerCase().split('@');
|
|
99
|
+
const username = parts[0];
|
|
100
|
+
const domain = parts[1];
|
|
101
|
+
if (!username || !domain) {
|
|
102
|
+
return email.toLowerCase();
|
|
103
|
+
}
|
|
74
104
|
const cleanUsername = username.split('+')[0];
|
|
75
105
|
return `${cleanUsername}@${domain}`;
|
|
76
106
|
}
|
|
@@ -80,7 +110,12 @@ const ALIAS_RULES = [
|
|
|
80
110
|
supportsPlusAddressing: true,
|
|
81
111
|
ignoresDots: false,
|
|
82
112
|
normalize: (email) => {
|
|
83
|
-
const
|
|
113
|
+
const parts = email.toLowerCase().split('@');
|
|
114
|
+
const username = parts[0];
|
|
115
|
+
const domain = parts[1];
|
|
116
|
+
if (!username || !domain) {
|
|
117
|
+
return email.toLowerCase();
|
|
118
|
+
}
|
|
84
119
|
const cleanUsername = username.split('+')[0];
|
|
85
120
|
return `${cleanUsername}@${domain}`;
|
|
86
121
|
}
|
|
@@ -90,7 +125,12 @@ const ALIAS_RULES = [
|
|
|
90
125
|
supportsPlusAddressing: true,
|
|
91
126
|
ignoresDots: false,
|
|
92
127
|
normalize: (email) => {
|
|
93
|
-
const
|
|
128
|
+
const parts = email.toLowerCase().split('@');
|
|
129
|
+
const username = parts[0];
|
|
130
|
+
const domain = parts[1];
|
|
131
|
+
if (!username || !domain) {
|
|
132
|
+
return email.toLowerCase();
|
|
133
|
+
}
|
|
94
134
|
const cleanUsername = username.split('+')[0];
|
|
95
135
|
return `${cleanUsername}@${domain}`;
|
|
96
136
|
}
|
|
@@ -100,7 +140,12 @@ const ALIAS_RULES = [
|
|
|
100
140
|
supportsPlusAddressing: true,
|
|
101
141
|
ignoresDots: false,
|
|
102
142
|
normalize: (email) => {
|
|
103
|
-
const
|
|
143
|
+
const parts = email.toLowerCase().split('@');
|
|
144
|
+
const username = parts[0];
|
|
145
|
+
const domain = parts[1];
|
|
146
|
+
if (!username || !domain) {
|
|
147
|
+
return email.toLowerCase();
|
|
148
|
+
}
|
|
104
149
|
const cleanUsername = username.split('+')[0];
|
|
105
150
|
return `${cleanUsername}@${domain}`;
|
|
106
151
|
}
|
|
@@ -116,7 +161,12 @@ const ALIAS_RULES = [
|
|
|
116
161
|
supportsPlusAddressing: true,
|
|
117
162
|
ignoresDots: false,
|
|
118
163
|
normalize: (email) => {
|
|
119
|
-
const
|
|
164
|
+
const parts = email.toLowerCase().split('@');
|
|
165
|
+
const username = parts[0];
|
|
166
|
+
const domain = parts[1];
|
|
167
|
+
if (!username || !domain) {
|
|
168
|
+
return email.toLowerCase();
|
|
169
|
+
}
|
|
120
170
|
const cleanUsername = username.split('+')[0];
|
|
121
171
|
return `${cleanUsername}@${domain}`;
|
|
122
172
|
}
|
|
@@ -126,7 +176,12 @@ const ALIAS_RULES = [
|
|
|
126
176
|
supportsPlusAddressing: true,
|
|
127
177
|
ignoresDots: false,
|
|
128
178
|
normalize: (email) => {
|
|
129
|
-
const
|
|
179
|
+
const parts = email.toLowerCase().split('@');
|
|
180
|
+
const username = parts[0];
|
|
181
|
+
const domain = parts[1];
|
|
182
|
+
if (!username || !domain) {
|
|
183
|
+
return email.toLowerCase();
|
|
184
|
+
}
|
|
130
185
|
const cleanUsername = username.split('+')[0];
|
|
131
186
|
return `${cleanUsername}@${domain}`;
|
|
132
187
|
}
|
|
@@ -143,7 +198,7 @@ function isValidEmail(email) {
|
|
|
143
198
|
* Gets the alias rule for a given domain
|
|
144
199
|
*/
|
|
145
200
|
function getAliasRule(domain) {
|
|
146
|
-
return ALIAS_RULES.find(rule => rule.domains.includes(domain.toLowerCase()));
|
|
201
|
+
return ALIAS_RULES.find(rule => rule.domains.includes(domain.toLowerCase())) || null;
|
|
147
202
|
}
|
|
148
203
|
/**
|
|
149
204
|
* Detects and analyzes email aliases
|
|
@@ -156,7 +211,12 @@ function detectEmailAlias(email) {
|
|
|
156
211
|
throw new Error('Invalid email format');
|
|
157
212
|
}
|
|
158
213
|
const originalEmail = email.trim();
|
|
159
|
-
const
|
|
214
|
+
const emailParts = originalEmail.toLowerCase().split('@');
|
|
215
|
+
const username = emailParts[0];
|
|
216
|
+
const domain = emailParts[1];
|
|
217
|
+
if (!username || !domain) {
|
|
218
|
+
throw new Error('Invalid email format - missing username or domain');
|
|
219
|
+
}
|
|
160
220
|
const rule = getAliasRule(domain);
|
|
161
221
|
const result = {
|
|
162
222
|
canonical: originalEmail.toLowerCase(),
|
|
@@ -243,3 +303,4 @@ function emailsMatch(email1, email2) {
|
|
|
243
303
|
return false;
|
|
244
304
|
}
|
|
245
305
|
}
|
|
306
|
+
//# sourceMappingURL=alias-detection.js.map
|
package/dist/api.d.ts
CHANGED
|
@@ -51,13 +51,13 @@ export interface EmailProviderResult {
|
|
|
51
51
|
* ```typescript
|
|
52
52
|
* // Consumer email
|
|
53
53
|
* const gmail = await getEmailProvider('user@gmail.com');
|
|
54
|
-
* console.log(gmail.provider?.
|
|
55
|
-
* console.log(gmail.loginUrl);
|
|
54
|
+
* console.log(gmail.provider?.companyProvider); // "Gmail"
|
|
55
|
+
* console.log(gmail.loginUrl); // "https://mail.google.com/mail/"
|
|
56
56
|
*
|
|
57
57
|
* // Business domain
|
|
58
58
|
* const business = await getEmailProvider('user@mycompany.com');
|
|
59
|
-
* console.log(business.provider?.
|
|
60
|
-
* console.log(business.detectionMethod);
|
|
59
|
+
* console.log(business.provider?.companyProvider); // "Google Workspace" (if detected)
|
|
60
|
+
* console.log(business.detectionMethod); // "mx_record"
|
|
61
61
|
*
|
|
62
62
|
* // Error handling
|
|
63
63
|
* const invalid = await getEmailProvider('invalid-email');
|
|
@@ -79,7 +79,7 @@ export declare function getEmailProvider(email: string, timeout?: number): Promi
|
|
|
79
79
|
* ```typescript
|
|
80
80
|
* // Works for known domains
|
|
81
81
|
* const gmail = getEmailProviderSync('user@gmail.com');
|
|
82
|
-
* console.log(gmail.provider?.
|
|
82
|
+
* console.log(gmail.provider?.companyProvider); // "Gmail"
|
|
83
83
|
*
|
|
84
84
|
* // Unknown domains return null
|
|
85
85
|
* const unknown = getEmailProviderSync('user@mycompany.com');
|
|
@@ -171,3 +171,4 @@ export declare const Config: {
|
|
|
171
171
|
readonly SUPPORTED_PROVIDERS_COUNT: 93;
|
|
172
172
|
readonly SUPPORTED_DOMAINS_COUNT: 180;
|
|
173
173
|
};
|
|
174
|
+
//# sourceMappingURL=api.d.ts.map
|