I'm trying to build a tool like SendGrid (jk) ;<
yet I'm trying to break it into manageable parts, ignoring all practices.
too lazy to write a commit message too motivated to write in readme: For now ...
A custom email sending service inspired by SendGrid, built with Node.js. This project handles email queuing, scheduling, templating, and delivery, with a focus on reliability and scalability.
- server.js
Bootstrap file that initializes the Express server, worker manager, and Agenda scheduler. - app.js
Express application that defines API routes.
- config/mongodb.js: MongoDB connection setup.
- config/queue.js: Redis configuration for the Bull queue.
- config/smtp.js: SMTP server settings for email delivery.
- services/emailService.js: Core email sending functionality using Nodemailer.
- services/templateService.js: Renders email templates with EJS.
- views/email-templates/: Directory containing EJS templates (e.g.,
welcome.ejs).
- queues/emailQueue.js: Implementation of Bull queue for email jobs.
- queues/agendaSetup.js: Agenda scheduler for recurring and scheduled email tasks.
- jobs/emailJob.js: Processor for email sending jobs.
- workers/emailWorker.js: Worker thread that processes email jobs.
- workers/workerManager.js: Manages dynamic scaling of worker threads based on queue load.
- controllers/emailController.js: Handles immediate email sending requests.
- controllers/scheduledEmailController.js: Manages scheduled and recurring email requests.
- Queue-based Processing:
Uses Bull (Redis-based queue) for asynchronous email sending. - Scalable Architecture:
Dynamic worker scaling based on queue size. - Email Templates:
EJS-based system for customizable email designs. - Scheduled Emails:
Supports one-time and recurring emails using Agenda. - Graceful Shutdown:
Properly terminates workers and connections. - Error Handling:
Implements retry mechanisms for failed email delivery.
- Database:
MongoDB for managing scheduled jobs. - Queue:
Redis for handling the email sending queue. - Email Transport:
For now : Nodemailer configured with SMTP settings. - Concurrency Control:
Worker threads ensure parallel processing. - Auto-scaling:
Adjusts worker count based on the queue load. - Templates:
Dynamic rendering using EJS for email content.
┌─────────────┐ ┌─────────────┐ ┌───────────────┐
│ Express API │────▶│ Bull Queue │────▶│ Worker Threads│
└─────────────┘ └─────────────┘ └───────────────┘
│ │ │
│ │ │
▼ ▼ ▼
┌─────────────┐ ┌─────────────┐ ┌───────────────┐
│ MongoDB │ │ Redis │ │ SMTP Server │
└─────────────┘ └─────────────┘ └───────────────┘
▲
│
┌─────────────┐
│ Agenda │
│ Scheduler │
└─────────────┘
- Evaluate alternatives to Nodemailer, such as smtp-client, emailJs, or even implementing raw SMTP support.
- Introduce middleware components to improve request handling, security, and error processing.
make sure you have :
-
Node.js (v16 or higher)
-
MongoDB (running locally or accessible) refer to docs ps: Ctrl + click to open in another tab
-
Redis (running locally or accessible) refer to docs ps: Ctrl + click to open in another tab
- Clone the repository:
git clone https://github.com/Ayman-aa/noBrainerSendGrid.git
cd noBrainerSendGrid- Install dependencies:
npm install- Set up environment variables:
cp .example.env .env- Edit the .env file with your SMTP, Redis, and MongoDB configurations:
# SMTP Configuration (e.g., Gmail)
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_USER=your_email
SMTP_PASS=your_password # Use an "App Password" if using Gmail
SMTP_SECURE=false # true for port 465, false for 587
DEFAULT_FROM="No Reply <email@example.com>"
# Redis (required for Bull queue)
REDIS_HOST=127.0.0.1
REDIS_PORT=6379
# REDIS_PASSWORD=yourpassword (if applicable)
# MongoDB (required for Agenda scheduler)
MONGODB_URI=mongodb://localhost:27017/emailService #leave this as it is
# Server
PORT=3000
Start the server:
npm startFor development with auto-restart:
npm run devSending an Email
curl -X POST http://localhost:3000/api/email/send \
-H "Content-Type: application/json" \
-d '{
"to": "recipient@example.com",
"subject": "Hello from noBrainerSendGrid",
"body": "<h1>Hello!</h1><p>This is a test email.</p>"
}'Using a Template
curl -X POST http://localhost:3000/api/email/send \
-H "Content-Type: application/json" \
-d '{
"to": "recipient@example.com",
"subject": "Welcome to Our Service",
"templateId": "welcome",
"templateData": {
"name": "John Doe",
"docsUrl": "https://example.com/docs"
}
}'Scheduling an Email
curl -X POST http://localhost:3000/api/email/schedule \
-H "Content-Type: application/json" \
-d '{
"to": "recipient@example.com",
"subject": "Reminder",
"body": "<p>Don't forget your appointment!</p>",
"scheduledTime": "2023-12-25T10:00:00.000Z"
}'Note: This is a custom implementation of an email delivery system and is not affiliated with SendGrid.