Email

Transactional emails via Resend with React Email templates. All outbound email goes through centralized helpers.


Key files

  • lib/email.ts - Email sending helpers
  • emails/WelcomeEmail.tsx - New user welcome
  • emails/MagicLinkSignInEmail.tsx - Magic link sign-in
  • emails/SubscriptionCreatedEmail.tsx - Subscription confirmation

Environment variables

RESEND_API_KEY=re_xxx
EMAIL_FROM_ADDRESS=noreply@yourdomain.com
EMAIL_FROM_NAME=My App

Sending emails

Always use the helpers in lib/email.ts:

import { sendWelcomeEmail } from "@/lib/email";

await sendWelcomeEmail({
  user: { email: "user@example.com", name: "John" },
});

Never import Resend directly in pages, routes, or components.


Creating a new template

Use the /add-email-template Cursor command, or manually:

  1. Create template in emails/<Name>Email.tsx:
export type WelcomeEmailProps = {
  userName: string;
  appName: string;
};

export function WelcomeEmail({ userName, appName }: WelcomeEmailProps) {
  return (
    <Html>
      <Body>
        <Text>Welcome to {appName}, {userName}!</Text>
      </Body>
    </Html>
  );
}
  1. Add helper in lib/email.ts:
export async function sendWelcomeEmail(args: {
  user: EmailRecipient;
}): Promise<{ success: boolean }> {
  return sendEmail({
    to: args.user,
    subject: "Welcome!",
    react: WelcomeEmail({ userName: args.user.name, appName: siteConfig.name }),
  });
}

Event-driven emails

Trigger emails from central flows, not random UI components:

  • New user created - Welcome email in lib/auth.ts createUser event
  • Subscription activated - Confirmation in webhook handlers
  • Magic link requested - Sign-in link in magic link API route

Error handling

Email functions return { success: boolean } and don't throw. Failures are logged but don't crash the request.

const result = await sendWelcomeEmail({ user });
if (!result.success) {
  // Handle failure (optional)
}

Production setup

  1. Verify your sending domain in Resend
  2. Update EMAIL_FROM_ADDRESS to use your domain
  3. Test emails in Resend dashboard