Stentor

Email delivery platform

GoNATS JetStreamPostgreSQLNext.js 16PythonKubernetes

Stentor is a self-hostable, multi-tenant email delivery platform. It exposes a REST API —including a SendGrid-compatible /v3/mail/send endpoint, so migrating does not force a client rewrite—, an authenticated SMTP submission gateway and an asynchronous worker that dispatches mail across several providers with failover and circuit breaking. On top of that sit a dashboard for campaigns, contacts and analytics, and a scoring service that decides when to send and how a subject line rates. Tenant isolation is not coded into the application: it is enforced in PostgreSQL with row-level security, and every service connects as a least-privilege role.

What it does

It covers the full path of transactional and campaign mail, from the moment it arrives over the API or SMTP until the provider confirms delivery.

  • Accepts submissions over a REST API with a SendGrid-compatible endpoint and over authenticated SMTP on 587 with STARTTLS and 465 with implicit TLS.
  • Dispatches each send across several providers, with retries, failover and circuit breaking when one degrades.
  • Consumes send jobs from a durable queue and emits outbound webhooks with the result.
  • Receives inbound provider webhooks to close the status loop for every message.
  • Manages campaigns, contacts and analytics from its own dashboard.
  • Scores send time and subject lines through a separate machine-learning service.

Architecture

Three toolchains share one repository, each where it pays off, and the tenant boundary lives in the database rather than in application code.

  • A Go workspace with four modules: API, worker, SMTP gateway and a shared package holding delivery logic, providers, queue, DNS and circuit breakers.
  • Multi-tenant isolation through PostgreSQL row-level security: the guarantee does not depend on no query ever forgetting the filter.
  • Every service connects to the database as its own least-privilege role.
  • NATS JetStream as the durable queue between API and worker.
  • A Next.js 16 dashboard with React 19 and TanStack Query in an npm workspace driven by turbo.
  • A Python scoring service on FastAPI, kept off the critical delivery path.
  • Deployment with Kubernetes manifests, Helm charts and monitoring versioned in the repository.

Stack

The delivery services are written in Go, the queue is NATS JetStream and persistence is PostgreSQL with row-level security. The dashboard is Next.js 16 with React 19 and TypeScript, and the scoring service is Python on FastAPI. Everything is packaged in Docker and deployed to Kubernetes with Helm.

Back to projects