@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 CHANGED
@@ -113,7 +113,8 @@ const result = await verifyEmail({
113
113
  emailAddress: 'user@mydomain.com',
114
114
  verifyMx: true,
115
115
  verifySmtp: true,
116
- timeout: 3000
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): Email address to verify
253
- - `timeout` (number): Timeout in milliseconds (default: 4000)
254
- - `verifyMx` (boolean): Check MX records (default: true)
255
- - `verifySmtp` (boolean): Verify SMTP connection (default: false)
256
- - `smtpPort` (number): Custom SMTP port
257
- - `debug` (boolean): Enable debug logging (default: false)
258
- - `checkDisposable` (boolean): Check for disposable emails (default: true)
259
- - `checkFree` (boolean): Check for free email providers (default: true)
260
- - `retryAttempts` (number): Retry attempts for failures (default: 1)
261
- - `detectName` (boolean): Detect names from email address (default: false)
262
- - `nameDetectionMethod` (function): Custom name detection method
263
- - `suggestDomain` (boolean): Enable domain typo suggestions (default: true)
264
- - `domainSuggestionMethod` (function): Custom domain suggestion method
265
- - `commonDomains` (string[]): Custom list of domains for suggestions
266
- - `checkDomainAge` (boolean): Check domain age (default: false)
267
- - `checkDomainRegistration` (boolean): Check domain registration status (default: false)
268
- - `whoisTimeout` (number): WHOIS lookup timeout (default: 5000)
269
- - `debug` (boolean): Enable debug logging including WHOIS lookups (default: false)
270
- - `cache` (ICache): Optional custom cache instance
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
- timeout: 3000
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], // Plain → STARTTLS-able → implicit-TLS
794
- timeout: 5000,
795
- cache: getDefaultCache(), // Per-isolate verdict + port cache
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
- tls: {
806
+ tlsConfig: { // Renamed from `tls` in v5
798
807
  rejectUnauthorized: false,
799
808
  minVersion: 'TLSv1.2',
800
809
  },
801
- hostname: 'your-domain.com', // EHLO/HELO identity
802
- captureTranscript: false, // see "SMTP Transcript Capture" below
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], timeout: 5000, captureTranscript: true },
940
+ options: { ports: [25, 587], perAttemptTimeoutMs: 5000, captureTranscript: true },
843
941
  });
844
942
 
845
- // Both arrays aggregate across every port attempted, prefixed with the port:
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