Email campaign platform for organisations that send recurring newsletters. Block-based editor, email-safe HTML, delivery through Amazon SES from your own domain.
Website Β· Architecture Β· Report a bug Β· Request a feature
Most newsletter tools either lock your content into their editor or charge per subscriber for delivery you could buy at cost. LetterStack does neither. You design a campaign on a block canvas, it compiles to responsive table-based HTML that survives Outlook and stays under Gmail's clipping threshold, and it sends through your own Amazon SES account from your own verified domain.
Campaigns are stored as JSON, exported as HTML, and sent from infrastructure you control. There is nothing to migrate off.
- Block canvas editor β 14 block types, live preview, undo/redo, autosave
- Email-safe output β tables and inline styles, no clipping at Gmail's 102KB limit
- Send from your own domain β SES domain identities with DKIM, or a shared subdomain
- Gmail as a sender β connect a mailbox via OAuth for small sends
- Batched delivery β QStash fan-out with idempotent workers, retry-safe
- Deliverability built in β automatic suppression on bounce and complaint
- Analytics β delivery, bounce, complaint, open and click via SES event notifications
- Contact import β CSV and XLSX with fuzzy header mapping, validation and dedupe
- Signup forms β embeddable inline, popup and slide-in forms
- Automations β triggered sequences on a flow canvas
- Multi-workspace β organisations, members, invites and per-plan limits
- Next.js β App Router, React 19, TypeScript
- Neon + Drizzle ORM β Postgres
- Amazon SES β delivery and event notifications
- Upstash QStash β queueing and scheduling
- Tailwind CSS + shadcn/ui β interface
- UploadThing β image hosting
- NextAuth β credentials and Google OAuth
A send goes: editor β EmailDocument (JSON) β compiler β frozen HTML snapshot β
QStash fan-out in batches of 50 β workers β one SES call per recipient. Delivery
events return through an SES configuration set to SNS, and from there to a
webhook that writes them to Postgres and suppresses bad addresses.
See docs/architecture.md for why it works this way β idempotency, snapshot freezing, quota reservation, suppression and DMARC alignment.
- Node.js 22+
- A Postgres database (Neon or any Postgres)
- An AWS account with SES access and a verified sending domain
- An Upstash QStash token
git clone https://github.com/krishpinto/Letterstack.git
cd Letterstack
npm install
cp .env.example .env.localFill in .env.local, then:
npm run qstash:dev # local QStash, in a second terminal
npm run devThe app runs at http://localhost:3000. The editor, dashboard and import flow
work against Postgres alone β sending requires SES credentials and a QStash
token, and will tell you what is missing rather than failing quietly.
| Command | Description |
|---|---|
npm run dev |
Start the development server |
npm run build |
Production build |
npm run typecheck |
tsc --noEmit |
npm run lint |
ESLint |
npm run db:push |
Push schema changes with Drizzle |
npm run db:studio |
Open Drizzle Studio |
LetterStack is deployed on Vercel with Neon and Upstash.
Any host that runs Next.js with Node serverless functions works. Point
APP_URL at your deployment so QStash can reach the worker routes, and add your
webhook endpoint as an HTTPS subscriber to the SNS topic behind your SES
configuration set.
Issues and pull requests are welcome. See CONTRIBUTING.md.
Please do not open public issues for security problems. See SECURITY.md for how to report them.
Apache 2.0. "LetterStack" and its logo are trademarks and are not granted by the licence β see section 6 and NOTICE.
If you would rather not run SES, DKIM and a queue yourself, letterstack.site is the hosted version.

