Send your first email
This walks the whole path once: dashboard → template → API key → a send()
call from your own backend. It assumes the stack is
running locally.
You will also need a Resend API key. Local Letter renders the email; Resend delivers it. The key is used by the SDK on your server and is never sent to Local Letter.
Create an account
Open the dashboard at http://localhost:5173 and sign up. Accounts are stored
in your own database — there is no hosted tenant.
Create a project
A project owns templates and API keys. Give it a name; the slug is derived from
it (lowercase, a–z0–9-) and is what URLs use.
{ "name": "Acme", "slug": "acme" }See Projects for how slugs and ownership work.
Add a template
Create a template with a name and a key — the key is what your code will
reference forever, so pick something stable like welcome-email. Keys must
match ^[a-z0-9-]+$ and are unique within a project.
New templates start with a single en locale, marked as the default. Design the
subject and body in the visual editor, using {{token}} placeholders wherever a
value comes from your app:
Subject: Welcome aboard, {{first_name}}
Body: Hi {{first_name}}, thanks for joining {{company}}.In a hurry? The dashboard ships with a template library — fourteen packs of ready-made emails you can import into a project and edit.
Add a translation
Add a locale (say fr) to the same template, optionally copying the English
version so translators start from the built layout rather than a blank canvas.
Same tokens, translated copy:
Subject: Bienvenue, {{first_name}}Details in Locales.
Create an API key
On the project’s API Keys page, create a key and copy it immediately — the raw value is shown once and never again. Afterwards only a prefix and the first few characters are stored for identification.
Put it in your app’s environment:
LOCAL_LETTER_API_KEY="..."
RESEND_API_KEY="..."Send it
Node
npm install local-letterimport { TemplateClient } from 'local-letter'
const letters = new TemplateClient({
baseUrl: 'http://localhost:4000',
apiKey: process.env.LOCAL_LETTER_API_KEY!,
resendApiKey: process.env.RESEND_API_KEY!,
from: 'hello@yourcompany.com',
})
const result = await letters.send({
template: 'welcome-email',
to: 'customer@example.com',
variables: { first_name: 'Sagar', company: 'Acme' },
locale: 'fr',
fallbackLocale: 'en',
})
console.log(result.id, result.locale)What just happened
- The SDK
POSTed to/v1/render/welcome-emailwith your API key, the variables and the locale. - The API found the template in the project that key belongs to, picked the
frlocale, and substituted every{{token}}it had a value for. - The SDK handed the rendered subject and HTML to Resend from your server.
- You got back the Resend message id, plus the locale that actually shipped —
result.locale, which may be your fallback iffrdidn’t exist.
Sending fails?
| Symptom | Usual cause |
|---|---|
401 Invalid API key | Key was revoked, or copied with whitespace around it. |
403 API key is not linked to a project | Key exists but has no project. Create a new one from a project’s API Keys page. |
404 Template not found | The template key doesn’t exist in that key’s project. |
404 No locale available for this template | The template has no locale rows at all. |
| Resend rejects the send | Usually an unverified sender domain — check from. |
Full error semantics per language: Node, Python, Go.
Next
- Working end-to-end apps per language live in
examples/. - How locale fallback resolves
- The render endpoint, without an SDK