Search

Search Kavel...

Documentation menu

Email

Transactional email via Resend, with typed React templates and a durable send queue.

What you get

  • sendEmail: render a template and send it immediately
  • enqueueEmail + flushEmailQueue, store emails in D1 and send them from a scheduled Worker, with per-row retries so one bad recipient can't fail a batch
  • React email templates in packages/transactional, previewable during development

Sending mail

ts
import { sendEmail } from "@/lib/email";
import { WelcomeEmail } from "@my-app/transactional/emails/welcome";

await sendEmail(env, {
  to: user.email,
  subject: "Welcome aboard",
  react: WelcomeEmail({ name: user.name }),
});

The queue

For anything non-urgent, enqueue instead of sending inline. Rendering happens at enqueue time, so the queue only holds finished HTML. A cron-triggered flushEmailQueue drains it in batches, marking each row sent or recording the error and incrementing its attempt count.

Note

Without RESEND_API_KEY, both sendEmail and the queue flush log a warning and skip sending. This keeps flows like auth verification working locally before you've set up email.

Setup

bash
# in apps/api/.dev.vars
RESEND_API_KEY=re_...
EMAIL_FROM="My App <noreply@myapp.com>"

Preview templates while developing:

bash
cd packages/transactional && bun preview