Sendbay — Self-Hosted Email Infrastructure
Re-architected the entire send engine of a SendGrid-class email platform on Apache Kafka — per-provider rate limiting across 4 provider types, full delivery, and a zero-downtime production cutover.
- Stack
- Kafka · Node.js · TypeScript · BullMQ · PostgreSQL · Redis · Docker
- Links
- Live
The challenge
Sendbay is an email service provider in the class of SendGrid — with one radical difference: the customer owns the infrastructure. One Docker command, a license key, and unlimited sending with zero per-email pricing. Customers plug in their own providers — Amazon SES, SendGrid, Mailgun, or any SMTP server — and Sendbay runs templates, timezone-aware scheduling, teams, and real-time analytics on top.
Sending one email is trivial. Sending an entire campaign through four different providers, each enforcing its own rate limits, each capable of throttling or failing at any moment — without losing a single message and without the platform buckling — is a genuine distributed-systems problem. That was the problem I owned.
What I engineered
I designed and built a Kafka-driven send engine from the ground up, replacing the direct request-to-provider path with an event-streaming backbone built to absorb any load thrown at it.
- Apache Kafka as the backbone. Every email becomes a durable event on a Kafka topic. The API accepts instantly; consumer groups drain the stream at exactly the rate each provider can sustain. Spikes are absorbed by the log, not by the providers — a campaign of any size becomes a steady, controlled flow.
- Self-managed, per-provider rate limiting. I built rate-limit handling into the consumers themselves — each provider gets its own independently governed throughput. When a provider pushes back, consumers back off intelligently instead of hammering it into a harder throttle.
- Engineered for full delivery. A message is only marked complete once the provider accepts it. Failures are retried with discipline, never silently dropped — the system is built to deliver every accepted email.
- Zero-downtime migration. The new engine replaced the legacy send path live in production, without a single minute of sending downtime.
- One reliable path for everything. Scheduled campaigns, bulk sends, and transactional mail all flow through the same hardened pipeline, with BullMQ orchestrating scheduled and background jobs.
Architecture
API → PostgreSQL → Kafka → provider-specific consumers → SES / SendGrid / Mailgun / SMTP, with delivery events — opens, clicks, bounces, unsubscribes — streaming back asynchronously into analytics. Redis holds hot counters and live rate-limit state; BullMQ drives scheduling and background processing; everything ships in Docker.
Three architectural decisions carry the system:
- Rate limits are enforced per provider, never globally — one slow provider can never stall the others.
- The Kafka log is the source of truth for what still needs to be sent — a crashed consumer loses nothing; it simply resumes from its offset.
- Delivery status is written back asynchronously — the send path never waits on analytics.
Technical leadership
Beyond the engine, I led the backend team on Sendbay's self-hosted infrastructure and license-based system — the capability that turns the product into a single Docker deployment that validates its license before it runs. I owned the backend design, broke the work down across the team, and drove it through review to release.
Impact
- A send engine that scales with the log, not with the load
- Full delivery of accepted email across every connected provider
- Zero downtime through the entire cutover
- The self-hosted, licensed product shipped under my backend leadership
What I took from it
A queue alone doesn't make a system reliable. What made the difference was treating every provider as its own rate-limited, independently failing downstream — and designing the failure path before the happy path. That's the discipline behind a backend that doesn't fall over.