This is a Rust-based notification system that accepts order requests through an API, pushes email jobs into Redis, and lets a worker send real emails asynchronously over SMTP.
- API Server: Accepts order requests, validates input, and creates email jobs
- Redis Queue: Stores email jobs for asynchronous processing
- Worker: Pops email jobs from Redis and sends them through SMTP
- Redis server running locally or accessible
- Rust toolchain installed
REDIS_URL: Redis connection URL (default:redis://127.0.0.1:6379)SMTP_HOST: SMTP server hostname used by the workerSMTP_PORT: SMTP server port used by the workerSMTP_USERNAME: SMTP username for authenticationSMTP_PASSWORD: SMTP password for authenticationSMTP_FROM_EMAIL: Sender email address used by the workerSMTP_FROM_NAME: Optional sender display name
This project loads variables automatically from a root .env file using dotenvy.
- Copy
.env.exampleto.envif needed. - Fill in your SMTP credentials.
- Start the API and worker normally with
cargo run.
-
Start Redis (if not already running):
redis-server
-
Configure
.env:REDIS_URL=redis://127.0.0.1:6379 SMTP_HOST=sandbox.smtp.mailtrap.io SMTP_PORT=587 SMTP_USERNAME=your-smtp-username SMTP_PASSWORD=your-smtp-password SMTP_FROM_EMAIL=orders@example.com SMTP_FROM_NAME=Order Bot
-
Run the API Server:
cargo run -p api
The server will start on
http://127.0.0.1:3000 -
Run the Worker (in a separate terminal):
cargo run -p worker
notification-system/
├── api/ # API server package
│ ├── src/
│ │ ├── lib.rs # Library exports
│ │ ├── main.rs # API server entry point
│ │ ├── handlers/ # HTTP request handlers
│ │ └── queue.rs # Redis queue implementation
│ └── Cargo.toml
├── worker/ # Worker process package
│ ├── src/
│ │ └── main.rs # Worker entry point
│ └── Cargo.toml
├── shared/ # Shared code (if needed)
├── Cargo.toml # Workspace configuration
└── README.md
POST /orders
Content-Type: application/json
{
"user_id": "user123",
"product_id": "product456",
"quantity": 2,
"payment": "COMPLETED",
"email": "customer@example.com"
}GET /health- A client sends
POST /orderswith order details and the recipient email address. - The API validates the request and stores it in the in-memory database.
- The API converts the order into an
EmailJoband pushes it to the Redis queueemail_queue. - The worker blocks on Redis, pops the next email job, and builds an SMTP message.
- The worker sends the email to the client-provided address and logs the result.
The Redis queue implementation provides:
push_email_job(job): Add an email job to the queue
-
Create an order:
curl -X POST http://127.0.0.1:3000/orders \ -H "Content-Type: application/json" \ -d '{ "user_id": "user123", "product_id": "product456", "quantity": 1, "payment": "COMPLETED", "email": "customer@example.com" }'
-
Watch the worker terminal to see the email job being delivered.
The worker currently sends an order confirmation email in this format:
Hello ketu101,
Your order has been created successfully.
Order ID: 853a0135-4bef-438f-923e-0e19dbe3b4cc
Product ID: 245kj452k35j2k3
Quantity: 1
Payment Status: INITIATED
- Put valid SMTP credentials into
.env. - Start Redis with
redis-server. - Run the worker with
cargo run -p worker. - Run the API with
cargo run -p api. - Send a
POST /ordersrequest using a real email address you control. - Confirm two things:
- The worker logs
Email sent - The email arrives in the inbox
- The worker logs
For safe end-to-end testing, Mailtrap is a good first option because it captures real SMTP traffic without sending to external inboxes. Once that works, switch the same .env fields to your real provider credentials and test with an actual recipient address.
# Build API server
cargo build -p api
# Build worker
cargo build -p worker
# Build all packages
cargo build# Test API server
cargo test -p api
# Test worker
cargo test -p worker
# Test the whole workspace
cargo testTo add new types to the queue:
- Ensure the type implements
SerializeandDeserialize - Add appropriate queue methods in
api/src/queue.rs - Update the worker logic in
worker/src/main.rsto handle the new type
You can monitor the queue using Redis CLI:
# Check queue length
redis-cli LLEN email_queue
# View all items in queue
redis-cli LRANGE email_queue 0 -1- Scalability: Worker can be scaled independently from the API
- Reliability: If the worker crashes, the API continues accepting requests
- Resource Isolation: Worker can be resource-intensive without affecting API performance
- Independent Deployment: Worker can be deployed on separate machines
- Add database persistence
- Implement retry logic for failed orders
- Add metrics and monitoring
- Support multiple queue types
- Add order status tracking
- Implement dead letter queue
- Add worker health checks
- Support multiple worker instances
