LogoLaunchSaaS

Email

Configure transactional email providers using split-package architecture

LaunchSaaS provides email support via a split-package design. The core @launchsaas/email package defines the interface and Email service; each provider is a separate package that you install only when needed.

Updated: 2026-03-15

Architecture

@launchsaas/email              ← interface + Email class (always needed)
@launchsaas/email-resend       ← Resend (recommended, works serverless)
@launchsaas/email-nodemailer   ← Nodemailer (SMTP, Node.js only)

You only add the provider package you actually use. This keeps your bundle lean and avoids pulling in SDKs you don't need.

LaunchSaaS ships with @launchsaas/email-resend as the default. In your own app, install whichever provider you prefer — Resend, Nodemailer, or a custom package.

Setting Up Email

1. Install the provider package

In your app directory pick one provider:

# Resend (recommended — works on serverless and edge)
pnpm add @launchsaas/email-resend

# Nodemailer / SMTP (Node.js runtime only)
pnpm add @launchsaas/email-nodemailer

2. Add env variables

Add the provider's keys export to your app's env.ts so the env vars are validated at startup.

// src/env.ts
import { keys as emailKeys } from "@launchsaas/email-resend/keys";

export const env = createEnv({
  extends: [
    // ... other keys
    emailKeys,
  ],
  // ...
});

Then set the variables in your .env:

# Resend
RESEND_API_KEY="re_..."
RESEND_FROM_EMAIL="[email protected]"

# — or — Nodemailer (SMTP)
SMTP_HOST="smtp.example.com"
SMTP_PORT="587"
SMTP_USER="[email protected]"
SMTP_PASS="your-password"
SMTP_FROM_EMAIL="[email protected]"
SMTP_SECURE="false"

3. Register in src/capabilities.ts

Open your app's src/capabilities.ts and configure your chosen provider in the email field:

// src/capabilities.ts  (your app — apps/launchsaas/src/capabilities.ts)

// Option A — Resend (recommended)
import { ResendEmailProvider } from "@launchsaas/email-resend";
// Option B — Nodemailer (SMTP)
// import { NodemailerEmailProvider } from "@launchsaas/email-nodemailer";

export const capabilities = {
  // set to null to disable email
  email: ResendEmailProvider.create(),
  // email: NodemailerEmailProvider.create(),
  // ...other capabilities
};

4. Verify it works

Start your dev server and trigger an email (e.g., sign up to get a verification email). Check the Resend dashboard or your SMTP logs.

Resend: Domain Verification (Production)

To send from your own domain instead of the Resend test address:

  1. Go to Domains in the Resend Dashboard
  2. Click Add Domain and enter your domain (e.g., yourdomain.com)
  3. Add the DNS records Resend provides (MX, TXT/SPF, DKIM) to your DNS provider
  4. Wait for propagation (up to 48 hours) then click Verify
  5. Update your env: RESEND_FROM_EMAIL="[email protected]"

Email Templates

LaunchSaaS renders transactional emails with the shared @launchsaas/email-templates package in packages/design-system/email-templates. The apps/email app is only a React Email preview surface; it reuses the same shared layout instead of owning separate template implementations. The content of each production email is driven by translations in messages/[locale].json under the Email namespace:

TemplateWhen sent
emailVerificationOn user signup
resetPasswordPassword reset flow
magicLinkPasswordless login
paymentCompletedPayment confirmation
welcomePost-verification welcome

Customizing Content

Edit the text in messages/en.json (and messages/zh.json) under the Email key:

{
  "Email": {
    "hello": "Hello, {name}",
    "emailVerification": {
      "title": "Verify your email",
      "heading": "Email Verification",
      "action": "Verify Email",
      "content": "Please click the button below to verify your email address."
    }
  }
}

Previewing Templates

Run the email preview app to see all templates with hot reload:

pnpm run dev:email
# → http://localhost:3003

Preview files live in apps/email/emails/. Each file provides mock data and renders the full email layout so you can iterate without sending real emails.

i18n Support

Templates automatically use the user's saved locale, falling back to the request locale, then en.

Custom Email Provider

To integrate a provider not shipped with LaunchSaaS, create a new email-xxx package:

1. Create the package

mkdir -p packages/capabilities/email-myservice/src

packages/capabilities/email-myservice/package.json:

{
  "name": "@launchsaas/email-myservice",
  "version": "0.1.0",
  "private": true,
  "main": "./src/index.ts",
  "exports": {
    ".": "./src/index.ts"
  },
  "dependencies": {
    "@launchsaas/email": "workspace:*",
    "@launchsaas/errors": "workspace:*",
    "@t3-oss/env-nextjs": "^0.13.10",
    "my-email-sdk": "^1.0.0",
    "zod": "^4.0.0"
  }
}

packages/capabilities/email-myservice/src/keys.ts:

import { createEnv } from "@t3-oss/env-nextjs";
import { z } from "zod";

export const keys = createEnv({
  server: {
    MYSERVICE_API_KEY: z.string().optional(),
    MYSERVICE_FROM_EMAIL: z.string().optional(),
  },
  experimental__runtimeEnv: {},
});

packages/capabilities/email-myservice/src/provider.ts:

import type { EmailProvider, SendEmailOptions } from "@launchsaas/email";

export class MyServiceEmailProvider implements EmailProvider {
  readonly name = "myservice";

  static create(): MyServiceEmailProvider {
    return new MyServiceEmailProvider();
  }

  async send(options: SendEmailOptions): Promise<void> {
    // Call my-email-sdk here
  }
}

packages/capabilities/email-myservice/src/index.ts:

export { MyServiceEmailProvider } from "./provider";
export { keys } from "./keys";

2. Register with pnpm workspace

Add to pnpm-workspace.yaml if it uses a glob that doesn't already cover it (e.g., packages/*).

3. Wire up in your app

pnpm add @launchsaas/email-myservice

Add keys to env.ts and register in your app's src/capabilities.ts:

// src/capabilities.ts  (apps/launchsaas/src/capabilities.ts)
import { MyServiceEmailProvider } from "@launchsaas/email-myservice";

export const capabilities = {
  email: MyServiceEmailProvider.create(),
  // ...other capabilities
};

Disabling Email

To disable email entirely, set email: null in capabilities.ts. Email-dependent features (magic link, email verification) will be skipped automatically.

If you leave email disabled, also set magicLink: false in your features config to avoid confusing users with a sign-in option that silently fails.

Provider Comparison

ProviderPackageRuntimeFree tier
Resend@launchsaas/email-resendAny (HTTP)100/day
Nodemailer@launchsaas/email-nodemailerNode.js onlyDepends on SMTP host
Custom@launchsaas/email-xxxCustom

References

Next Steps