Node.js Email Validation
Complete guide to email validation in Node.js
What You'll Learn
- Install and configure VerifyForge in Node.js
- Validate emails in Express routes
- Create reusable middleware
- Handle validation errors
- Implement bulk validation
- Best practices for production
Prerequisites
- Node.js 16+ installed
- Basic knowledge of Node.js and Express
- VerifyForge API key (get free key)
Installation
npm install @verifyforge/sdk express
Quick Start
import { VerifyForge } from '@verifyforge/sdk';
const client = new VerifyForge({ apiKey: 'your_api_key' });
const result = await client.validate('user@example.com');
if (result.data.isValid) {
console.log('✓ Email is valid!');
console.log(`Reachability: ${result.data.reachability}`);
}
Tutorial 1: Express API Routes
// server.js
import express from 'express';
import { VerifyForge } from '@verifyforge/sdk';
const app = express();
const client = new VerifyForge({ apiKey: process.env.VERIFYFORGE_API_KEY });
app.use(express.json());
// Validate single email
app.post('/api/validate', async (req, res) => {
const { email } = req.body;
if (!email) {
return res.status(400).json({ error: 'Email is required' });
}
try {
const result = await client.validate(email);
res.json({
success: true,
data: {
email: result.data.email,
isValid: result.data.isValid,
reachability: result.data.reachability,
disposable: result.data.disposable,
roleAccount: result.data.roleAccount,
suggestion: result.data.suggestion,
},
});
} catch (error) {
console.error('Validation error:', error);
res.status(500).json({ error: 'Validation failed' });
}
});
// Bulk validate
app.post('/api/validate-bulk', async (req, res) => {
const { emails } = req.body;
if (!Array.isArray(emails) || emails.length === 0) {
return res.status(400).json({ error: 'Emails array is required' });
}
if (emails.length > 100) {
return res.status(400).json({ error: 'Maximum 100 emails per request' });
}
try {
const result = await client.validateBulk(emails);
res.json({
success: true,
data: result.data,
summary: result.data.summary,
});
} catch (error) {
console.error('Bulk validation error:', error);
res.status(500).json({ error: 'Bulk validation failed' });
}
});
app.listen(3000, () => {
console.log('Server running on port 3000');
});
Tutorial 2: Validation Middleware
// middleware/validateEmail.js
import { VerifyForge } from '@verifyforge/sdk';
const client = new VerifyForge({ apiKey: process.env.VERIFYFORGE_API_KEY });
// Cache for validation results
const cache = new Map();
const CACHE_TTL = 3600000; // 1 hour
export const validateEmail = async (req, res, next) => {
const email = req.body.email || req.query.email;
if (!email) {
return res.status(400).json({ error: 'Email is required' });
}
try {
// Check cache
if (cache.has(email)) {
const cached = cache.get(email);
if (Date.now() - cached.timestamp < CACHE_TTL) {
req.emailValidation = cached.data;
return next();
}
cache.delete(email);
}
// Validate
const result = await client.validate(email);
if (!result.data.isValid) {
return res.status(422).json({
error: 'Invalid email address',
suggestion: result.data.suggestion,
});
}
if (result.data.disposable) {
return res.status(422).json({
error: 'Temporary email addresses are not allowed',
});
}
// Cache result
cache.set(email, {
data: result.data,
timestamp: Date.now(),
});
// Attach to request
req.emailValidation = result.data;
next();
} catch (error) {
console.error('Email validation error:', error);
// Fail gracefully - allow request to continue
next();
}
};
Use in routes:
import { validateEmail } from './middleware/validateEmail.js';
app.post('/api/subscribe', validateEmail, async (req, res) => {
const { email, name } = req.body;
// Email is already validated by middleware
const validation = req.emailValidation;
// Save subscriber
console.log('Saving subscriber:', { email, name, validation });
res.json({ success: true, message: 'Subscribed successfully' });
});
Tutorial 3: Validation Service Class
// services/EmailValidationService.js
import { VerifyForge, AuthenticationError, InsufficientCreditsError } from '@verifyforge/sdk';
export class EmailValidationService {
constructor(apiKey) {
this.client = new VerifyForge({ apiKey });
this.cache = new Map();
}
async validate(email) {
// Check cache
if (this.cache.has(email)) {
const cached = this.cache.get(email);
if (Date.now() - cached.timestamp < 3600000) {
return cached.result;
}
this.cache.delete(email);
}
// Validate
const result = await this.client.validate(email);
// Cache result
this.cache.set(email, {
result: result.data,
timestamp: Date.now(),
});
return result.data;
}
async validateBulk(emails) {
const result = await this.client.validateBulk(emails);
return result.data;
}
async isValid(email) {
try {
const result = await this.validate(email);
return result.isValid;
} catch (error) {
console.error('Validation error:', error);
return false;
}
}
clearCache() {
this.cache.clear();
}
}
// Usage
const validationService = new EmailValidationService(process.env.VERIFYFORGE_API_KEY);
export default validationService;
Tutorial 4: Error Handling
// utils/errorHandler.js
import { AuthenticationError, InsufficientCreditsError, ValidationError } from '@verifyforge/sdk';
export const handleValidationError = (error, res) => {
if (error instanceof AuthenticationError) {
return res.status(401).json({
error: 'Invalid API key',
});
}
if (error instanceof InsufficientCreditsError) {
return res.status(402).json({
error: 'Insufficient credits',
});
}
if (error instanceof ValidationError) {
return res.status(400).json({
error: error.message,
details: error.details,
});
}
console.error('Unexpected error:', error);
return res.status(500).json({
error: 'Internal server error',
});
};
Use in routes:
import { handleValidationError } from './utils/errorHandler.js';
app.post('/api/validate', async (req, res) => {
try {
const result = await client.validate(req.body.email);
res.json({ success: true, data: result.data });
} catch (error) {
handleValidationError(error, res);
}
});
Tutorial 5: Rate Limiting
// middleware/rateLimiter.js
import rateLimit from 'express-rate-limit';
export const validationRateLimiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100, // Limit each IP to 100 requests per windowMs
message: 'Too many validation requests, please try again later',
standardHeaders: true,
legacyHeaders: false,
});
Apply to routes:
import { validationRateLimiter } from './middleware/rateLimiter.js';
app.post('/api/validate', validationRateLimiter, async (req, res) => {
// ... validation logic
});
Best Practices
1. Environment Variables
# .env
VERIFYFORGE_API_KEY=your_api_key_here
PORT=3000
import 'dotenv/config';
const client = new VerifyForge({
apiKey: process.env.VERIFYFORGE_API_KEY
});
2. Async Error Handling Wrapper
// utils/asyncHandler.js
export const asyncHandler = (fn) => (req, res, next) => {
Promise.resolve(fn(req, res, next)).catch(next);
};
// Usage
app.post('/api/validate', asyncHandler(async (req, res) => {
const result = await client.validate(req.body.email);
res.json({ success: true, data: result.data });
}));
3. Request Timeout
import timeout from 'connect-timeout';
app.use(timeout('30s'));
app.use((req, res, next) => {
if (!req.timedout) next();
});
4. Logging
import winston from 'winston';
const logger = winston.createLogger({
level: 'info',
format: winston.format.json(),
transports: [
new winston.transports.File({ filename: 'error.log', level: 'error' }),
new winston.transports.File({ filename: 'combined.log' }),
],
});
// Log validation errors
try {
const result = await client.validate(email);
logger.info('Email validated', { email, isValid: result.data.isValid });
} catch (error) {
logger.error('Validation failed', { email, error: error.message });
}
Complete Example: Newsletter API
// server.js
import express from 'express';
import { VerifyForge } from '@verifyforge/sdk';
import { validateEmail } from './middleware/validateEmail.js';
import { validationRateLimiter } from './middleware/rateLimiter.js';
const app = express();
const client = new VerifyForge({ apiKey: process.env.VERIFYFORGE_API_KEY });
app.use(express.json());
// In-memory storage (use database in production)
const subscribers = new Set();
app.post('/api/subscribe',
validationRateLimiter,
validateEmail,
async (req, res) => {
const { email, name } = req.body;
if (!name) {
return res.status(400).json({ error: 'Name is required' });
}
// Check if already subscribed
if (subscribers.has(email)) {
return res.status(409).json({
error: 'Email already subscribed',
});
}
// Email is validated by middleware
const validation = req.emailValidation;
// Additional checks
if (validation.reachability === 'risky') {
return res.status(422).json({
error: 'This email appears risky',
});
}
// Add subscriber
subscribers.add(email);
res.json({
success: true,
message: 'Successfully subscribed',
subscriber: { email, name },
});
}
);
app.get('/api/subscribers', (req, res) => {
res.json({
count: subscribers.size,
subscribers: Array.from(subscribers),
});
});
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
Testing
// test/validation.test.js
import { VerifyForge } from '@verifyforge/sdk';
import { expect } from 'chai';
describe('Email Validation', () => {
const client = new VerifyForge({
apiKey: process.env.VERIFYFORGE_API_KEY
});
it('should validate a valid email', async () => {
const result = await client.validate('test@example.com');
expect(result.data).to.have.property('isValid');
expect(result.data.email).to.equal('test@example.com');
});
it('should detect disposable emails', async () => {
const result = await client.validate('test@tempmail.com');
expect(result.data.disposable).to.be.true;
});
it('should validate bulk emails', async () => {
const emails = ['test1@example.com', 'test2@example.com'];
const result = await client.validateBulk(emails);
expect(result.data.results).to.have.lengthOf(2);
});
});
Troubleshooting
Problem: Module not found errors
Solution: Ensure you're using ES modules. Add to package.json:
{
"type": "module"
}
Problem: API key not found
Solution: Install dotenv and load it: import 'dotenv/config'
Problem: Timeout errors
Solution: Increase client timeout:
const client = new VerifyForge({
apiKey: process.env.VERIFYFORGE_API_KEY,
timeout: 60000 // 60 seconds
});
