--- status: "published" label: "Email Templates" description: "Create branded email templates with React Email in your Next.js Supabase application. Learn the template architecture, i18n support, and how to build custom templates." title: "Email Templates in the Next.js Supabase SaaS Starter Kit" order: 2 --- MakerKit uses [React Email](https://react.email) to create type-safe, responsive email templates. Templates are stored in the `@kit/email-templates` package and support internationalization out of the box. ## Template Architecture The email templates package is organized as follows: ``` packages/email-templates/ ├── src/ │ ├── components/ # Reusable email components │ │ ├── body-style.tsx │ │ ├── content.tsx │ │ ├── cta-button.tsx │ │ ├── footer.tsx │ │ ├── header.tsx │ │ ├── heading.tsx │ │ └── wrapper.tsx │ ├── emails/ # Email templates │ │ ├── account-delete.email.tsx │ │ ├── invite.email.tsx │ │ └── otp.email.tsx │ ├── lib/ │ │ └── i18n.ts # i18n initialization │ └── locales/ # Translation files │ └── en/ │ ├── account-delete-email.json │ ├── invite-email.json │ └── otp-email.json ``` ## Built-in Templates MakerKit includes three email templates: | Template | Function | Purpose | |----------|----------|---------| | Team Invitation | `renderInviteEmail` | Invite users to join a team | | Account Deletion | `renderAccountDeleteEmail` | Confirm account deletion | | OTP Code | `renderOtpEmail` | Send one-time password codes | ## Using Templates Each template exports an async render function that returns HTML and a subject line: ```tsx import { getMailer } from '@kit/mailers'; import { renderInviteEmail } from '@kit/email-templates'; async function sendInvitation() { const { html, subject } = await renderInviteEmail({ teamName: 'Acme Corp', teamLogo: 'https://example.com/logo.png', // optional inviter: 'John Doe', // can be undefined if inviter is unknown invitedUserEmail: 'jane@example.com', link: 'https://app.example.com/invite/abc123', productName: 'Your App', language: 'en', // optional, defaults to NEXT_PUBLIC_DEFAULT_LOCALE }); const mailer = await getMailer(); await mailer.sendEmail({ to: 'jane@example.com', from: process.env.EMAIL_SENDER!, subject, html, }); } ``` ## Creating Custom Templates To create a new email template: ### 1. Create the Template File Create a new file in `packages/email-templates/src/emails/`: ```tsx {% title="packages/email-templates/src/emails/welcome.email.tsx" %} import { Body, Head, Html, Preview, Tailwind, Text, render, } from '@react-email/components'; import { BodyStyle } from '../components/body-style'; import { EmailContent } from '../components/content'; import { CtaButton } from '../components/cta-button'; import { EmailFooter } from '../components/footer'; import { EmailHeader } from '../components/header'; import { EmailHeading } from '../components/heading'; import { EmailWrapper } from '../components/wrapper'; import { initializeEmailI18n } from '../lib/i18n'; interface Props { userName: string; productName: string; dashboardUrl: string; language?: string; } export async function renderWelcomeEmail(props: Props) { const namespace = 'welcome-email'; const { t } = await initializeEmailI18n({ language: props.language, namespace, }); const previewText = t('previewText', { productName: props.productName, }); const subject = t('subject', { productName: props.productName, }); const html = await render( {previewText} {t('heading', { productName: props.productName })} {t('hello', { userName: props.userName })} {t('mainText')} {t('ctaButton')} {props.productName} , ); return { html, subject, }; } ``` ### 2. Create Translation File Add a translation file in `packages/email-templates/src/locales/en/`: ```json {% title="packages/email-templates/src/locales/en/welcome-email.json" %} { "subject": "Welcome to {productName}", "previewText": "Welcome to {productName} - Let's get started", "heading": "Welcome to {productName}", "hello": "Hi {userName},", "mainText": "Thanks for signing up! We're excited to have you on board. Click the button below to access your dashboard and get started.", "ctaButton": "Go to Dashboard" } ``` ### 3. Export the Template Add the export to the package's index file: ```tsx {% title="packages/email-templates/src/index.ts" %} export { renderInviteEmail } from './emails/invite.email'; export { renderAccountDeleteEmail } from './emails/account-delete.email'; export { renderOtpEmail } from './emails/otp.email'; export { renderWelcomeEmail } from './emails/welcome.email'; // Add this ``` ### 4. Use the Template ```tsx import { getMailer } from '@kit/mailers'; import { renderWelcomeEmail } from '@kit/email-templates'; async function sendWelcome(user: { email: string; name: string }) { const { html, subject } = await renderWelcomeEmail({ userName: user.name, productName: 'Your App', dashboardUrl: 'https://app.example.com/dashboard', }); const mailer = await getMailer(); await mailer.sendEmail({ to: user.email, from: process.env.EMAIL_SENDER!, subject, html, }); } ``` ## Reusable Components MakerKit provides styled components for consistent email design: ### EmailWrapper The outer container with proper styling: ```tsx {/* Email content */} ``` ### EmailHeader and EmailHeading Header section with title: ```tsx Your Email Title ``` ### EmailContent Main content area with white background: ```tsx Your email body text here. ``` ### CtaButton Call-to-action button: ```tsx Click Here ``` ### EmailFooter Footer with product name: ```tsx Your Product Name ``` ## Internationalization Templates support multiple languages through the i18n system. The language is determined by: 1. The `language` prop passed to the render function 2. Falls back to `'en'` if no language specified ### Adding a New Language Create a new locale folder: ``` packages/email-templates/src/locales/es/ ``` Copy and translate the JSON files: ```json {% title="packages/email-templates/src/locales/es/invite-email.json" %} { "subject": "Te han invitado a unirte a {teamName}", "heading": "Únete a {teamName} en {productName}", "hello": "Hola {invitedUserEmail},", "mainText": "{inviter} te ha invitado a unirte al equipo {teamName} en {productName}.", "joinTeam": "Unirse a {teamName}", "copyPasteLink": "O copia y pega este enlace en tu navegador:", "invitationIntendedFor": "Esta invitación fue enviada a {invitedUserEmail}." } ``` Pass the language when rendering: ```tsx const { html, subject } = await renderInviteEmail({ // ... other props language: 'es', }); ``` ## Styling with Tailwind React Email supports Tailwind CSS classes. The `` wrapper enables Tailwind styling: ```tsx Styled text ``` Note that email clients have limited CSS support. Stick to basic styles: - Font sizes and weights - Colors - Padding and margins - Basic flexbox (limited support) Avoid: - CSS Grid - Complex transforms - CSS variables - Advanced selectors ## Testing Templates Please use the Dev Tool to see how emails look like. ## Next Steps - [Send emails](/docs/next-supabase-turbo/sending-emails) using your templates - [Configure Supabase Auth emails](/docs/next-supabase-turbo/authentication-emails) with custom templates - [Test emails locally](/docs/next-supabase-turbo/emails/inbucket) with Mailpit