This project allows you to send emails in bulk by uploading an Excel sheet containing a column with email addresses. The system will automatically detect the emails, and you can mail all recipients.
npm installnpm run ready
- Then start the project by running the given command in the project directory:
npm startThis project utilizes a custom message queue system built with SOLID principles to handle email sending. The primary components are:
-
Next.js:
- Handles user authentication.
- Allows users to upload an Excel sheet with email addresses.
- Provides a user interface for sending emails.
-
Node.js server:
- Manages the email sending process.
- Uses a custom message queue system for job queueing and processing.
- Uses Nodemailer for sending emails.
-
Custom Message Queue System:
- A message queue system built from scratch following SOLID principles for managing the concurrent processing of email sending jobs.
-
Nodemailer:
- A module for Node.js applications to send emails.
In this project, a custom message queue system replaces BullMQ. The system follows SOLID principles and provides flexibility, scalability, and error handling through the use of Dead-Letter Queues (DLQs). Here’s how it works:
-
MessageQueue Class:
- Manages the queue and processes messages using a configurable concurrency limit.
- Utilizes DLQs for failed message retries, adhering to the Single Responsibility and Dependency Inversion principles.
-
MessageProcessor Interface:
- Defines the
processmethod that each processor (e.g., EmailProcessor) must implement. This ensures that processors follow the Open/Closed Principle, allowing new processors without modifying the base class.
export interface Message { id: number; data: any; delay?: number; } export default abstract class MessageProcessor { abstract process(message: Message): Promise<void>; }
- Defines the
-
EmailProcessor Class:
- A specific implementation of
MessageProcessorthat handles email sending using Nodemailer.
import { sendEmail } from "../utils/sendMail"; import MessageProcessor, { Message } from "./MessageProcessor"; export default class EmailProcessor extends MessageProcessor { async process(message: Message): Promise<void> { return new Promise<void>((resolve, reject) => { setTimeout(() => { sendEmail(message).then(resolve).catch(reject); }, message.delay || 0); }); } }
- A specific implementation of
-
Dead-Letter Queues (DLQs):
- When a message fails to process, it is retried through multiple DLQs, with increasing delay intervals. This ensures robust handling of failures.
private createDLQChain(processor: EmailProcessor, concurrency: number, numberOfDLQs: number): MessageQueue | null { let prevDLQ: MessageQueue | null = null; for (let i = 0; i < numberOfDLQs; i++) { const retryDelay = Math.pow(3, numberOfDLQs - i) * 1000; const curDLQ: MessageQueue = new MessageQueue(processor, concurrency, prevDLQ, retryDelay); prevDLQ = curDLQ; } return prevDLQ; }
The Producer class is responsible for adding messages to the queue.
export default class Producer {
private queue: MessageQueue;
constructor(queue: MessageQueue) {
this.queue = queue;
}
produce(data: any): void {
const message: Message = {
id: Date.now(),
data: data,
delay: 0,
};
this.queue.addMessage(message);
}
}To use the bulk email sender, you need to log in with your credentials. The login method is detailed on the docs page of the website.