One provider for product email and marketing.
Add a subscriber on signup, send the receipt, then send the newsletter — from the same SDK, the same verified domain and the same dashboard. If you are running Resend or Postmark next to a separate newsletter tool, this replaces both.
Typed SDK, REST and SMTP
Transactional lane, separate from campaigns
3,000 emails a month on the free plan
Read lumail.io/integration/install and wire Lumail into this codebase.Your agent reads the integration guide, installs the SDK, finds your signup and transactional call sites, and writes the code. It asks you for the API token rather than inventing one.
The calls you actually need on day one.
Subscribers and transactional email are the same API surface, so a signup handler and a receipt handler share a client. Everything the marketing side reads — tags, events, analytics — is populated by the calls your app already makes.
Create or update a subscriber on signup, with tags and custom fields.
Send a receipt, a magic link or a password reset as Markdown or HTML.
Verify an address before you write it to your database.
Record a custom event so a workflow can pick it up later.
One API token, scoped to one organization.
Server-side integrations authenticate with a Lumail API token from Settings > API Tokens, sent as a bearer header. The SDK, the REST API and the SMTP endpoint all accept the same token.
- 01
Verify a sending domain
Add your domain in Lumail and complete the DNS records. Every from address you use has to belong to a verified domain in the same organization as the token.
- 02
Create an API token
Settings > API Tokens issues a lum_... token bound to that one organization. Put it in your server environment — it is a secret, and it never belongs in client-side code.
- 03
Point the SDK at it
new Lumail({ apiKey }) is the whole setup. The client handles retries and returns typed errors you can branch on.
The token carries the organization, so a leaked token cannot reach another organization in your account — but it can do everything within that one. Keep it server-side, rotate it from Settings > API Tokens, and use a separate token per environment.
What you can drive from your app.
The REST API and the SDK cover the same surface: the audience side your product writes to, and the sending side your product triggers.
Available over the API
Create or update subscribers, with tags, custom fields and country
Add and remove tags, and read a subscriber's full event timeline
Send transactional email as Markdown, HTML or Tiptap content
Verify an address and catch disposable or mistyped domains
Record custom events that trigger workflows
Create, update and send campaigns programmatically
Worth knowing before you build
Sending from an unverified domain
Attachments over the SMTP endpoint
More than one recipient per SMTP message
Reaching another organization with the same token
Transactional messages are queued on a priority lane separate from campaign batches — 40 emails per second each — so a newsletter going out to your whole list cannot delay a magic link. That separation is the main reason to stop running two providers.
Install, token, two calls.
The SDK ships in the same npm package as the CLI. If you are migrating off Resend, the shape of the send call will look familiar, and the SMTP endpoint covers anything that cannot call HTTP.
Let your agent do it
Paste this into the agent working in your codebase. It reads the integration guide at lumail.io/integration/install, installs the SDK, wires the signup and transactional call sites, and tells you which environment variable to set.
Read lumail.io/integration/install and wire Lumail into this codebase.Or write it yourself
Four steps from empty project to a real send. TypeScript types come with the package.
- 01
Install the SDK
The lumail package contains both the typed client and the CLI. Node, Bun and Deno all work.
npm install lumail - 02
Create the client once
Instantiate it in a shared module and import it everywhere. Read the token from the environment — never hardcode it, and never ship it to the browser.
import { Lumail } from "lumail"; export const lumail = new Lumail({ apiKey: process.env.LUMAIL_API_KEY, }); - 03
Add the subscriber on signup
create doubles as an upsert: if the address already exists it updates the record instead of failing. Tags and custom fields are what the marketing side later segments on.
await lumail.subscribers.create({ email: user.email, name: user.name, tags: ["trial"], fields: { plan: "free" }, triggerWorkflows: true, }); - 04
Send the transactional email
The from address must belong to a verified domain in the same organization as the token. transactional: true puts the message on the priority lane and skips marketing tracking defaults.
await lumail.emails.send({ to: user.email, from: "[email protected]", subject: "Welcome aboard", content: "Your account is **ready**.", contentType: "MARKDOWN", transactional: true, });
Connection details
- Package
lumail- Base URL
https://lumail.io/api- Auth
Authorization: Bearer lum_...- SMTP host
smtp.lumail.io:587- Content
MARKDOWN, HTML, TIPTAP- Priority lane
- 40 emails/second
Stuck with an SMTP-only tool?
Supabase Auth, legacy frameworks and most self-hosted apps can only speak SMTP. smtp.lumail.io on port 587 with STARTTLS takes your API token as the password and forwards to the same transactional lane.
Host: smtp.lumail.io
Port: 587 (STARTTLS)
Password: lum_your_api_tokenOne less provider to reconcile.
Running a transactional provider next to a newsletter tool means two domains to warm, two suppression lists and two places to look when an email goes missing. This collapses that into one.
One verified domain for both
Receipts and campaigns leave from the same authenticated domain, so your reputation is built by everything you send instead of split across two providers.
One subscriber record
The signup call your app makes is the same record the marketing side segments, tags and reports on. There is no sync job between two systems to go stale.
Separate queues where it matters
Shared identity, separate throughput: transactional and bulk have their own lanes, so a campaign send cannot sit in front of an OTP.
Frequently asked questions
Can Lumail replace Resend or Postmark?
For transactional email, yes: POST /api/v1/emails and lumail.emails.send cover Markdown, HTML and Tiptap content, with a priority queue lane at 40 emails per second and an SMTP endpoint for tools that cannot call HTTP. The difference is that the same account also runs your campaigns and holds your subscriber list.
How do I authenticate from my server?
Create an API token in Settings > API Tokens and pass it to new Lumail({ apiKey }) or as an Authorization: Bearer header. The token is bound to one organization and belongs in your server environment, never in client-side code.
Do I need to verify a domain?
Yes. Every from address must belong to a domain verified in the same organization as the token. Add the domain in Lumail, complete the DNS records, and the address becomes usable for both transactional email and campaigns.
Will a big campaign delay my password reset emails?
No. Transactional messages are queued on a priority lane with its own capacity, separate from the bulk lane campaigns use. Both run at 40 emails per second and neither blocks the other.
What about Supabase Auth or another SMTP-only tool?
Point it at smtp.lumail.io on port 587 with STARTTLS, using any non-empty username and your API token as the password. It is a thin adapter over the same HTTP endpoint. One recipient per message, no attachments, 1 MB limit.
Is there a REST API if I am not on TypeScript?
Yes. Every SDK method maps to a documented REST endpoint under https://lumail.io/api, authenticated with the same bearer token. The SDK is a convenience, not a requirement.
What does it cost to start?
The free plan includes 3,000 emails a month with full API access, which covers most products' transactional volume while you are getting started.
Put your product email and your newsletter in one place.
Install the SDK, create a token, and send your first transactional email today. Your campaigns can move over whenever you are ready.
Read lumail.io/integration/install and wire Lumail into this codebase.