valid-email-checker 1.0.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/LICENSE +21 -0
- package/README.md +129 -0
- package/package.json +33 -0
- package/src/data/disposableDomains.js +1194 -0
- package/src/index.d.ts +156 -0
- package/src/index.js +335 -0
- package/src/validators/formatValidator.js +257 -0
- package/src/validators/mxValidator.js +143 -0
- package/src/validators/spamDetector.js +338 -0
- package/src/validators/tempMailDetector.js +205 -0
package/src/index.d.ts
ADDED
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TypeScript Definitions for valid-email-checker
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export interface ValidationResult {
|
|
6
|
+
valid: boolean;
|
|
7
|
+
email: string;
|
|
8
|
+
normalized?: string | null;
|
|
9
|
+
local?: string | null;
|
|
10
|
+
domain?: string | null;
|
|
11
|
+
tld?: string;
|
|
12
|
+
errors?: string[];
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface TemporaryEmailResult {
|
|
16
|
+
isTemporary: boolean;
|
|
17
|
+
email: string;
|
|
18
|
+
domain: string | null;
|
|
19
|
+
reason: string | null;
|
|
20
|
+
confidence: 'none' | 'low' | 'medium' | 'high';
|
|
21
|
+
matchType: string | null;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface SpamEmailResult {
|
|
25
|
+
isSpam: boolean;
|
|
26
|
+
email: string;
|
|
27
|
+
score: number;
|
|
28
|
+
maxScore: number;
|
|
29
|
+
spamLevel: 'none' | 'low' | 'medium' | 'high';
|
|
30
|
+
reasons: string[];
|
|
31
|
+
details: {
|
|
32
|
+
localPart: string | null;
|
|
33
|
+
domain: string | null;
|
|
34
|
+
matches: Array<{ type: string; pattern?: string; keyword?: string }>;
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface MxResult {
|
|
39
|
+
hasMxRecords: boolean;
|
|
40
|
+
domain: string;
|
|
41
|
+
mxRecords: Array<{ exchange: string; priority: number; type?: string }>;
|
|
42
|
+
error: string | null;
|
|
43
|
+
fallbackToA?: boolean;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export interface FullValidationResult {
|
|
47
|
+
valid: boolean;
|
|
48
|
+
email: string;
|
|
49
|
+
normalized: string | null;
|
|
50
|
+
score: number;
|
|
51
|
+
quality: 'excellent' | 'good' | 'acceptable' | 'poor' | 'bad';
|
|
52
|
+
isTemporary: boolean;
|
|
53
|
+
isSpam: boolean;
|
|
54
|
+
details: {
|
|
55
|
+
format: ValidationResult | null;
|
|
56
|
+
temporary: TemporaryEmailResult | null;
|
|
57
|
+
spam: SpamEmailResult | null;
|
|
58
|
+
mx?: MxResult | { skipped: boolean; reason: string } | { error: string };
|
|
59
|
+
};
|
|
60
|
+
recommendations: string[];
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export interface ValidationOptions {
|
|
64
|
+
strict?: boolean;
|
|
65
|
+
allowPlusAddressing?: boolean;
|
|
66
|
+
checkTld?: boolean;
|
|
67
|
+
maxLength?: number;
|
|
68
|
+
minLocalLength?: number;
|
|
69
|
+
maxLocalLength?: number;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export interface TempCheckOptions {
|
|
73
|
+
customDomains?: string[];
|
|
74
|
+
customPatterns?: RegExp[];
|
|
75
|
+
strictMode?: boolean;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export interface SpamCheckOptions {
|
|
79
|
+
customPatterns?: RegExp[];
|
|
80
|
+
threshold?: number;
|
|
81
|
+
strictMode?: boolean;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export interface FullValidationOptions {
|
|
85
|
+
checkFormat?: boolean;
|
|
86
|
+
checkTemporary?: boolean;
|
|
87
|
+
checkSpam?: boolean;
|
|
88
|
+
checkMx?: boolean;
|
|
89
|
+
spamThreshold?: number;
|
|
90
|
+
strictMode?: boolean;
|
|
91
|
+
mxTimeout?: number;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export interface EmailValidatorOptions {
|
|
95
|
+
allowPlusAddressing?: boolean;
|
|
96
|
+
checkMxRecords?: boolean;
|
|
97
|
+
strictMode?: boolean;
|
|
98
|
+
spamThreshold?: number;
|
|
99
|
+
customTempDomains?: string[];
|
|
100
|
+
customSpamPatterns?: RegExp[];
|
|
101
|
+
mxTimeout?: number;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Main validation functions
|
|
105
|
+
export function validateEmail(email: string, options?: ValidationOptions): ValidationResult;
|
|
106
|
+
export function validateEmailAsync(email: string, options?: FullValidationOptions): Promise<FullValidationResult>;
|
|
107
|
+
export function fullValidation(email: string, options?: FullValidationOptions): FullValidationResult;
|
|
108
|
+
export function fullValidationAsync(email: string, options?: FullValidationOptions): Promise<FullValidationResult>;
|
|
109
|
+
|
|
110
|
+
// Quick validators
|
|
111
|
+
export function isValidEmail(email: string): boolean;
|
|
112
|
+
export function isTempEmail(email: string): boolean;
|
|
113
|
+
export function isTemporaryEmail(email: string, options?: TempCheckOptions): TemporaryEmailResult;
|
|
114
|
+
export function isSpam(email: string, threshold?: number): boolean;
|
|
115
|
+
export function isSpamEmail(email: string, options?: SpamCheckOptions): SpamEmailResult;
|
|
116
|
+
|
|
117
|
+
// Utility functions
|
|
118
|
+
export function normalizeEmail(email: string, options?: {
|
|
119
|
+
lowercase?: boolean;
|
|
120
|
+
removePlusAddressing?: boolean;
|
|
121
|
+
removeDotsFromGmail?: boolean;
|
|
122
|
+
}): string | null;
|
|
123
|
+
export function extractDomain(email: string): string | null;
|
|
124
|
+
export function extractLocal(email: string): string | null;
|
|
125
|
+
|
|
126
|
+
// Domain checks
|
|
127
|
+
export function isDisposableDomain(domain: string): boolean;
|
|
128
|
+
export function isSuspiciousDomain(domain: string): boolean;
|
|
129
|
+
export function addDisposableDomains(domains: string[]): void;
|
|
130
|
+
export function getDisposableDomainCount(): number;
|
|
131
|
+
|
|
132
|
+
// MX validation
|
|
133
|
+
export function checkMxRecords(domain: string, options?: { timeout?: number }): Promise<MxResult>;
|
|
134
|
+
export function validateEmailMx(email: string, options?: { timeout?: number }): Promise<MxResult & { valid: boolean; email: string }>;
|
|
135
|
+
export function batchCheckMxRecords(domains: string[], options?: { concurrency?: number; timeout?: number }): Promise<{ [domain: string]: MxResult }>;
|
|
136
|
+
|
|
137
|
+
// Scoring
|
|
138
|
+
export function getSpamScore(email: string): number;
|
|
139
|
+
|
|
140
|
+
// EmailValidator class
|
|
141
|
+
export class EmailValidator {
|
|
142
|
+
constructor(options?: EmailValidatorOptions);
|
|
143
|
+
validate(email: string): Promise<FullValidationResult>;
|
|
144
|
+
isValid(email: string): boolean;
|
|
145
|
+
isTemporary(email: string): boolean;
|
|
146
|
+
isSpam(email: string): boolean;
|
|
147
|
+
addTempDomains(domains: string[]): void;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// Constants
|
|
151
|
+
export const DISPOSABLE_DOMAINS: Set<string>;
|
|
152
|
+
export const EMAIL_REGEX: RegExp;
|
|
153
|
+
export const SIMPLE_EMAIL_REGEX: RegExp;
|
|
154
|
+
export const VALID_TLDS: Set<string>;
|
|
155
|
+
export const SPAM_LOCAL_PATTERNS: RegExp[];
|
|
156
|
+
export const SPAM_DOMAIN_PATTERNS: RegExp[];
|
package/src/index.js
ADDED
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Valid Email Checker
|
|
3
|
+
* Comprehensive email validation library
|
|
4
|
+
*
|
|
5
|
+
* Features:
|
|
6
|
+
* - Email format validation (RFC 5322)
|
|
7
|
+
* - Temporary/disposable email detection
|
|
8
|
+
* - Spam pattern detection
|
|
9
|
+
* - MX record verification
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
const {
|
|
13
|
+
validateEmail,
|
|
14
|
+
isValidEmail,
|
|
15
|
+
normalizeEmail,
|
|
16
|
+
extractDomain,
|
|
17
|
+
extractLocal,
|
|
18
|
+
EMAIL_REGEX,
|
|
19
|
+
SIMPLE_EMAIL_REGEX,
|
|
20
|
+
VALID_TLDS
|
|
21
|
+
} = require('./validators/formatValidator');
|
|
22
|
+
|
|
23
|
+
const {
|
|
24
|
+
isTemporaryEmail,
|
|
25
|
+
isTempEmail,
|
|
26
|
+
isDisposableDomain,
|
|
27
|
+
addDisposableDomains,
|
|
28
|
+
getDisposableDomainCount
|
|
29
|
+
} = require('./validators/tempMailDetector');
|
|
30
|
+
|
|
31
|
+
const {
|
|
32
|
+
isSpamEmail,
|
|
33
|
+
isSpam,
|
|
34
|
+
getSpamScore,
|
|
35
|
+
isSuspiciousDomain,
|
|
36
|
+
SPAM_LOCAL_PATTERNS,
|
|
37
|
+
SPAM_DOMAIN_PATTERNS
|
|
38
|
+
} = require('./validators/spamDetector');
|
|
39
|
+
|
|
40
|
+
const {
|
|
41
|
+
checkMxRecords,
|
|
42
|
+
validateEmailMx,
|
|
43
|
+
batchCheckMxRecords
|
|
44
|
+
} = require('./validators/mxValidator');
|
|
45
|
+
|
|
46
|
+
const { DISPOSABLE_DOMAINS } = require('./data/disposableDomains');
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Perform full email validation combining all checks
|
|
50
|
+
* @param {string} email - Email to validate
|
|
51
|
+
* @param {object} options - Validation options
|
|
52
|
+
* @returns {object} Comprehensive validation result
|
|
53
|
+
*/
|
|
54
|
+
function fullValidation(email, options = {}) {
|
|
55
|
+
const {
|
|
56
|
+
checkFormat = true,
|
|
57
|
+
checkTemporary = true,
|
|
58
|
+
checkSpam = true,
|
|
59
|
+
spamThreshold = 30,
|
|
60
|
+
strictMode = false
|
|
61
|
+
} = options;
|
|
62
|
+
|
|
63
|
+
const result = {
|
|
64
|
+
valid: false,
|
|
65
|
+
email: email,
|
|
66
|
+
normalized: null,
|
|
67
|
+
score: 100,
|
|
68
|
+
isTemporary: false,
|
|
69
|
+
isSpam: false,
|
|
70
|
+
details: {
|
|
71
|
+
format: null,
|
|
72
|
+
temporary: null,
|
|
73
|
+
spam: null
|
|
74
|
+
},
|
|
75
|
+
recommendations: []
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
// Format validation
|
|
79
|
+
if (checkFormat) {
|
|
80
|
+
const formatResult = validateEmail(email, { strict: strictMode });
|
|
81
|
+
result.details.format = formatResult;
|
|
82
|
+
result.normalized = formatResult.normalized;
|
|
83
|
+
|
|
84
|
+
if (!formatResult.valid) {
|
|
85
|
+
result.valid = false;
|
|
86
|
+
result.score = 0;
|
|
87
|
+
result.recommendations.push('Fix email format errors: ' + formatResult.errors.join(', '));
|
|
88
|
+
return result;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Temporary email check
|
|
93
|
+
if (checkTemporary) {
|
|
94
|
+
const tempResult = isTemporaryEmail(email, { strictMode });
|
|
95
|
+
result.details.temporary = tempResult;
|
|
96
|
+
result.isTemporary = tempResult.isTemporary;
|
|
97
|
+
|
|
98
|
+
if (tempResult.isTemporary) {
|
|
99
|
+
// Reduce score based on confidence
|
|
100
|
+
const scoreReduction = {
|
|
101
|
+
high: 50,
|
|
102
|
+
medium: 35,
|
|
103
|
+
low: 20
|
|
104
|
+
};
|
|
105
|
+
result.score -= scoreReduction[tempResult.confidence] || 30;
|
|
106
|
+
result.recommendations.push('Email appears to be from a disposable email service');
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Spam check
|
|
111
|
+
if (checkSpam) {
|
|
112
|
+
const spamResult = isSpamEmail(email, { threshold: spamThreshold, strictMode });
|
|
113
|
+
result.details.spam = spamResult;
|
|
114
|
+
result.isSpam = spamResult.isSpam;
|
|
115
|
+
|
|
116
|
+
if (spamResult.score > 0) {
|
|
117
|
+
result.score -= Math.min(spamResult.score, 50);
|
|
118
|
+
if (spamResult.isSpam) {
|
|
119
|
+
result.recommendations.push('Email matches spam patterns: ' + spamResult.reasons.slice(0, 2).join(', '));
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Ensure score is within bounds
|
|
125
|
+
result.score = Math.max(0, Math.min(100, result.score));
|
|
126
|
+
|
|
127
|
+
// Determine overall validity
|
|
128
|
+
result.valid = result.score >= 50 && !result.isTemporary;
|
|
129
|
+
|
|
130
|
+
// Add quality assessment
|
|
131
|
+
if (result.score >= 90) {
|
|
132
|
+
result.quality = 'excellent';
|
|
133
|
+
} else if (result.score >= 70) {
|
|
134
|
+
result.quality = 'good';
|
|
135
|
+
} else if (result.score >= 50) {
|
|
136
|
+
result.quality = 'acceptable';
|
|
137
|
+
} else if (result.score >= 30) {
|
|
138
|
+
result.quality = 'poor';
|
|
139
|
+
} else {
|
|
140
|
+
result.quality = 'bad';
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
return result;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Async full validation with MX record check
|
|
148
|
+
* @param {string} email - Email to validate
|
|
149
|
+
* @param {object} options - Validation options
|
|
150
|
+
* @returns {Promise<object>} Comprehensive validation result
|
|
151
|
+
*/
|
|
152
|
+
async function fullValidationAsync(email, options = {}) {
|
|
153
|
+
const { checkMx = true, mxTimeout = 5000 } = options;
|
|
154
|
+
|
|
155
|
+
// Run sync validation first
|
|
156
|
+
const result = fullValidation(email, options);
|
|
157
|
+
|
|
158
|
+
// If format is invalid, skip MX check
|
|
159
|
+
if (!result.details.format?.valid) {
|
|
160
|
+
result.details.mx = { skipped: true, reason: 'Invalid format' };
|
|
161
|
+
return result;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// MX record validation
|
|
165
|
+
if (checkMx) {
|
|
166
|
+
try {
|
|
167
|
+
const mxResult = await validateEmailMx(email, { timeout: mxTimeout });
|
|
168
|
+
result.details.mx = mxResult;
|
|
169
|
+
|
|
170
|
+
if (!mxResult.hasMxRecords) {
|
|
171
|
+
result.score -= 30;
|
|
172
|
+
result.recommendations.push('Domain does not have valid mail server records');
|
|
173
|
+
}
|
|
174
|
+
} catch (error) {
|
|
175
|
+
result.details.mx = { error: error.message };
|
|
176
|
+
result.score -= 10;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// Recalculate validity and quality
|
|
181
|
+
result.score = Math.max(0, Math.min(100, result.score));
|
|
182
|
+
result.valid = result.score >= 50 && !result.isTemporary;
|
|
183
|
+
|
|
184
|
+
if (result.score >= 90) {
|
|
185
|
+
result.quality = 'excellent';
|
|
186
|
+
} else if (result.score >= 70) {
|
|
187
|
+
result.quality = 'good';
|
|
188
|
+
} else if (result.score >= 50) {
|
|
189
|
+
result.quality = 'acceptable';
|
|
190
|
+
} else if (result.score >= 30) {
|
|
191
|
+
result.quality = 'poor';
|
|
192
|
+
} else {
|
|
193
|
+
result.quality = 'bad';
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
return result;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Validate email asynchronously (alias for convenience)
|
|
201
|
+
* @param {string} email - Email to validate
|
|
202
|
+
* @param {object} options - Options
|
|
203
|
+
* @returns {Promise<object>} Validation result
|
|
204
|
+
*/
|
|
205
|
+
async function validateEmailAsync(email, options = {}) {
|
|
206
|
+
return fullValidationAsync(email, options);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* EmailValidator class for custom configuration
|
|
211
|
+
*/
|
|
212
|
+
class EmailValidator {
|
|
213
|
+
constructor(options = {}) {
|
|
214
|
+
this.options = {
|
|
215
|
+
allowPlusAddressing: true,
|
|
216
|
+
checkMxRecords: false,
|
|
217
|
+
strictMode: false,
|
|
218
|
+
spamThreshold: 30,
|
|
219
|
+
customTempDomains: [],
|
|
220
|
+
customSpamPatterns: [],
|
|
221
|
+
mxTimeout: 5000,
|
|
222
|
+
...options
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
// Add custom temp domains
|
|
226
|
+
if (this.options.customTempDomains.length > 0) {
|
|
227
|
+
addDisposableDomains(this.options.customTempDomains);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Validate email
|
|
233
|
+
* @param {string} email - Email to validate
|
|
234
|
+
* @returns {Promise<object>|object} Validation result
|
|
235
|
+
*/
|
|
236
|
+
async validate(email) {
|
|
237
|
+
const validationOptions = {
|
|
238
|
+
checkFormat: true,
|
|
239
|
+
checkTemporary: true,
|
|
240
|
+
checkSpam: true,
|
|
241
|
+
checkMx: this.options.checkMxRecords,
|
|
242
|
+
spamThreshold: this.options.spamThreshold,
|
|
243
|
+
strictMode: this.options.strictMode,
|
|
244
|
+
mxTimeout: this.options.mxTimeout,
|
|
245
|
+
customPatterns: this.options.customSpamPatterns
|
|
246
|
+
};
|
|
247
|
+
|
|
248
|
+
if (this.options.checkMxRecords) {
|
|
249
|
+
return fullValidationAsync(email, validationOptions);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
return fullValidation(email, validationOptions);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Quick validation - format only
|
|
257
|
+
* @param {string} email - Email to validate
|
|
258
|
+
* @returns {boolean} True if valid format
|
|
259
|
+
*/
|
|
260
|
+
isValid(email) {
|
|
261
|
+
return isValidEmail(email);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Check if temporary email
|
|
266
|
+
* @param {string} email - Email to check
|
|
267
|
+
* @returns {boolean} True if temporary
|
|
268
|
+
*/
|
|
269
|
+
isTemporary(email) {
|
|
270
|
+
return isTempEmail(email);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* Check if spam email
|
|
275
|
+
* @param {string} email - Email to check
|
|
276
|
+
* @returns {boolean} True if spam
|
|
277
|
+
*/
|
|
278
|
+
isSpam(email) {
|
|
279
|
+
return isSpam(email, this.options.spamThreshold);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Add custom disposable domains
|
|
284
|
+
* @param {string[]} domains - Domains to add
|
|
285
|
+
*/
|
|
286
|
+
addTempDomains(domains) {
|
|
287
|
+
addDisposableDomains(domains);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// Export everything
|
|
292
|
+
module.exports = {
|
|
293
|
+
// Main validation functions
|
|
294
|
+
validateEmail,
|
|
295
|
+
validateEmailAsync,
|
|
296
|
+
fullValidation,
|
|
297
|
+
fullValidationAsync,
|
|
298
|
+
|
|
299
|
+
// Quick validators
|
|
300
|
+
isValidEmail,
|
|
301
|
+
isTempEmail,
|
|
302
|
+
isTemporaryEmail,
|
|
303
|
+
isSpam,
|
|
304
|
+
isSpamEmail,
|
|
305
|
+
|
|
306
|
+
// Utility functions
|
|
307
|
+
normalizeEmail,
|
|
308
|
+
extractDomain,
|
|
309
|
+
extractLocal,
|
|
310
|
+
|
|
311
|
+
// Domain checks
|
|
312
|
+
isDisposableDomain,
|
|
313
|
+
isSuspiciousDomain,
|
|
314
|
+
addDisposableDomains,
|
|
315
|
+
getDisposableDomainCount,
|
|
316
|
+
|
|
317
|
+
// MX validation
|
|
318
|
+
checkMxRecords,
|
|
319
|
+
validateEmailMx,
|
|
320
|
+
batchCheckMxRecords,
|
|
321
|
+
|
|
322
|
+
// Scoring
|
|
323
|
+
getSpamScore,
|
|
324
|
+
|
|
325
|
+
// Class for custom configuration
|
|
326
|
+
EmailValidator,
|
|
327
|
+
|
|
328
|
+
// Constants (for advanced users)
|
|
329
|
+
DISPOSABLE_DOMAINS,
|
|
330
|
+
EMAIL_REGEX,
|
|
331
|
+
SIMPLE_EMAIL_REGEX,
|
|
332
|
+
VALID_TLDS,
|
|
333
|
+
SPAM_LOCAL_PATTERNS,
|
|
334
|
+
SPAM_DOMAIN_PATTERNS
|
|
335
|
+
};
|