A robust, scalable, and high-throughput email processing service built with Node.js, BullMQ, Redis, and Nodemailer. TurboMailer allows you to send emails efficiently, handle retries, manage priorities, and monitor queue status with ease.
- Features
- Prerequisites
- Installation
- Getting Started
- Usage
- Configuration Options
- Advanced Usage
- Example
- Testing
- Asynchronous Email Processing: Offload email sending to a queue to improve application responsiveness.
- High Throughput: Efficiently handle thousands of emails concurrently using BullMQ and Redis.
- Retry Mechanism: Automatic retries with customizable backoff strategies for transient failures.
- Priority Handling: Assign priorities to emails to ensure critical messages are sent first.
- Delayed Emails: Schedule emails to be sent at a later time.
- Monitoring: Retrieve queue status and monitor email processing metrics.
- Graceful Shutdown: Safely close connections and workers on application termination.
- Node.js: Version 14 or higher.
- Redis Server: Version 6.2.0 or higher (required by BullMQ 5.x).
- SMTP Server Credentials: Access to an SMTP server for sending emails.
Install TurboMailer via npm:
npm install turbomailer
Before using TurboMailer, you need to configure it with your SMTP and Redis settings.
- SMTP Configuration: Used by Nodemailer to send emails.
- Redis Configuration: Used by BullMQ for job queueing.
import { EmailService, EmailServiceConfig } from 'turbomailer';
const config: EmailServiceConfig = {
transporter: {
host: 'smtp.yourserver.com',
port: 587,
secure: false, // true for port 465, false for other ports
auth: {
user: 'your_username',
pass: 'your_password',
},
},
concurrency: 5, // Number of concurrent email processing jobs
retryLimit: 3, // Number of retries for failed emails
backoffStrategy: 5000, // Delay between retries in milliseconds
logLevel: 'info', // 'error' | 'warn' | 'info' | 'verbose' | 'debug' | 'silly'
redis: {
host: 'localhost',
port: 6379,
},
queueName: 'mailerQueue' // Defaults to emailQueue
};
const emailService = new EmailService(config);
const emailOptions = {
from: '[email protected]',
to: '[email protected]',
subject: 'Welcome to Our Service',
text: 'Thank you for signing up!',
};
await emailService.sendEmail(emailOptions);
To queue an email for asynchronous processing:
await emailService.queueEmail(emailOptions);
TurboMailer automatically processes queued emails using the worker initialized during instantiation. You can adjust the concurrency level in the configuration.
Assign priorities to ensure critical emails are sent first:
const highPriorityEmail = {
...emailOptions,
priority: 'high', // 'high' | 'normal' | 'low'
};
await emailService.queueEmail(highPriorityEmail);
Schedule an email to be sent after a certain delay:
await emailService.queueEmail(emailOptions, {
delay: 60000, // Delay in milliseconds (e.g., 60000ms = 1 minute)
});
Retrieve the current status of the email queue:
const status = await emailService.getQueueStatus();
console.log(status);
/*
{
waiting: 5,
active: 2,
completed: 10,
failed: 1,
delayed: 3,
}
*/
Ensure all resources are properly closed when shutting down your application:
await emailService.close();
Property | Type | Required | Description |
---|---|---|---|
transporter | TransporterConfig |
Yes | SMTP configuration object used by Nodemailer. |
concurrency | number |
No | Number of concurrent email processing jobs (default: 5). |
retryLimit | number |
No | Number of retries for failed emails (default: 3). |
backoffStrategy | number |
No | Delay between retries in milliseconds (default: 5000). |
logLevel | 'error' | 'warn' | 'info' | 'debug' |
No | Logging level for the internal logger (default: 'info'). |
redis | RedisOptions |
No | Redis connection options. Defaults to { host: '127.0.0.1', port: 6379 } . |
Example:
const config: EmailServiceConfig = {
transporter: {
host: 'smtp.yourserver.com',
port: 465,
secure: true,
auth: {
user: 'your_username',
pass: 'your_password',
},
},
concurrency: 10,
retryLimit: 5,
backoffStrategy: 10000,
logLevel: 'debug',
redis: {
host: 'redis-server',
port: 6380,
password: 'your_redis_password',
db: 1,
},
};
Property | Type | Required | Description |
---|---|---|---|
from | string |
Yes | Sender's email address. |
to | string |
Yes | Recipient's email address. |
subject | string |
Yes | Email subject line. |
text | string |
No | Plain text version of the email content. |
html | string |
No | HTML version of the email content. |
attachments | Attachment[] |
No | Array of attachment objects as per Nodemailer specifications. |
priority | 'high' | 'normal' | 'low' |
No | Email priority level (default: 'normal'). |
Example:
const emailOptions = {
from: '[email protected]',
to: '[email protected]',
subject: 'Account Activation',
html: '<h1>Activate Your Account</h1><p>Please click the link below to activate your account.</p>',
priority: 'high',
};
Property | Type | Required | Description |
---|---|---|---|
priority | number |
No | Custom priority value (1 is highest). |
delay | number |
No | Delay before the job becomes active, in milliseconds. |
removeOnComplete | boolean |
No | Whether to remove the job from the queue upon completion (default: true). |
Example:
const queueOptions = {
priority: 1, // High priority
delay: 300000, // Delay of 5 minutes
removeOnComplete: false, // Keep the job in the queue after completion
};
Handle errors gracefully using try-catch blocks:
try {
await emailService.sendEmail(emailOptions);
} catch (error) {
console.error('Failed to send email:', error.message);
}
Listen to events emitted by TurboMailer for custom actions:
emailService.eventEmitter.on('completed', ({ jobId, emailOptions }) => {
console.log(`Email sent successfully: Job ID ${jobId}`);
});
emailService.eventEmitter.on('failed', ({ jobId, failedReason, emailOptions }) => {
console.error(`Email failed: Job ID ${jobId}, Reason: ${failedReason}`);
});
emailService.eventEmitter.on('error', err => {
console.error('Worker error:', err.message);
});
Customize the Redis connection by providing additional options:
const config: EmailServiceConfig = {
// ... other configurations
redis: {
host: 'custom-redis-host',
port: 6380,
password: 'your_redis_password',
db: 2,
tls: {
// TLS/SSL options if needed
},
},
};
Here's a complete example demonstrating how to set up and use TurboMailer:
import { EmailService, EmailServiceConfig } from 'turbomailer';
const config: EmailServiceConfig = {
transporter: {
host: 'smtp.mailtrap.io',
port: 2525,
auth: {
user: 'your_mailtrap_username',
pass: 'your_mailtrap_password',
},
},
concurrency: 3,
retryLimit: 2,
backoffStrategy: 2000,
logLevel: 'info',
redis: {
host: 'localhost',
port: 6379,
},
};
(async () => {
const emailService = new EmailService(config);
const emailOptions = {
from: '[email protected]',
to: '[email protected]',
subject: 'Welcome!',
text: 'Thank you for joining our service.',
};
// Send email immediately
await emailService.sendEmail(emailOptions);
// Queue email with delay
await emailService.queueEmail(emailOptions, { delay: 60000 });
// Listen for completion events
emailService.eventEmitter.on('completed', ({ jobId, emailOptions }) => {
console.log(`Email sent: Job ID ${jobId}`);
});
// Retrieve queue status
const status = await emailService.getQueueStatus();
console.log('Queue Status:', status);
// Close the service when done
await emailService.close();
})();
TurboMailer includes comprehensive unit tests to ensure reliability.
Make sure Redis is running before executing the tests:
npm test