Emails

Send emails with React Email and a provider-agnostic email worker. Easily switch between Resend, SES, Mailgun, SparkPost, or custom SMTP.

Nuxflare Pro ships with a robust email system that works on Cloudflare Workers.

Note from Tanay: Under the hood, this email system uses a port of the AdonisJS Mailer that I adapted to work on Cloudflare Workers. It's called @tanayvk/mailer. While I haven't tested all the advanced features yet, you can check out the AdonisJS Mailer docs for more details. If you run into any issues or have feature requests, please let me know!

Architecture

  • Email Templates (packages/emails) - Type-safe email templates using React Email
  • Email Worker (packages/functions/src/emails.ts) - Cloudflare Worker that handles provider-agnostic email sending
  • Infrastructure (infra/emails.ts) - Infrastructure configuration for the Cloudflare Worker

Email Templates

Nuxflare Welcome Email Template Screenshot

Templates are built using React Email and Tailwind (optional). For example:

packages/emails/emails/Welcome.tsx
import { Body, Container, Html, Text } from "@react-email/components";

export const WelcomeEmail = ({ username }: { username: string }) => (
  <Html>
    <Body>
      <Tailwind>
        <Container class="p-4 border border-solid border-[#eaeaea] rounded my-[40px] mx-auto max-w-[465px]">
          <Text>Welcome {username}!</Text>
        </Container>
      </Tailwind>
    </Body>
  </Html>
);

Provider Configuration

Email providers are configured in config.ts and the emails worker packages/functions/src/emails.ts:

config.ts
// ...
export const authEmail = {
  name: "Tanay Karnik",
  address: "auth@pro.nuxflare.com",
};
export const authEmailDomain = "pro.nuxflare.com";
export const flags: {
  // ...
  resend?: boolean;
  mailgun?: boolean;
  ses?: boolean;
  sparkPost?: boolean;
  smtp?: boolean;
  // ...
} = {
  // ...
  resend: true,
  mailgun: true,
};
packages/functions/src/emails.ts
const config: Parameters<typeof generateMailer>[0] = {
  default: "resend",
  // NOTE: you can also set defaults here
  // from: {
  //   address: "example@domain.com",
  //   name: "Tanay Karnik",
  // },
  // replyTo: {
  //   address: "example@domain.com",
  //   name: "Tanay Karnik",
  // },
  mailers: {
    ...(flags.resend && {
      resend: () =>
        new ResendTransport({
          key: Resource.ResendApiKey.value || "",
          baseUrl: "https://api.resend.com",
        }),
    }),
    ...(flags.mailgun && {
      mailgun: () =>
        new MailgunTransport({
          key: Resource.MailgunApiKey.value || "",
          domain: authEmailDomain,
          baseUrl: "https://api.mailgun.net/v3",
        }),
    }),
  },
};

Setting Up Secrets

Secrets for email providers are managed using SST.

# Resend
bun sst secrets set ResendApiKey sk_123...
# Mailgun
bun sst secrets set MailgunApiKey key-123...

Sending Emails

Use the sendEmail function to send emails:

async ({ ctx: { user, origin, authorize, sendEmail }, input }) => {
  // ...
  // pass the from email, to email, template name and template props to send emails
  await sendEmail(authEmail, invite.email, "Invitation", {
    teamName: team.name,
    invitedBy: user.name,
    inviteLink,
  });
  // ...
};

Emails worker can be used from any package:

import { sender } from "@nuxflare-pro/functions/sender";
const sendEmail = sender(event.context?.cloudflare?.env?.Emails); // pass the Emails binding