A high-concurrency microservice built with Go and gRPC to handle email delivery and OTP management.
go_server/: The core gRPC server (Go).node_client/: A TypeScript client for functional and performance testing.
- The Problem: Standard
net/smtpis slow because it creates a new connection (TCP handshake + TLS + Auth) for every single email sent. - Our Solution: Implements a Worker Pool with Persistent Connections. Workers pre-dial and stay authenticated, allowing emails to be dispatched instantly with zero handshake latency.
- Zero-Latency Sending: Persistent SMTP connections eliminate handshake overhead.
- Concurrency: Configurable worker pool (default: 5) handles multiple clients simultaneously without blocking.
- Thread-Safe OTP: In-memory storage protected by
sync.RWMutexwith atomic validation logic to prevent race conditions. - Auto-Cleanup: Background "Janitor" worker removes expired OTPs to prevent memory leaks.
- Graceful Shutdown: Completes active jobs before closing connections on
SIGINTorSIGTERM.
Create a .env file inside the go_server/ directory:
PORT=40700
WORKERS=5 # Concurrent SMTP connections
OTP_CLEANUP_SECONDS=180 # Expiry check interval
OTP_LIFESPAN_SECONDS=120 # Duration before OTP expires
# SMTP Settings (e.g., Gmail)
EMAIL_HOST=smtp.gmail.com
EMAIL_PORT=465
EMAIL=your_email@gmail.com
APP_PASSWORD=xxxx-xxxx-xxxx-xxxx
# For test in node_client
TARGET=example@gmail.comRecommended for Testing: Use these values to ensure the Node.js client tests (which check for expiration) finish quickly without long waits.
# Test Settings (Short durations to speed up client tests)
OTP_CLEANUP_SECONDS=15 # Run cleanup every 15s
OTP_LIFESPAN_SECONDS=5 # OTP expires after 5scd go_server
go mod tidy
make generate # Re-generates Protobuf codego run main.goThe client performs functional tests (OTP flow, Email sending) and benchmarks performance.
⚠️ Important: The client relies on Protocol Buffers code generated by the server. You must run the server generation step first.
cd node_client
npm installnpm start| Method | Inputs | Description |
|---|---|---|
SendCode |
email |
Generates a 6-digit code, stores it in memory, and dispatches an email via the worker pool. |
ValidateCode |
email, otp |
Thread-safe validation. Automatically deletes the code upon success to prevent replay attacks. |
| Method | Inputs | Description |
|---|---|---|
SendMail |
to, subject, body |
Asynchronously queues a raw email to be processed by the next available worker. |
Here is the average response time per request based on the worker pool size:
1 Worker: ~1700ms (High Latency)
2 Workers: ~800ms
3 Workers: ~700ms
≥ 4 Workers: ~500ms - 700ms (Saturation Point)
4 Workers is the optimal configuration.
The data shows that performance improves significantly up to 4 workers but plateaus afterwards. Beyond this point, the bottleneck shifts from our application to the external Gmail SMTP server. Since the upstream provider handles requests sequentially or enforces rate limits, adding more workers (5-10) adds system overhead without reducing the average wait time.