@emailcheck/email-validator-js 3.2.0 → 3.4.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/README.md CHANGED
@@ -390,28 +390,28 @@ const name = detectNameFromEmail({
390
390
  #### `defaultNameDetectionMethod(email: string): DetectedName | null`
391
391
  The default name detection implementation, exported for custom extensions.
392
392
 
393
- #### Algrothin-Specific Name Cleaning
393
+ #### Algorithm-Specific Name Cleaning
394
394
 
395
- ##### `cleanNameForAlgrothin(name: string): string`
396
- Clean a name by removing special characters (dots, underscores, asterisks). Specifically designed for Algrothin name processing.
395
+ ##### `cleanNameForAlgorithm(name: string): string`
396
+ Clean a name by removing special characters (dots, underscores, asterisks). Specifically designed for Algorithm name processing.
397
397
 
398
398
  ```typescript
399
- import { cleanNameForAlgrothin } from '@emailcheck/email-validator-js';
399
+ import { cleanNameForAlgorithm } from '@emailcheck/email-validator-js';
400
400
 
401
- const cleanedName = cleanNameForAlgrothin('john.doe_smith*');
401
+ const cleanedName = cleanNameForAlgorithm('john.doe_smith*');
402
402
  // Returns: 'johndoesmith'
403
403
 
404
- const cleanedName2 = cleanNameForAlgrothin('first_name.last');
404
+ const cleanedName2 = cleanNameForAlgorithm('first_name.last');
405
405
  // Returns: 'firstnamelast'
406
406
  ```
407
407
 
408
- ##### `detectNameForAlgrothin(email: string): DetectedName | null`
409
- Enhanced name detection for Algrothin with aggressive cleaning. Removes dots, underscores, and asterisks from detected names.
408
+ ##### `detectNameForAlgorithm(email: string): DetectedName | null`
409
+ Enhanced name detection for Algorithm with aggressive cleaning. Removes dots, underscores, and asterisks from detected names.
410
410
 
411
411
  ```typescript
412
- import { detectNameForAlgrothin } from '@emailcheck/email-validator-js';
412
+ import { detectNameForAlgorithm } from '@emailcheck/email-validator-js';
413
413
 
414
- const result = detectNameForAlgrothin('john.doe_smith@company.com');
414
+ const result = detectNameForAlgorithm('john.doe_smith@company.com');
415
415
  // Returns: { firstName: 'John', lastName: 'Doesmith', confidence: 0.9025 }
416
416
 
417
417
  // Compared to regular detection:
package/dist/index.d.ts CHANGED
@@ -6,6 +6,8 @@ export * from './cache';
6
6
  export * from './cache-interface';
7
7
  export { commonEmailDomains, defaultDomainSuggestionMethod, getDomainSimilarity, isCommonDomain, suggestDomain, suggestEmailDomain, } from './domain-suggester';
8
8
  export { isValidEmail, isValidEmailDomain } from './email-validator';
9
+ export { isSpamEmail, isSpamEmailLocalPart } from './is-spam-email';
10
+ export { isSpamName } from './is-spam-name';
9
11
  export { cleanNameForAlgorithm, defaultNameDetectionMethod, detectName, detectNameForAlgorithm, detectNameFromEmail, } from './name-detector';
10
12
  export * from './types';
11
13
  export { getDomainAge, getDomainRegistrationStatus } from './whois';
package/dist/index.esm.js CHANGED
@@ -1332,11 +1332,10 @@ function isIPAddress(host) {
1332
1332
  const ipv6Regex = /^(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$|^(?:[0-9a-fA-F]{1,4}:){1,7}:$|^(?:[0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}$|^(?:[0-9a-fA-F]{1,4}:){1,5}(?::[0-9a-fA-F]{1,4}){1,2}$|^(?:[0-9a-fA-F]{1,4}:){1,4}(?::[0-9a-fA-F]{1,4}){1,3}$|^(?:[0-9a-fA-F]{1,4}:){1,3}(?::[0-9a-fA-F]{1,4}){1,4}$|^(?:[0-9a-fA-F]{1,4}:){1,2}(?::[0-9a-fA-F]{1,4}){1,5}$|^[0-9a-fA-F]{1,4}:(?:(?::[0-9a-fA-F]{1,4}){1,6})$|^::1(?::(?::[0-9a-fA-F]{1,4}){1,7})|$|:(?:(?::[0-9a-fA-F]{1,4}){1,7}:)$/;
1333
1333
  return ipv6Regex.test(host);
1334
1334
  }
1335
+ function isHighVolume(smtpReply) {
1336
+ return Boolean(smtpReply && /high number of/gi.test(smtpReply));
1337
+ }
1335
1338
  function isOverQuota(smtpReply) {
1336
- var _a;
1337
- if ((_a = smtpReply === null || smtpReply === void 0 ? void 0 : smtpReply.toLowerCase()) === null || _a === void 0 ? void 0 : _a.includes("excessively high number of invalid recipients")) {
1338
- return true;
1339
- }
1340
1339
  return Boolean(smtpReply && /(over quota)/gi.test(smtpReply));
1341
1340
  }
1342
1341
  function isInvalidMailboxError(smtpReply) {
@@ -1568,7 +1567,7 @@ async function testSMTPConnection(params) {
1568
1567
  sendCommand("STARTTLS");
1569
1568
  break;
1570
1569
  case SMTPStep.mailFrom: {
1571
- const from = activeSequence.from || "<>";
1570
+ const from = activeSequence.from || `<${local}@${domain}>`;
1572
1571
  sendCommand(`MAIL FROM:${from}`);
1573
1572
  break;
1574
1573
  }
@@ -1594,6 +1593,10 @@ async function testSMTPConnection(params) {
1594
1593
  if (isMultilineGreet(response)) {
1595
1594
  return;
1596
1595
  }
1596
+ if (isHighVolume(response)) {
1597
+ finish(true, "high_volume");
1598
+ return;
1599
+ }
1597
1600
  if (isOverQuota(response)) {
1598
1601
  finish(false, "over_quota");
1599
1602
  return;
@@ -2643,6 +2646,99 @@ function createErrorResult(email, _error) {
2643
2646
  };
2644
2647
  }
2645
2648
 
2649
+ function isSpamEmail(email) {
2650
+ if (typeof email !== "string")
2651
+ return false;
2652
+ const atIndex = email.lastIndexOf("@");
2653
+ if (atIndex === -1)
2654
+ return false;
2655
+ const localPart = email.slice(0, atIndex);
2656
+ if (localPart.length < 16)
2657
+ return false;
2658
+ const cleaned = localPart.replace(/[._+-]/g, "");
2659
+ if (cleaned.length < 12)
2660
+ return false;
2661
+ if (!/^[A-Za-z0-9]+$/.test(cleaned))
2662
+ return false;
2663
+ const lettersOnly = cleaned.replace(/[0-9]/g, "");
2664
+ if (lettersOnly.length < 10)
2665
+ return false;
2666
+ function vowelRatio(str) {
2667
+ const vowels = (str.match(/[aeiouAEIOU]/g) || []).length;
2668
+ return vowels / str.length;
2669
+ }
2670
+ function uppercaseRatio(str) {
2671
+ const uppercase = (str.match(/[A-Z]/g) || []).length;
2672
+ return uppercase / str.length;
2673
+ }
2674
+ function hasRepeatedPatterns(str) {
2675
+ const patterns = /(.)\1{2,}/g;
2676
+ const matches = str.match(patterns);
2677
+ return matches !== null && matches.length > 0;
2678
+ }
2679
+ function hasConsonantClusters(str) {
2680
+ const clusters = str.match(/[^aeiouAEIOU]{3,}/g);
2681
+ return clusters !== null && clusters.length > 0;
2682
+ }
2683
+ function hasAlternatingCase(str) {
2684
+ if (str.length < 8)
2685
+ return false;
2686
+ let alternatingChanges = 0;
2687
+ for (let i = 1; i < str.length; i++) {
2688
+ const prevIsUpper = str[i - 1] >= "A" && str[i - 1] <= "Z";
2689
+ const currIsUpper = str[i] >= "A" && str[i] <= "Z";
2690
+ if (prevIsUpper !== currIsUpper) {
2691
+ alternatingChanges++;
2692
+ }
2693
+ }
2694
+ return alternatingChanges / str.length > 0.7;
2695
+ }
2696
+ const vowelR = vowelRatio(lettersOnly);
2697
+ const upperR = uppercaseRatio(lettersOnly);
2698
+ if (hasAlternatingCase(lettersOnly))
2699
+ return true;
2700
+ if (vowelR > 0.35)
2701
+ return false;
2702
+ if (upperR < 0.15)
2703
+ return false;
2704
+ if (hasRepeatedPatterns(localPart))
2705
+ return true;
2706
+ if (hasConsonantClusters(lettersOnly))
2707
+ return true;
2708
+ if (cleaned.length >= 20 && vowelR < 0.25)
2709
+ return true;
2710
+ return true;
2711
+ }
2712
+ function isSpamEmailLocalPart(email) {
2713
+ return isSpamEmail(email);
2714
+ }
2715
+
2716
+ function isSpamName(name) {
2717
+ if (typeof name !== "string")
2718
+ return false;
2719
+ const cleaned = name.replace(/[,.;:!?]+$/, "").trim();
2720
+ const parts = cleaned.split(/\s+/);
2721
+ if (parts.length !== 2)
2722
+ return false;
2723
+ const [first, second] = parts;
2724
+ if (!/^[A-Za-z]+$/.test(first) || !/^[A-Za-z]+$/.test(second))
2725
+ return false;
2726
+ if (first.length < 16 || second.length < 16)
2727
+ return false;
2728
+ function vowelRatio(str) {
2729
+ const vowels = (str.match(/[aeiouAEIOU]/g) || []).length;
2730
+ return vowels / str.length;
2731
+ }
2732
+ const ratio1 = vowelRatio(first);
2733
+ const ratio2 = vowelRatio(second);
2734
+ const avgRatio = (ratio1 + ratio2) / 2;
2735
+ if (avgRatio > 0.35 && ratio1 > 0.25 && ratio2 > 0.25)
2736
+ return false;
2737
+ if (!/[A-Z]/.test(first) || !/[A-Z]/.test(second))
2738
+ return false;
2739
+ return true;
2740
+ }
2741
+
2646
2742
  let disposableEmailProviders;
2647
2743
  let freeEmailProviders;
2648
2744
  async function isDisposableEmail(params) {
@@ -2918,5 +3014,5 @@ async function verifyEmail(params) {
2918
3014
  return result;
2919
3015
  }
2920
3016
 
2921
- export { DEFAULT_CACHE_OPTIONS, EmailProvider, LRUAdapter, RedisAdapter, SMTPStep, VerificationErrorCode, cleanNameForAlgorithm, clearDefaultCache, commonEmailDomains, defaultDomainSuggestionMethod, defaultNameDetectionMethod, detectName, detectNameForAlgorithm, detectNameFromEmail, domainPorts, getCacheStore, getDefaultCache, getDomainAge, getDomainRegistrationStatus, getDomainSimilarity, isCommonDomain, isDisposableEmail, isFreeEmail, isValidEmail, isValidEmailDomain, parseSmtpError, resetDefaultCache, suggestDomain, suggestEmailDomain, verifyEmail, verifyEmailBatch };
3017
+ export { DEFAULT_CACHE_OPTIONS, EmailProvider, LRUAdapter, RedisAdapter, SMTPStep, VerificationErrorCode, cleanNameForAlgorithm, clearDefaultCache, commonEmailDomains, defaultDomainSuggestionMethod, defaultNameDetectionMethod, detectName, detectNameForAlgorithm, detectNameFromEmail, domainPorts, getCacheStore, getDefaultCache, getDomainAge, getDomainRegistrationStatus, getDomainSimilarity, isCommonDomain, isDisposableEmail, isFreeEmail, isSpamEmail, isSpamEmailLocalPart, isSpamName, isValidEmail, isValidEmailDomain, parseSmtpError, resetDefaultCache, suggestDomain, suggestEmailDomain, verifyEmail, verifyEmailBatch };
2922
3018
  //# sourceMappingURL=index.esm.js.map