Transactional email
that speaks every language
Design a template once in a visual editor, translate it per locale, and render it from any codebase with one typed SDK call. Your templates, your database, your infrastructure.
- No vendor lock-in
- Runs in your VPC
- MIT licensed
Variables
{{first_name}}string*{{workspace_url}}url*{{trial_days}}numberFallback chain
Serving the published “en” variant.
Welcome to Acme, Sarah
Acme <hello@acme.com> · to sarah@example.com
Your workspace is ready
Hi Sarah,
Your workspace is ready. Invite your team and send your first campaign in under five minutes.
Sent by Acme · You can unsubscribe at any time
Drops into the stack you already run
The problem
Email templates rot in string literals
Transactional email starts as one hardcoded HTML blob and ends as a maintenance problem that nobody owns. Adding a second language usually makes it worse.
Without Local Letter
- Email HTML pasted into template literals across three services
- Every locale is a new
if (locale === "fr")branch - Marketing files a ticket to change one button colour
- A missing variable ships as literal
{{first_name}}to 40,000 inboxes
With Local Letter
- One template key, one visual editor, every locale in one place
- The SDK resolves the locale and falls back automatically
- Non-engineers publish copy changes without a deploy
- Required variables are validated before a single email leaves
Everything in the box
A whole email pipeline,
minus the SaaS bill
Drag-and-drop email editor
A GrapesJS newsletter editor that outputs table-based, inlined HTML every email client can actually render. Designers ship without touching a build.
A locale is a variant, not a fork
Every template holds one variant per locale with its own subject, body and design. Request ja, get ja — or the fallback you configured.
Typed variable schemas
Declare {{first_name}} as a required string and the render call rejects a payload that omits it — before it reaches an inbox.
Draft, publish, roll back
Edit safely in draft, publish when it is right, and snapshot every version so a bad copy change is one click away from undone.
Scoped API keys
One key per project, hashed at rest, shown exactly once. Keys read only their own project, and revoking is instant.
Runs where you run
Docker Compose, your Postgres, your network. No outbound call leaves your perimeter to render a template.
Your secrets stay yours
The SDK talks to your mail provider directly. Local Letter never sees, stores or proxies your provider API key.
How it works
Four steps from blank page
to delivered inbox
Design it once
Build the template in the visual editor, drop in {{variables}}, and declare which ones are required.
Translate per locale
Add a variant for each language. Subject, body and layout can differ — the template key never changes.
Publish
Flip the locale from draft to published. Versions are snapshotted, so rolling back is one click.
Send from anywhere
Your service calls the SDK with a key, a locale and variables. Local Letter renders, your provider delivers.
One key, every language
Switch the locale,
not the code path
Your application always asks for the same template key. Local Letter picks the published variant for the requested locale, and walks your fallback chain when that language has not been translated yet.
Requesting locale “en” returns this published variant directly.
Welcome to Acme, Sarah
Acme <hello@acme.com> · to sarah@example.com
Your workspace is ready
Hi Sarah,
Your workspace is ready. Invite your team and send your first campaign in under five minutes.
Sent by Acme · You can unsubscribe at any time
Response
{
"locale": "en",
"subject": "Welcome to Acme, {{first_name}}",
"html": "<!doctype html>…"
}Built for your codebase
One call.
Any service.
The Node SDK is shipping today: it renders the template against your instance and hands the result to your mail provider. Everything is a plain authenticated HTTP call underneath, so any language can talk to it right now.
Typed errors. Render failures and send failures stay distinguishable.
Locale fallback. Ask for ja, get ja — or the chain you configured.
No mailer lock-in. Render-only mode hands you subject + HTML to send yourself.
SDKs for other languages are coming
Python, Go, Ruby and PHP clients are in progress. Tell us which one you need first and we will prioritise it.
Request a languagepnpm add local-letterimport { TemplateClient } from "local-letter";
const letters = new TemplateClient({
baseUrl: process.env.LOCAL_LETTER_URL,
apiKey: process.env.LOCAL_LETTER_API_KEY,
resendApiKey: process.env.RESEND_API_KEY,
from: "hello@acme.com",
});
// Renders the published "fr" variant, then sends it.
const { id, subject } = await letters.send({
template: "welcome-email",
to: "sarah@example.com",
locale: "fr",
fallbackLocale: "en",
variables: { first_name: "Sarah" },
});Self-hosted by default
The data stays
on your side of the wall
Local Letter is a Docker Compose stack you run yourself: an Express API, a React dashboard and a Postgres database. Self-hosting is free and always will be — Cloud, when it lands, is something you opt into, not something you get moved onto.
Your Postgres
Templates, locales and versions live in a database you already back up and audit.
Your network
Render calls stay inside your VPC. There is no Local Letter cloud to route through.
Your provider keys
The SDK calls Resend directly with your key. Our API never receives or stores it.
Your compliance story
Customer names and addresses never leave the jurisdiction you deployed into.
docker-compose.ymlservices:
api:
image: ghcr.io/local-letter/api:latest
environment:
DATABASE_URL: postgres://letter:pw@db:5432/letter
WEB_ORIGIN: https://letters.acme.internal
ports: ["4000:4000"]
web:
image: ghcr.io/local-letter/web:latest
environment:
VITE_API_URL: https://api.letters.acme.internal
ports: ["5173:5173"]
db:
image: postgres:16
volumes: ["letter-data:/var/lib/postgresql/data"]$ docker compose up -dThe manual is
nearly written
We are finishing the deployment guides, the SDK reference and the API docs. Until they publish, our team will onboard you directly — no waiting on a changelog.
Get onboarded now- Deploying with Docker ComposeDrafting
- Modelling templates and localesDrafting
- Node SDK referenceIn review
- HTTP API referenceIn review
- Variable schemas and validationPlanned
- Versioning and rollbackPlanned
Questions
Before you
deploy it
It can, and it does not have to. The Node SDK will render a template and hand it to Resend in a single call, or return the subject and HTML so you can send it with whatever mailer you already run. Local Letter itself never holds an SMTP connection.
Get started
Let's scope your
email pipeline
Tell us how many locales you send in and where you need it deployed. We will walk your team through the stack and put together a plan that fits.
Free to self-host · MIT licensed · Cloud coming soon