@emailcheck/email-validator-js 5.0.0 → 5.1.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.
Files changed (44) hide show
  1. package/README.md +40 -4
  2. package/dist/cli/index.js +34 -2
  3. package/dist/cli/index.js.map +1 -1
  4. package/dist/index.d.ts +1 -0
  5. package/dist/index.esm.js +36 -3
  6. package/dist/index.esm.js.map +1 -1
  7. package/dist/index.js +36 -2
  8. package/dist/index.js.map +1 -1
  9. package/dist/sender-strategy.d.ts +26 -0
  10. package/dist/serverless/adapters/aws-lambda.cjs.js +5 -5
  11. package/dist/serverless/adapters/aws-lambda.cjs.js.map +1 -1
  12. package/dist/serverless/adapters/aws-lambda.esm.js +5 -5
  13. package/dist/serverless/adapters/aws-lambda.esm.js.map +1 -1
  14. package/dist/serverless/adapters/azure.cjs.js +5 -5
  15. package/dist/serverless/adapters/azure.cjs.js.map +1 -1
  16. package/dist/serverless/adapters/azure.esm.js +5 -5
  17. package/dist/serverless/adapters/azure.esm.js.map +1 -1
  18. package/dist/serverless/adapters/cloudflare.cjs.js +5 -5
  19. package/dist/serverless/adapters/cloudflare.cjs.js.map +1 -1
  20. package/dist/serverless/adapters/cloudflare.esm.js +5 -5
  21. package/dist/serverless/adapters/cloudflare.esm.js.map +1 -1
  22. package/dist/serverless/adapters/gcp.cjs.js +5 -5
  23. package/dist/serverless/adapters/gcp.cjs.js.map +1 -1
  24. package/dist/serverless/adapters/gcp.esm.js +5 -5
  25. package/dist/serverless/adapters/gcp.esm.js.map +1 -1
  26. package/dist/serverless/adapters/netlify.cjs.js +5 -5
  27. package/dist/serverless/adapters/netlify.cjs.js.map +1 -1
  28. package/dist/serverless/adapters/netlify.esm.js +5 -5
  29. package/dist/serverless/adapters/netlify.esm.js.map +1 -1
  30. package/dist/serverless/adapters/vercel.cjs.js +5 -5
  31. package/dist/serverless/adapters/vercel.cjs.js.map +1 -1
  32. package/dist/serverless/adapters/vercel.esm.js +5 -5
  33. package/dist/serverless/adapters/vercel.esm.js.map +1 -1
  34. package/dist/serverless/index.cjs.js +5 -5
  35. package/dist/serverless/index.cjs.js.map +1 -1
  36. package/dist/serverless/index.esm.js +5 -5
  37. package/dist/serverless/index.esm.js.map +1 -1
  38. package/dist/serverless/verifier.cjs.js +5 -5
  39. package/dist/serverless/verifier.cjs.js.map +1 -1
  40. package/dist/serverless/verifier.esm.js +5 -5
  41. package/dist/serverless/verifier.esm.js.map +1 -1
  42. package/dist/serverless/verifier.min.js +1 -1
  43. package/dist/types.d.ts +72 -0
  44. package/package.json +3 -3
package/README.md CHANGED
@@ -268,6 +268,14 @@ Comprehensive email verification with detailed results and error codes.
268
268
  - `smtpMaxConsecutiveFailures` (number) — Bail after N connection-class failures in a row (`connection_error` / `connection_timeout` / `connection_closed`). Default: unbounded.
269
269
  - `smtpMaxMxHosts` (number) — Cap the MX walk to the first N hostnames. Default: unbounded.
270
270
  - `smtpRetry` (`{ attempts, delayMs?, backoff? }`) — Retry connection-class failures on the same MX × port. Default: no retries.
271
+ - **SMTP envelope controls** (anti-spam — recommended for production):
272
+ - `smtpSender` (`SMTPSenderStrategy`) — Strategy for the `MAIL FROM:` envelope. The library default is `<recipient@domain>`, which blocklists key on as the textbook verification-probe fingerprint. Pick a deliberate strategy:
273
+ - `{ kind: 'null-sender' }` → `MAIL FROM:<>` (RFC 5321 §4.5.5; DSN-shaped, best on Gmail / Outlook).
274
+ - `{ kind: 'fixed', address: 'verify@your-domain.com' }` → fixed real address (best with valid SPF / PTR / DMARC).
275
+ - `{ kind: 'random-at-recipient', localPrefix? }` → random local-part on the recipient's domain.
276
+ - `{ kind: 'random-at-domain', domain, localPrefix? }` → random local-part on a configured domain.
277
+ - `{ kind: 'custom', build: r => ... }` → full escape hatch.
278
+ - `smtpHeloHostname` (string) — Hostname presented to the MX in `EHLO` / `HELO`. Default: `'localhost'` (a spam-bot signature from a public IP — override with a real FQDN in production).
271
279
  - `whoisTimeoutMs` (number) — Per-WHOIS-query timeout (default: `5000`).
272
280
  - `debug` (boolean) — Per-line `console.debug` trace (default: `false`).
273
281
  - `captureTranscript` (boolean) — Populate `result.transcript` with a per-step structured trace (default: `false`).
@@ -1133,10 +1141,38 @@ clearAllCaches();
1133
1141
 
1134
1142
  ## 💻 Command-line Tool (`email-validate`)
1135
1143
 
1136
- `bun add -g @emailcheck/email-validator-js` (or the npm equivalent) installs an
1137
- `email-validate` binary. It runs the full validation pipeline against one
1138
- address, captures a structured transcript, prints the result to stdout, and
1139
- saves the JSON result to `./logs/` by default.
1144
+ The package ships an `email-validate` binary that runs the full validation
1145
+ pipeline against one address, captures a structured transcript, prints the
1146
+ result to stdout, and saves the JSON result to `./logs/` by default.
1147
+
1148
+ ### Run without installing (npx / bunx / pnpm dlx)
1149
+
1150
+ ```bash
1151
+ # One-off check — pulls the latest published version, no install required
1152
+ npx -p @emailcheck/email-validator-js email-validate alice@example.com
1153
+
1154
+ # Same with bunx / pnpm dlx
1155
+ bunx -p @emailcheck/email-validator-js email-validate alice@example.com
1156
+ pnpm dlx -p @emailcheck/email-validator-js email-validate alice@example.com
1157
+
1158
+ # Pin a version (avoids npx caching surprises in CI)
1159
+ npx -p @emailcheck/email-validator-js@4.0.0 email-validate alice@example.com
1160
+ ```
1161
+
1162
+ > The `-p <package>` form is the safest because the bin name
1163
+ > (`email-validate`) differs from the package name. The shorthand
1164
+ > `npx @emailcheck/email-validator-js alice@example.com` also works since the
1165
+ > package has exactly one bin.
1166
+
1167
+ ### Install globally
1168
+
1169
+ ```bash
1170
+ bun add -g @emailcheck/email-validator-js
1171
+ # or: npm i -g @emailcheck/email-validator-js
1172
+ # or: pnpm add -g @emailcheck/email-validator-js
1173
+ ```
1174
+
1175
+ ### Examples
1140
1176
 
1141
1177
  ```bash
1142
1178
  # Quick interactive check — full pipeline, pretty colored output
package/dist/cli/index.js CHANGED
@@ -1015,6 +1015,31 @@ function detectNameFromEmail(params) {
1015
1015
  return defaultNameDetectionMethod(email);
1016
1016
  }
1017
1017
 
1018
+ const DEFAULT_LOCAL_PREFIX = "probe";
1019
+ function resolveSenderAddress(strategy, recipient) {
1020
+ switch (strategy.kind) {
1021
+ case "null-sender":
1022
+ return "<>";
1023
+ case "fixed":
1024
+ return wrap(strategy.address);
1025
+ case "random-at-recipient":
1026
+ return wrap(`${randomLocal(strategy.localPrefix)}@${recipient.domain}`);
1027
+ case "random-at-domain":
1028
+ return wrap(`${randomLocal(strategy.localPrefix)}@${strategy.domain}`);
1029
+ case "custom":
1030
+ return strategy.build({ local: recipient.local, domain: recipient.domain });
1031
+ }
1032
+ }
1033
+ function wrap(address) {
1034
+ if (address.startsWith("<") && address.endsWith(">")) return address;
1035
+ return `<${address}>`;
1036
+ }
1037
+ function randomLocal(prefix) {
1038
+ const random = node_crypto.randomBytes(8).toString("hex");
1039
+ const safePrefix = prefix ?? DEFAULT_LOCAL_PREFIX;
1040
+ return `${safePrefix}-${random}`;
1041
+ }
1042
+
1018
1043
  const DEFAULT_PORTS = [25, 587, 465];
1019
1044
  const DEFAULT_TIMEOUT_MS = 3e3;
1020
1045
  const QUIT_DRAIN_MS = 100;
@@ -1058,6 +1083,7 @@ async function verifyMailboxSMTP(params) {
1058
1083
  const debug = options.debug ?? false;
1059
1084
  const captureTranscript = options.captureTranscript ?? false;
1060
1085
  const sequence = options.sequence;
1086
+ const sender = options.sender;
1061
1087
  const cache = options.cache;
1062
1088
  const log = debug ? (...args) => console.log("[SMTP]", ...args) : () => {
1063
1089
  };
@@ -1084,6 +1110,7 @@ async function verifyMailboxSMTP(params) {
1084
1110
  tlsConfig,
1085
1111
  heloHostname,
1086
1112
  sequence,
1113
+ sender,
1087
1114
  log,
1088
1115
  catchAllProbeLocal: options.catchAllProbeLocal,
1089
1116
  pipelining: options.pipelining ?? "auto",
@@ -1354,7 +1381,7 @@ class SMTPProbeConnection {
1354
1381
  this.executeStartTls();
1355
1382
  return;
1356
1383
  case SMTPStep.mailFrom: {
1357
- const from = this.p.sequence?.from ?? `<${this.p.local}@${this.p.domain}>`;
1384
+ const from = this.p.sender ? resolveSenderAddress(this.p.sender, { local: this.p.local, domain: this.p.domain }) : this.p.sequence?.from ?? `<${this.p.local}@${this.p.domain}>`;
1358
1385
  this.send(`MAIL FROM:${from}`);
1359
1386
  return;
1360
1387
  }
@@ -2471,7 +2498,12 @@ async function runSmtp(local, domain, mxRecords, params, result, log, collector)
2471
2498
  debug: params.debug ?? false,
2472
2499
  // Forward transcript capture so the SMTP step's details include
2473
2500
  // the full per-port transcript when the caller asked for it.
2474
- captureTranscript: params.captureTranscript ?? false
2501
+ captureTranscript: params.captureTranscript ?? false,
2502
+ // Forward the high-level envelope strategy and HELO override so
2503
+ // callers can control the spam-fingerprint of the probe without
2504
+ // dropping down to `verifyMailboxSMTP` directly.
2505
+ ...params.smtpSender !== void 0 && { sender: params.smtpSender },
2506
+ ...params.smtpHeloHostname !== void 0 && { heloHostname: params.smtpHeloHostname }
2475
2507
  }
2476
2508
  });
2477
2509
  await smtpCache.set(cacheKey, probe.smtpResult);