@emailcheck/email-validator-js 5.0.0-beta.1 → 5.0.0-beta.2
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 +128 -30
- package/dist/index.d.ts +1 -0
- package/dist/index.esm.js +86 -1
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +87 -0
- package/dist/index.js.map +1 -1
- package/dist/presets.d.ts +155 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -113,7 +113,8 @@ const result = await verifyEmail({
|
|
|
113
113
|
emailAddress: 'user@mydomain.com',
|
|
114
114
|
verifyMx: true,
|
|
115
115
|
verifySmtp: true,
|
|
116
|
-
|
|
116
|
+
smtpPerAttemptTimeoutMs: 3000, // bounds a single MX × port attempt
|
|
117
|
+
smtpTotalDeadlineMs: 8000, // bounds the entire SMTP probe (NEW in v5)
|
|
117
118
|
});
|
|
118
119
|
|
|
119
120
|
console.log(result.validFormat); // true
|
|
@@ -249,25 +250,31 @@ If you're using an IDE with refactoring support (like VS Code), you can use find
|
|
|
249
250
|
Comprehensive email verification with detailed results and error codes.
|
|
250
251
|
|
|
251
252
|
**Parameters:**
|
|
252
|
-
- `emailAddress` (string, required)
|
|
253
|
-
- `
|
|
254
|
-
- `
|
|
255
|
-
- `
|
|
256
|
-
- `
|
|
257
|
-
- `
|
|
258
|
-
- `
|
|
259
|
-
- `
|
|
260
|
-
- `
|
|
261
|
-
- `
|
|
262
|
-
- `
|
|
263
|
-
- `
|
|
264
|
-
-
|
|
265
|
-
- `
|
|
266
|
-
- `
|
|
267
|
-
- `
|
|
268
|
-
- `
|
|
269
|
-
- `
|
|
270
|
-
- `
|
|
253
|
+
- `emailAddress` (string, required) — Email address to verify.
|
|
254
|
+
- `verifyMx` (boolean) — Resolve MX records (default: `true`).
|
|
255
|
+
- `verifySmtp` (boolean) — Run live SMTP probe (default: `false`).
|
|
256
|
+
- `checkDisposable` (boolean) — Disposable-provider list check (default: `true`).
|
|
257
|
+
- `checkFree` (boolean) — Free-provider list check (default: `true`).
|
|
258
|
+
- `detectName` (boolean) — Extract first/last name from local-part (default: `false`).
|
|
259
|
+
- `suggestDomain` (boolean) — Suggest a corrected domain on typos (default: `true`).
|
|
260
|
+
- `checkDomainAge` (boolean) — WHOIS creation-date lookup (default: `false`).
|
|
261
|
+
- `checkDomainRegistration` (boolean) — WHOIS registration / expiry / lock lookup (default: `false`).
|
|
262
|
+
- `skipMxForDisposable` (boolean) — Skip MX/SMTP for disposable addresses (default: `false`).
|
|
263
|
+
- `skipDomainWhoisForDisposable` (boolean) — Skip WHOIS for disposable addresses (default: `false`).
|
|
264
|
+
- `smtpPort` (number) — Force a specific port for the SMTP probe (overrides the `[25, 587, 465]` walk).
|
|
265
|
+
- **SMTP time-budget controls** (NEW in v5):
|
|
266
|
+
- `smtpPerAttemptTimeoutMs` (number) — Per-MX × port budget in ms (default: `4000`).
|
|
267
|
+
- `smtpTotalDeadlineMs` (number) — Hard cap on total wall-clock for the SMTP probe. Use this from a request handler with a tight latency budget. Default: unbounded.
|
|
268
|
+
- `smtpMaxConsecutiveFailures` (number) — Bail after N connection-class failures in a row (`connection_error` / `connection_timeout` / `connection_closed`). Default: unbounded.
|
|
269
|
+
- `smtpMaxMxHosts` (number) — Cap the MX walk to the first N hostnames. Default: unbounded.
|
|
270
|
+
- `smtpRetry` (`{ attempts, delayMs?, backoff? }`) — Retry connection-class failures on the same MX × port. Default: no retries.
|
|
271
|
+
- `whoisTimeoutMs` (number) — Per-WHOIS-query timeout (default: `5000`).
|
|
272
|
+
- `debug` (boolean) — Per-line `console.debug` trace (default: `false`).
|
|
273
|
+
- `captureTranscript` (boolean) — Populate `result.transcript` with a per-step structured trace (default: `false`).
|
|
274
|
+
- `nameDetectionMethod` (function) — Override the default name-detection heuristic.
|
|
275
|
+
- `domainSuggestionMethod` (function) — Override the default typo-suggestion heuristic.
|
|
276
|
+
- `commonDomains` (string[]) — Custom canonical-domain list for the typo suggester.
|
|
277
|
+
- `cache` (Cache) — Optional shared cache (MX, WHOIS, disposable / free, SMTP, domain results all stored).
|
|
271
278
|
|
|
272
279
|
**Returns:**
|
|
273
280
|
```typescript
|
|
@@ -736,7 +743,7 @@ const result = await verifyEmail({
|
|
|
736
743
|
emailAddress: 'foo@email.com',
|
|
737
744
|
verifyMx: true,
|
|
738
745
|
verifySmtp: true,
|
|
739
|
-
|
|
746
|
+
smtpPerAttemptTimeoutMs: 3000,
|
|
740
747
|
});
|
|
741
748
|
console.log(result.validFormat); // true
|
|
742
749
|
console.log(result.validMx); // true
|
|
@@ -790,16 +797,20 @@ const { smtpResult, port, cached, portCached } = await verifyMailboxSMTP({
|
|
|
790
797
|
domain: 'example.com',
|
|
791
798
|
mxRecords: ['mx.example.com'],
|
|
792
799
|
options: {
|
|
793
|
-
ports: [25, 587, 465],
|
|
794
|
-
|
|
795
|
-
|
|
800
|
+
ports: [25, 587, 465], // Plain → STARTTLS-able → implicit-TLS
|
|
801
|
+
perAttemptTimeoutMs: 5000, // Per-MX × port budget (renamed from `timeout` in v5)
|
|
802
|
+
totalDeadlineMs: 12_000, // Hard cap on total wall-clock (NEW in v5)
|
|
803
|
+
maxConsecutiveFailures: 3, // Bail after N connection-class failures (NEW in v5)
|
|
804
|
+
cache: getDefaultCache(), // Per-isolate verdict + port cache
|
|
796
805
|
debug: false,
|
|
797
|
-
|
|
806
|
+
tlsConfig: { // Renamed from `tls` in v5
|
|
798
807
|
rejectUnauthorized: false,
|
|
799
808
|
minVersion: 'TLSv1.2',
|
|
800
809
|
},
|
|
801
|
-
|
|
802
|
-
|
|
810
|
+
heloHostname: 'your-domain.com', // EHLO/HELO identity (renamed from `hostname` in v5)
|
|
811
|
+
startTls: 'auto', // STARTTLS upgrade on plaintext ports (NEW in v5)
|
|
812
|
+
pipelining: 'auto', // Use SMTP PIPELINING when advertised
|
|
813
|
+
captureTranscript: false, // See "SMTP Transcript Capture" below
|
|
803
814
|
},
|
|
804
815
|
});
|
|
805
816
|
|
|
@@ -807,6 +818,93 @@ console.log(`SMTP result: ${smtpResult.isDeliverable} via port ${port}`);
|
|
|
807
818
|
console.log(`canConnectSmtp=${smtpResult.canConnectSmtp}, error=${smtpResult.error ?? 'none'}`);
|
|
808
819
|
```
|
|
809
820
|
|
|
821
|
+
### Configuration presets (NEW in v5)
|
|
822
|
+
|
|
823
|
+
Don't want to think about timeouts and retries? Pick a preset that matches your deployment shape:
|
|
824
|
+
|
|
825
|
+
```typescript
|
|
826
|
+
import { verifyEmail, VERIFY_EMAIL_PRESETS } from '@emailcheck/email-validator-js';
|
|
827
|
+
|
|
828
|
+
// Lambda / Vercel / Cloudflare-Workers handler
|
|
829
|
+
await verifyEmail({
|
|
830
|
+
emailAddress: 'alice@example.com',
|
|
831
|
+
verifySmtp: true,
|
|
832
|
+
...VERIFY_EMAIL_PRESETS.serverless,
|
|
833
|
+
});
|
|
834
|
+
|
|
835
|
+
// Long-running worker / dyno
|
|
836
|
+
await verifyEmail({ ..., ...VERIFY_EMAIL_PRESETS.dedicated });
|
|
837
|
+
|
|
838
|
+
// Bulk processing
|
|
839
|
+
await verifyEmail({ ..., ...VERIFY_EMAIL_PRESETS.batch });
|
|
840
|
+
|
|
841
|
+
// Form-autocomplete UX (sub-3s)
|
|
842
|
+
await verifyEmail({ ..., ...VERIFY_EMAIL_PRESETS.fast });
|
|
843
|
+
```
|
|
844
|
+
|
|
845
|
+
| Preset | Per-attempt | Total deadline | Max consecutive failures | Max MX | Retry |
|
|
846
|
+
| --- | --- | --- | --- | --- | --- |
|
|
847
|
+
| `serverless` | 2500 ms | **5 s** | 3 | 2 | none — fail fast |
|
|
848
|
+
| `dedicated` | 5000 ms | 30 s | unbounded | unbounded | 1 retry, 500 ms exp backoff |
|
|
849
|
+
| `batch` | 10 000 ms | 60 s | unbounded | unbounded | 2 retries, 1 s exp backoff |
|
|
850
|
+
| `fast` | 1500 ms | **3 s** | 2 | **1** | none — fail fast |
|
|
851
|
+
|
|
852
|
+
`SMTP_PRESETS` is a parallel set with the unprefixed field names for `verifyMailboxSMTP({ options })` callers — same values, same shape.
|
|
853
|
+
|
|
854
|
+
You can spread + override:
|
|
855
|
+
|
|
856
|
+
```typescript
|
|
857
|
+
await verifyEmail({
|
|
858
|
+
emailAddress: 'alice@example.com',
|
|
859
|
+
...VERIFY_EMAIL_PRESETS.serverless,
|
|
860
|
+
smtpTotalDeadlineMs: 3000, // tighter than the preset's 5s
|
|
861
|
+
});
|
|
862
|
+
```
|
|
863
|
+
|
|
864
|
+
### Time-budget controls (NEW in v5)
|
|
865
|
+
|
|
866
|
+
The probe walks `mxRecords × ports` (worst-case 4 × 3 = 12 attempts at 3s each = 36s). Four orthogonal knobs let you bound that:
|
|
867
|
+
|
|
868
|
+
```typescript
|
|
869
|
+
import { verifyEmail, verifyMailboxSMTP } from '@emailcheck/email-validator-js';
|
|
870
|
+
|
|
871
|
+
await verifyEmail({
|
|
872
|
+
emailAddress: 'maria.hernandez+news@yahoo.com',
|
|
873
|
+
verifySmtp: true,
|
|
874
|
+
smtpPerAttemptTimeoutMs: 3000, // Bound a single MX × port attempt
|
|
875
|
+
smtpTotalDeadlineMs: 5000, // Hard cap on total wall-clock
|
|
876
|
+
smtpMaxConsecutiveFailures: 3, // Bail after 3 connection failures in a row
|
|
877
|
+
smtpMaxMxHosts: 2, // Try only the first 2 MXes
|
|
878
|
+
smtpRetry: { // Retry connection-class failures
|
|
879
|
+
attempts: 1,
|
|
880
|
+
delayMs: 200,
|
|
881
|
+
backoff: 'exponential', // or 'fixed'
|
|
882
|
+
},
|
|
883
|
+
});
|
|
884
|
+
|
|
885
|
+
// On verifyMailboxSMTP directly, the same knobs are unprefixed:
|
|
886
|
+
await verifyMailboxSMTP({
|
|
887
|
+
local: 'alice', domain: 'example.com', mxRecords: [...],
|
|
888
|
+
options: {
|
|
889
|
+
perAttemptTimeoutMs: 3000,
|
|
890
|
+
totalDeadlineMs: 5000,
|
|
891
|
+
maxConsecutiveFailures: 3,
|
|
892
|
+
maxMxHosts: 2,
|
|
893
|
+
retry: { attempts: 1, delayMs: 200, backoff: 'exponential' },
|
|
894
|
+
},
|
|
895
|
+
});
|
|
896
|
+
```
|
|
897
|
+
|
|
898
|
+
| Knob | Default | When to use |
|
|
899
|
+
| --- | --- | --- |
|
|
900
|
+
| `(smtp)PerAttemptTimeoutMs` | `4000` (verifyEmail) / `3000` (verifyMailboxSMTP) | Per-MX × port budget. Bound a single attempt. |
|
|
901
|
+
| `(smtp)TotalDeadlineMs` | unbounded | Hard wall-clock cap. Use from a request handler with a tight latency budget. |
|
|
902
|
+
| `(smtp)MaxConsecutiveFailures` | unbounded | Cut off probes when the network path is dead. Counter resets on any non-connection-class outcome. |
|
|
903
|
+
| `(smtp)MaxMxHosts` | unbounded | Cap the MX walk regardless of how many DNS returned. |
|
|
904
|
+
| `(smtp)Retry` | no retries | Retry connection-class failures on the same MX × port. Definitive answers (250 / 550 / 552) are never retried. |
|
|
905
|
+
|
|
906
|
+
`PerAttemptTimeout` and `TotalDeadline` are **orthogonal** — use both when you have both a per-attempt SLO and a hard caller-side budget.
|
|
907
|
+
|
|
810
908
|
### Custom SMTP step sequence
|
|
811
909
|
|
|
812
910
|
Override the default `greeting → EHLO → MAIL FROM → RCPT TO` walk for advanced cases:
|
|
@@ -839,11 +937,11 @@ const { smtpResult } = await verifyMailboxSMTP({
|
|
|
839
937
|
local: 'user',
|
|
840
938
|
domain: 'example.com',
|
|
841
939
|
mxRecords: ['mx.example.com'],
|
|
842
|
-
options: { ports: [25, 587],
|
|
940
|
+
options: { ports: [25, 587], perAttemptTimeoutMs: 5000, captureTranscript: true },
|
|
843
941
|
});
|
|
844
942
|
|
|
845
|
-
// Both arrays aggregate across every port attempted, prefixed
|
|
846
|
-
// "25|s| 220 mx.example.com ESMTP"
|
|
943
|
+
// Both arrays aggregate across every MX × port attempted, prefixed:
|
|
944
|
+
// "mx.example.com:25|s| 220 mx.example.com ESMTP"
|
|
847
945
|
// "25|c| EHLO localhost"
|
|
848
946
|
console.log(smtpResult.transcript);
|
|
849
947
|
console.log(smtpResult.commands);
|
package/dist/index.d.ts
CHANGED
|
@@ -23,6 +23,7 @@ export { isSpamEmail } from './is-spam-email';
|
|
|
23
23
|
export { isSpamName } from './is-spam-name';
|
|
24
24
|
export { resolveMxRecords } from './mx-resolver';
|
|
25
25
|
export { cleanNameForAlgorithm, defaultNameDetectionMethod, detectName, detectNameForAlgorithm, detectNameFromEmail, } from './name-detector';
|
|
26
|
+
export { SMTP_PRESETS, type SmtpPresetName, VERIFY_EMAIL_PRESETS, type VerifyEmailPresetName, } from './presets';
|
|
26
27
|
export { refineReasonByEnhancedStatus } from './refine-reason';
|
|
27
28
|
export { type ParsedSmtpError, parseSmtpError } from './smtp-error-parser';
|
|
28
29
|
export { type ParsedDsn, parseDsn, verifyMailboxSMTP } from './smtp-verifier';
|
package/dist/index.esm.js
CHANGED
|
@@ -2663,6 +2663,91 @@ function isSpamName(name) {
|
|
|
2663
2663
|
return true;
|
|
2664
2664
|
}
|
|
2665
2665
|
|
|
2666
|
+
const SMTP_PRESETS = {
|
|
2667
|
+
/**
|
|
2668
|
+
* **Serverless** — Lambda / Vercel / Cloudflare-Workers handlers.
|
|
2669
|
+
*
|
|
2670
|
+
* Tight latency budget; cuts off bad MXes fast. The total wall-clock
|
|
2671
|
+
* is bounded at 5 s so the probe finishes well inside a typical 10 s
|
|
2672
|
+
* handler SLA, leaving headroom for everything else the handler does.
|
|
2673
|
+
*/
|
|
2674
|
+
serverless: {
|
|
2675
|
+
perAttemptTimeoutMs: 2500,
|
|
2676
|
+
totalDeadlineMs: 5e3,
|
|
2677
|
+
maxConsecutiveFailures: 3,
|
|
2678
|
+
maxMxHosts: 2
|
|
2679
|
+
},
|
|
2680
|
+
/**
|
|
2681
|
+
* **Dedicated** — long-running server / worker.
|
|
2682
|
+
*
|
|
2683
|
+
* Not latency-bound. Tries every MX, retries connection-class failures
|
|
2684
|
+
* once with a 500 ms backoff. Suitable for an always-on backend that
|
|
2685
|
+
* processes verification requests as they arrive.
|
|
2686
|
+
*/
|
|
2687
|
+
dedicated: {
|
|
2688
|
+
perAttemptTimeoutMs: 5e3,
|
|
2689
|
+
totalDeadlineMs: 3e4,
|
|
2690
|
+
retry: { attempts: 1, delayMs: 500, backoff: "exponential" }
|
|
2691
|
+
},
|
|
2692
|
+
/**
|
|
2693
|
+
* **Batch** — bulk processing.
|
|
2694
|
+
*
|
|
2695
|
+
* Each address can take a while; what matters is correctness across
|
|
2696
|
+
* the whole batch. Multiple retries with exponential backoff to ride
|
|
2697
|
+
* out transient network blips. Generous per-attempt budget so slow
|
|
2698
|
+
* MXes get a fair shot.
|
|
2699
|
+
*/
|
|
2700
|
+
batch: {
|
|
2701
|
+
perAttemptTimeoutMs: 1e4,
|
|
2702
|
+
totalDeadlineMs: 6e4,
|
|
2703
|
+
retry: { attempts: 2, delayMs: 1e3, backoff: "exponential" }
|
|
2704
|
+
},
|
|
2705
|
+
/**
|
|
2706
|
+
* **Fast** — UX-bound (form autocomplete / signup-form validation).
|
|
2707
|
+
*
|
|
2708
|
+
* Optimize for speed; accept that ambiguous results may be more common.
|
|
2709
|
+
* Tries the primary MX only, single retry, sub-3s wall-clock.
|
|
2710
|
+
*/
|
|
2711
|
+
fast: {
|
|
2712
|
+
perAttemptTimeoutMs: 1500,
|
|
2713
|
+
totalDeadlineMs: 3e3,
|
|
2714
|
+
maxConsecutiveFailures: 2,
|
|
2715
|
+
maxMxHosts: 1
|
|
2716
|
+
}
|
|
2717
|
+
};
|
|
2718
|
+
const VERIFY_EMAIL_PRESETS = {
|
|
2719
|
+
/** See `SMTP_PRESETS.serverless`. */
|
|
2720
|
+
serverless: {
|
|
2721
|
+
smtpPerAttemptTimeoutMs: 2500,
|
|
2722
|
+
smtpTotalDeadlineMs: 5e3,
|
|
2723
|
+
smtpMaxConsecutiveFailures: 3,
|
|
2724
|
+
smtpMaxMxHosts: 2,
|
|
2725
|
+
whoisTimeoutMs: 3e3
|
|
2726
|
+
},
|
|
2727
|
+
/** See `SMTP_PRESETS.dedicated`. */
|
|
2728
|
+
dedicated: {
|
|
2729
|
+
smtpPerAttemptTimeoutMs: 5e3,
|
|
2730
|
+
smtpTotalDeadlineMs: 3e4,
|
|
2731
|
+
smtpRetry: { attempts: 1, delayMs: 500, backoff: "exponential" },
|
|
2732
|
+
whoisTimeoutMs: 5e3
|
|
2733
|
+
},
|
|
2734
|
+
/** See `SMTP_PRESETS.batch`. */
|
|
2735
|
+
batch: {
|
|
2736
|
+
smtpPerAttemptTimeoutMs: 1e4,
|
|
2737
|
+
smtpTotalDeadlineMs: 6e4,
|
|
2738
|
+
smtpRetry: { attempts: 2, delayMs: 1e3, backoff: "exponential" },
|
|
2739
|
+
whoisTimeoutMs: 8e3
|
|
2740
|
+
},
|
|
2741
|
+
/** See `SMTP_PRESETS.fast`. */
|
|
2742
|
+
fast: {
|
|
2743
|
+
smtpPerAttemptTimeoutMs: 1500,
|
|
2744
|
+
smtpTotalDeadlineMs: 3e3,
|
|
2745
|
+
smtpMaxConsecutiveFailures: 2,
|
|
2746
|
+
smtpMaxMxHosts: 1,
|
|
2747
|
+
whoisTimeoutMs: 2e3
|
|
2748
|
+
}
|
|
2749
|
+
};
|
|
2750
|
+
|
|
2666
2751
|
const REFINEMENT_TABLE = {
|
|
2667
2752
|
// X.1.x — addressing
|
|
2668
2753
|
"5.1.1": "mailbox_does_not_exist",
|
|
@@ -2796,5 +2881,5 @@ function parseSmtpError(errorMessage) {
|
|
|
2796
2881
|
return { isDisabled, hasFullInbox, isCatchAll, isInvalid };
|
|
2797
2882
|
}
|
|
2798
2883
|
|
|
2799
|
-
export { ArrayTranscriptCollector, DEFAULT_CACHE_OPTIONS, EmailProvider, LRUAdapter, NULL_COLLECTOR, RedisAdapter, SMTPStep, VerificationErrorCode, cleanNameForAlgorithm, clearDefaultCache, commonEmailDomains, defaultDomainSuggestionMethod, defaultDomainSuggestionMethodAsync, defaultNameDetectionMethod, detectName, detectNameForAlgorithm, detectNameFromEmail, domainPorts, getCacheStore, getDefaultCache, getDomainAge, getDomainRegistrationStatus, getDomainSimilarity, isCommonDomain, isDisposableEmail, isFreeEmail, isSpamEmail, isSpamName, isValidEmail, isValidEmailDomain, parseDsn, parseSmtpError, parseWhoisData, refineReasonByEnhancedStatus, resolveMxRecords, suggestDomain, suggestEmailDomain, verifyEmail, verifyEmailBatch, verifyMailboxSMTP };
|
|
2884
|
+
export { ArrayTranscriptCollector, DEFAULT_CACHE_OPTIONS, EmailProvider, LRUAdapter, NULL_COLLECTOR, RedisAdapter, SMTPStep, SMTP_PRESETS, VERIFY_EMAIL_PRESETS, VerificationErrorCode, cleanNameForAlgorithm, clearDefaultCache, commonEmailDomains, defaultDomainSuggestionMethod, defaultDomainSuggestionMethodAsync, defaultNameDetectionMethod, detectName, detectNameForAlgorithm, detectNameFromEmail, domainPorts, getCacheStore, getDefaultCache, getDomainAge, getDomainRegistrationStatus, getDomainSimilarity, isCommonDomain, isDisposableEmail, isFreeEmail, isSpamEmail, isSpamName, isValidEmail, isValidEmailDomain, parseDsn, parseSmtpError, parseWhoisData, refineReasonByEnhancedStatus, resolveMxRecords, suggestDomain, suggestEmailDomain, verifyEmail, verifyEmailBatch, verifyMailboxSMTP };
|
|
2800
2885
|
//# sourceMappingURL=index.esm.js.map
|