bouncevalidator 0.0.1

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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 HyScaler(R) - NetTantra Technologies (India) Private Limited
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,483 @@
1
+ # BounceValidator
2
+
3
+ A completely local email validation service for Node.js. An alternative to cloud-based services like ZeroBounce, Bouncify, and Debounce - with zero external API dependencies.
4
+
5
+ ## Features
6
+
7
+ - **100% Local** - No external API calls, all validation happens on your machine
8
+ - **Syntax Validation** - RFC 5322 compliant email format validation
9
+ - **DNS/MX Verification** - Verifies domain has valid mail exchange records
10
+ - **SMTP Verification** - Connects to mail servers to verify mailbox existence
11
+ - **Disposable Email Detection** - Identifies temporary/throwaway email addresses
12
+ - **Role Account Detection** - Flags role-based emails (admin@, support@, etc.)
13
+ - **Free Provider Detection** - Identifies emails from free providers (Gmail, Yahoo, etc.)
14
+ - **Typo Suggestions** - Suggests corrections for common domain typos
15
+ - **Catch-All Detection** - Identifies domains that accept all addresses
16
+ - **Bulk Validation** - Process multiple emails with configurable concurrency
17
+ - **DNS Caching** - Improves performance for repeated lookups
18
+ - **CLI & Programmatic API** - Use from command line or as a library
19
+
20
+ ## Installation
21
+
22
+ ```bash
23
+ npm install bouncevalidator
24
+ ```
25
+
26
+ Or with yarn:
27
+
28
+ ```bash
29
+ yarn add bouncevalidator
30
+ ```
31
+
32
+ ## Quick Start
33
+
34
+ ### Programmatic Usage
35
+
36
+ ```typescript
37
+ import { validate } from 'bouncevalidator';
38
+
39
+ const result = await validate('user@example.com');
40
+
41
+ console.log(result.isReachable); // 'safe', 'invalid', 'risky', or 'unknown'
42
+ console.log(result.syntax.isValidSyntax); // true/false
43
+ console.log(result.mx.acceptsMail); // true/false
44
+ console.log(result.smtp.isDeliverable); // true/false
45
+ console.log(result.misc.isDisposable); // true/false
46
+ ```
47
+
48
+ ### CLI Usage
49
+
50
+ ```bash
51
+ # Validate a single email
52
+ npx bouncevalidator user@example.com
53
+
54
+ # Validate with pretty output
55
+ npx bouncevalidator -p user@example.com
56
+
57
+ # Quick validation (skip SMTP)
58
+ npx bouncevalidator -q user@example.com
59
+
60
+ # Validate from file
61
+ npx bouncevalidator -f emails.txt -o results.json
62
+ ```
63
+
64
+ ## API Reference
65
+
66
+ ### `validate(email, options?)`
67
+
68
+ Validates a single email address through the full verification pipeline.
69
+
70
+ **Parameters:**
71
+ - `email` (string) - The email address to validate
72
+ - `options` (ValidationOptions) - Optional configuration
73
+
74
+ **Returns:** `Promise<ValidationResult>`
75
+
76
+ ```typescript
77
+ import { validate } from 'bouncevalidator';
78
+
79
+ const result = await validate('user@gmail.com', {
80
+ smtpTimeout: 15000,
81
+ checkGravatar: true
82
+ });
83
+ ```
84
+
85
+ ### `validateBulk(emails, options?)`
86
+
87
+ Validates multiple email addresses with configurable concurrency.
88
+
89
+ **Parameters:**
90
+ - `emails` (string[]) - Array of email addresses
91
+ - `options` (BulkValidationOptions) - Optional configuration
92
+
93
+ **Returns:** `Promise<ValidationResult[]>`
94
+
95
+ ```typescript
96
+ import { validateBulk } from 'bouncevalidator';
97
+
98
+ const results = await validateBulk([
99
+ 'user1@example.com',
100
+ 'user2@example.com',
101
+ 'user3@example.com'
102
+ ], {
103
+ concurrency: 10,
104
+ onProgress: (completed, total, result) => {
105
+ console.log(`${completed}/${total}: ${result.input} - ${result.isReachable}`);
106
+ }
107
+ });
108
+ ```
109
+
110
+ ### `validateQuick(email)`
111
+
112
+ Quick validation that only checks syntax and MX records (skips SMTP verification).
113
+
114
+ **Parameters:**
115
+ - `email` (string) - The email address to validate
116
+
117
+ **Returns:** `Promise<ValidationResult>`
118
+
119
+ ```typescript
120
+ import { validateQuick } from 'bouncevalidator';
121
+
122
+ const result = await validateQuick('user@example.com');
123
+ ```
124
+
125
+ ### Individual Validators
126
+
127
+ You can use individual validators for more control:
128
+
129
+ ```typescript
130
+ import {
131
+ validateSyntax,
132
+ verifyMx,
133
+ verifySmtp,
134
+ checkMisc,
135
+ checkDisposable,
136
+ checkRoleAccount,
137
+ checkFreeProvider
138
+ } from 'bouncevalidator';
139
+
140
+ // Syntax validation only
141
+ const syntax = validateSyntax('user@example.com');
142
+
143
+ // MX verification only
144
+ const mx = await verifyMx('example.com');
145
+
146
+ // Check if domain is disposable
147
+ const isDisposable = checkDisposable('tempmail.com');
148
+
149
+ // Check if email is role-based
150
+ const isRole = checkRoleAccount('admin');
151
+ ```
152
+
153
+ ### Utility Functions
154
+
155
+ ```typescript
156
+ import {
157
+ normalizeEmail,
158
+ extractParts,
159
+ getSuggestion,
160
+ getEmailSuggestion
161
+ } from 'bouncevalidator';
162
+
163
+ // Normalize email
164
+ const normalized = normalizeEmail('User@GMAIL.com'); // 'user@gmail.com'
165
+
166
+ // Extract parts
167
+ const parts = extractParts('user@example.com');
168
+ // { username: 'user', domain: 'example.com' }
169
+
170
+ // Get domain typo suggestion
171
+ const suggestion = getSuggestion('gmial.com'); // 'gmail.com'
172
+
173
+ // Get full email suggestion
174
+ const emailSuggestion = getEmailSuggestion('user@gmial.com');
175
+ // 'user@gmail.com'
176
+ ```
177
+
178
+ ## Configuration Options
179
+
180
+ ### ValidationOptions
181
+
182
+ | Option | Type | Default | Description |
183
+ |--------|------|---------|-------------|
184
+ | `smtpTimeout` | number | 10000 | SMTP connection timeout in milliseconds |
185
+ | `verifySmtp` | boolean | true | Whether to perform SMTP verification |
186
+ | `checkDisposable` | boolean | true | Check for disposable email domains |
187
+ | `checkRoleAccount` | boolean | true | Check for role-based accounts |
188
+ | `checkFreeProvider` | boolean | true | Check for free email providers |
189
+ | `checkGravatar` | boolean | false | Check for Gravatar existence |
190
+ | `heloHost` | string | hostname | Custom HELO/EHLO hostname |
191
+ | `senderAddress` | string | '' | Custom MAIL FROM address |
192
+ | `dnsCacheTtl` | number | 300000 | DNS cache TTL in milliseconds |
193
+ | `useDnsCache` | boolean | true | Whether to use DNS caching |
194
+ | `detectCatchAll` | boolean | true | Detect catch-all domains |
195
+
196
+ ### BulkValidationOptions
197
+
198
+ Extends ValidationOptions with:
199
+
200
+ | Option | Type | Default | Description |
201
+ |--------|------|---------|-------------|
202
+ | `concurrency` | number | 5 | Maximum concurrent validations |
203
+ | `delayBetween` | number | 0 | Delay between batches in milliseconds |
204
+ | `onProgress` | function | - | Progress callback function |
205
+
206
+ ## ValidationResult Structure
207
+
208
+ ```typescript
209
+ interface ValidationResult {
210
+ input: string; // Original email input
211
+ isReachable: Reachability; // 'safe' | 'invalid' | 'risky' | 'unknown'
212
+
213
+ syntax: {
214
+ address: string; // Original address
215
+ domain: string; // Domain part
216
+ username: string; // Local part
217
+ isValidSyntax: boolean; // Syntax validity
218
+ normalizedEmail: string; // Normalized version
219
+ suggestion: string | null; // Typo suggestion
220
+ };
221
+
222
+ mx: {
223
+ acceptsMail: boolean; // Has valid MX records
224
+ records: string[]; // List of MX hostnames
225
+ };
226
+
227
+ smtp: {
228
+ canConnectSmtp: boolean; // Could connect to server
229
+ isDeliverable: boolean; // Mailbox exists
230
+ isCatchAll: boolean; // Domain is catch-all
231
+ error: {
232
+ type: string; // Error type
233
+ message: string; // Error message
234
+ } | null;
235
+ };
236
+
237
+ misc: {
238
+ isDisposable: boolean; // Disposable domain
239
+ isRoleAccount: boolean; // Role-based account
240
+ isFreeProvider: boolean; // Free email provider
241
+ gravatarUrl: string | null; // Gravatar URL if exists
242
+ };
243
+ }
244
+ ```
245
+
246
+ ## Reachability Status
247
+
248
+ | Status | Description |
249
+ |--------|-------------|
250
+ | `safe` | Email is verified to exist and can receive mail |
251
+ | `invalid` | Email has invalid syntax, domain doesn't exist, or mailbox not found |
252
+ | `risky` | Email might be valid but couldn't be verified (catch-all, greylisted, etc.) |
253
+ | `unknown` | Verification was inconclusive due to server issues |
254
+
255
+ ## CLI Reference
256
+
257
+ ```
258
+ bouncevalidator - Local email validation service
259
+
260
+ USAGE:
261
+ bouncevalidator [OPTIONS] <email>...
262
+ bouncevalidator -f <file> [OPTIONS]
263
+
264
+ ARGUMENTS:
265
+ <email>... Email addresses to validate
266
+
267
+ OPTIONS:
268
+ -h, --help Show help message
269
+ -v, --version Show version number
270
+ -f, --file <path> Read emails from file (one per line)
271
+ -o, --output <path> Write results to file
272
+ -q, --quick Quick mode (skip SMTP verification)
273
+ -p, --pretty Pretty print JSON output
274
+ --verbose Show detailed progress
275
+
276
+ VALIDATION OPTIONS:
277
+ -t, --timeout <ms> SMTP timeout (default: 10000)
278
+ -c, --concurrency <n> Max concurrent validations (default: 5)
279
+ --no-smtp Skip SMTP verification
280
+ --no-disposable Skip disposable email check
281
+ --no-role Skip role account check
282
+ --no-free-provider Skip free provider check
283
+ --gravatar Check for Gravatar
284
+
285
+ EXIT CODES:
286
+ 0 All emails are valid (safe)
287
+ 1 One or more emails are invalid
288
+ 2 One or more emails are risky or unknown
289
+ 3 Error occurred during validation
290
+ ```
291
+
292
+ ## Examples
293
+
294
+ ### Basic Validation
295
+
296
+ ```typescript
297
+ import { validate } from 'bouncevalidator';
298
+
299
+ async function checkEmail(email: string) {
300
+ const result = await validate(email);
301
+
302
+ if (result.isReachable === 'safe') {
303
+ console.log('Email is valid and deliverable');
304
+ } else if (result.isReachable === 'invalid') {
305
+ console.log('Email is invalid:', result.smtp.error?.message);
306
+ } else {
307
+ console.log('Email status uncertain:', result.isReachable);
308
+ }
309
+ }
310
+ ```
311
+
312
+ ### Bulk Validation with Progress
313
+
314
+ ```typescript
315
+ import { validateBulk } from 'bouncevalidator';
316
+ import fs from 'fs';
317
+
318
+ async function validateEmailList(filePath: string) {
319
+ const emails = fs.readFileSync(filePath, 'utf-8')
320
+ .split('\n')
321
+ .map(e => e.trim())
322
+ .filter(e => e.length > 0);
323
+
324
+ const results = await validateBulk(emails, {
325
+ concurrency: 10,
326
+ onProgress: (completed, total, result) => {
327
+ const pct = Math.round((completed / total) * 100);
328
+ process.stdout.write(`\r[${pct}%] Validating emails...`);
329
+ }
330
+ });
331
+
332
+ const valid = results.filter(r => r.isReachable === 'safe');
333
+ const invalid = results.filter(r => r.isReachable === 'invalid');
334
+
335
+ console.log(`\nValid: ${valid.length}, Invalid: ${invalid.length}`);
336
+
337
+ return results;
338
+ }
339
+ ```
340
+
341
+ ### Custom Validation Pipeline
342
+
343
+ ```typescript
344
+ import {
345
+ validateSyntax,
346
+ verifyMx,
347
+ checkDisposable,
348
+ checkRoleAccount
349
+ } from 'bouncevalidator';
350
+
351
+ async function customValidation(email: string) {
352
+ // Step 1: Check syntax
353
+ const syntax = validateSyntax(email);
354
+ if (!syntax.isValidSyntax) {
355
+ return { valid: false, reason: 'Invalid syntax' };
356
+ }
357
+
358
+ // Step 2: Check if disposable
359
+ if (checkDisposable(syntax.domain)) {
360
+ return { valid: false, reason: 'Disposable email' };
361
+ }
362
+
363
+ // Step 3: Check if role account
364
+ if (checkRoleAccount(syntax.username)) {
365
+ return { valid: false, reason: 'Role-based account' };
366
+ }
367
+
368
+ // Step 4: Verify MX records
369
+ const mx = await verifyMx(syntax.domain);
370
+ if (!mx.acceptsMail) {
371
+ return { valid: false, reason: 'Domain does not accept mail' };
372
+ }
373
+
374
+ return { valid: true, domain: syntax.domain, mx: mx.records };
375
+ }
376
+ ```
377
+
378
+ ### Express.js Integration
379
+
380
+ ```typescript
381
+ import express from 'express';
382
+ import { validate, validateBulk } from 'bouncevalidator';
383
+
384
+ const app = express();
385
+ app.use(express.json());
386
+
387
+ // Single email validation endpoint
388
+ app.post('/api/validate', async (req, res) => {
389
+ const { email } = req.body;
390
+
391
+ if (!email) {
392
+ return res.status(400).json({ error: 'Email is required' });
393
+ }
394
+
395
+ try {
396
+ const result = await validate(email);
397
+ res.json(result);
398
+ } catch (err) {
399
+ res.status(500).json({ error: 'Validation failed' });
400
+ }
401
+ });
402
+
403
+ // Bulk validation endpoint
404
+ app.post('/api/validate/bulk', async (req, res) => {
405
+ const { emails } = req.body;
406
+
407
+ if (!Array.isArray(emails)) {
408
+ return res.status(400).json({ error: 'Emails array is required' });
409
+ }
410
+
411
+ try {
412
+ const results = await validateBulk(emails, { concurrency: 5 });
413
+ res.json(results);
414
+ } catch (err) {
415
+ res.status(500).json({ error: 'Validation failed' });
416
+ }
417
+ });
418
+
419
+ app.listen(3000);
420
+ ```
421
+
422
+ ## How It Works
423
+
424
+ ### 1. Syntax Validation
425
+
426
+ The first step validates the email format against RFC 5322 standards:
427
+ - Checks for valid characters in local and domain parts
428
+ - Validates domain structure and TLD
429
+ - Enforces length limits (254 chars total, 64 chars local part)
430
+
431
+ ### 2. DNS/MX Verification
432
+
433
+ Next, we query DNS to verify the domain can receive email:
434
+ - Looks up MX (Mail Exchange) records
435
+ - Falls back to A/AAAA records if no MX exists (per RFC 5321)
436
+ - Detects null MX records (RFC 7505)
437
+ - Caches results for performance
438
+
439
+ ### 3. SMTP Verification
440
+
441
+ The most reliable check - we connect to the mail server:
442
+ 1. Connect to the highest priority MX host
443
+ 2. Send EHLO/HELO greeting
444
+ 3. Initiate MAIL FROM command
445
+ 4. Send RCPT TO with the target email
446
+ 5. Interpret the server's response
447
+
448
+ Response codes:
449
+ - 250: Mailbox exists
450
+ - 550: Mailbox not found
451
+ - 450/451: Greylisted or temporary failure
452
+ - 552: Mailbox disabled
453
+
454
+ ### 4. Additional Checks
455
+
456
+ Finally, we perform supplementary checks:
457
+ - **Disposable detection**: Compares domain against 500+ known disposable email services
458
+ - **Role account detection**: Checks for common role-based prefixes (admin, support, info, etc.)
459
+ - **Free provider detection**: Identifies free email services (Gmail, Yahoo, Outlook, etc.)
460
+ - **Catch-all detection**: Tests if domain accepts any random address
461
+
462
+ ## Limitations
463
+
464
+ - **SMTP verification may be blocked**: Some mail servers block or rate-limit SMTP verification attempts
465
+ - **Greylisting**: Some servers use greylisting which causes temporary rejections
466
+ - **Catch-all domains**: Cannot definitively verify addresses on catch-all domains
467
+ - **Network dependent**: Requires network access for DNS and SMTP operations
468
+ - **No DMARC/SPF checks**: Does not validate sending reputation
469
+
470
+ ## Performance Tips
471
+
472
+ 1. **Use DNS caching**: Enabled by default, reduces repeated DNS lookups
473
+ 2. **Adjust concurrency**: Higher concurrency for bulk operations, but be mindful of rate limits
474
+ 3. **Use quick mode**: Skip SMTP verification when you only need syntax/MX validation
475
+ 4. **Batch operations**: Use `validateBulk` instead of multiple `validate` calls
476
+
477
+ ## Contributing
478
+
479
+ Contributions are welcome! Please feel free to submit issues and pull requests.
480
+
481
+ ## License
482
+
483
+ MIT