Node.js
Use the official Lettermint Node.js SDK to send email from a Node.js application. The package provides typed requests and responses for the Sending API and Team API. See Integrations for the capability overview.
This guide covers SDK 3.0. If your project uses 2.x, follow the Node.js SDK 3.0 upgrade guide on GitHub.
Requirements
Before you start you need:
- Node.js 20 or newer. The SDK also runs on Bun, Deno, and edge runtimes such as Cloudflare Workers and Vercel Edge, and it has no dependencies.
- A Lettermint account with a verified sending domain
- A Project API token from your project settings
If your domain is not verified yet, follow the domain setup guide first so your mail reaches the inbox instead of the spam folder.
1. Installation
Install the SDK via your preferred package manager:
2. Send your first email
Create the client with your Project API token as the sendingToken:
Code
The client stores nothing about a message, so create it once and share it across your app, including across concurrent requests. You can also pass the token as a string, as in new Lettermint(token).
Send your first email:
Code
emails.send() takes the message in the API's format, for example reply_to and scheduled_at. The to, cc, and bcc fields are arrays.
The Team API uses a separate Team API token. Pass it as teamToken, alone or next to sendingToken. Each part of the client uses its own token and never falls back to the other. See the Team API quickstart.
3. Email features
The examples in this section use lettermint.emails.compose(), a fluent builder. Every setter returns a new builder and leaves the original unchanged, so one builder is safe to share and reuse. Keep the value that a setter returns when you build an email over several statements:
Code
Each builder example is equivalent to a plain object passed to lettermint.emails.send(). Use whichever reads better.
Basic email
Send a simple text or HTML email:
Code
Multiple recipients
Send to multiple recipients using CC and BCC:
Code
Custom headers and reply-to
Add custom headers and set reply-to addresses:
Code
Metadata
Add metadata for tracking and webhook payloads:
Code
Metadata is included in webhook payloads but not added to the actual email headers. Use it for tracking and analytics purposes.
Tags
Categorize emails for filtering and analytics:
Code
tags() accepts up to 20 name and value pairs. The SDK checks names and values before it sends the request and throws LettermintValidationError if one is invalid. tag() still sets the existing singular tag, which has no deprecation date. See Tags documentation.
Route selection
Direct emails to specific routes within your project:
Code
Idempotency
Pass an idempotency key so a retry never sends the same email twice. If a request with the same key is repeated within the idempotency window, Lettermint returns the original result instead of sending again. The key is an option of the call that sends the email:
Code
emails.send(message, { idempotencyKey }) and emails.sendBatch(messages, { idempotencyKey }) take the same option. The key applies only to that call, and the SDK never retries on its own.
Derive the key from something stable in your domain, such as an order or invoice ID, so the same business event always maps to the same key. See the idempotency documentation for the full behaviour.
File attachments
Attach files to your emails. content is a base64 string, a Uint8Array (including a Node.js Buffer), or an ArrayBuffer. The SDK encodes bytes to base64 for you:
Code
To show an attachment inside the HTML body, set contentId and reference it as cid: in the markup. See Inline images.
Batch sending
Send up to 500 emails in one request. The array can mix plain messages and builders:
Code
4. Send an order confirmation
A real transactional send usually pulls several of these features together. This example sends a receipt with an HTML and plain-text body, tags it for analytics, attaches the order and customer IDs as metadata, and uses an idempotency key so a retry never emails the customer twice:
order-confirmation.ts
The metadata you attach here travels with every webhook event for the message, so a later delivery or bounce maps straight back to the order in your database.
5. Response
Code
6. Handle errors
Every error the SDK throws extends LettermintError. API errors extend ApiError, which carries status, code, and message. Catch the subclasses you want to handle:
Code
The SDK never retries on its own. Reuse the same idempotency key when you retry so the customer gets one email. Other errors include AuthenticationError, PermissionError, NotFoundError, ConflictError, ServerError, ConnectionError, LettermintConfigError for a missing token, and LettermintValidationError when the SDK rejects a request before it sends it.
Track delivery, opens, and bounces
Sending is only half of a transactional setup. To see what happens after a message leaves your app, combine the SDK with Lettermint's platform features:
- Email tracking records opens and clicks, with bot filtering so your metrics stay accurate.
- Webhooks push delivery, bounce, and complaint events to your server in real time, so you can update order records or suppress bad addresses. The SDK verifies each delivery with
new Webhook(secret).verify(rawBody, headers). See Webhook signatures. - Test addresses let you trigger a hard or soft bounce on demand while you build and verify your webhook handler.
Tracking is configured per route, so turn it on for the route your app sends through, then read the results from your dashboard or your webhook endpoint.
FAQ
Does the SDK support TypeScript?
Yes. The SDK is written in TypeScript and exports its request and response types, such as SendMailRequest and SendMailResponse, so every builder method and field is typed and autocompletes in your editor. Query parameters for the Team API are typed objects too, for example { page: { size: 30 } }.
How do I stop the same email being sent twice?
Pass an idempotencyKey option to send() or sendBatch(), derived from a stable ID such as an order number. A repeated request with the same key returns the original result instead of sending again. See the idempotency documentation.
Is Lettermint email GDPR compliant and EU-hosted?
Yes. Lettermint runs exclusively on European infrastructure and processes email in line with GDPR, so transactional mail from your Node app is handled inside the EU.
How do I track opens, clicks, and bounces?
Enable tracking on your route and subscribe to webhooks to receive delivery, open, and bounce events. Use the test addresses to simulate bounces while you build your handler.
Next steps
Tags
Organize and filter emails with tags.
Tracking
Track opens, clicks, and deliverability.
Webhooks
Receive delivery events through webhooks.
SMTP Alternative
Send via SMTP instead of the API.
GitHub Repository
Find the complete source code, report issues, or contribute on GitHub.