Nitrofy LogoNitrofy
Como funcionaBeneficiosIntegracoesPlanosDuvidas
Comece agora
Nitrofy Logo
Comecar
Introduction
QuickstartEnvironment SetupRunning LocallyFirst Deploy
Organizations & TenancyAuthentication & SessionsRoles & PermissionsControllers & ProceduresJobs & QueuesPlugin ManagerContent LayerBuilt-in MCP ServerBillingNotificationsFile StorageEmailWebhooksAPI KeysSEOData FetchingDesign System
Development

Email

Transactional email system with React Email templates, multiple adapters, and real-time preview.

By the end of this guide, you'll have set up a comprehensive transactional email system with React Email templates, multiple provider adapters, and real-time preview capabilities for reliable email delivery in your SaaS application.

Overview

The SaaS Boilerplate includes a robust email system built on React Email that supports multiple delivery providers, template-based rendering, and real-time preview development. Key features include:

  • Multi-provider support: SMTP, Resend, and other email providers via adapters
  • React Email templates: Beautiful, responsive email templates with Tailwind CSS
  • Type-safe templates: Zod schemas ensure data validation and type safety
  • Real-time preview: Live email preview during development with npm run dev:email
  • Notification integration: Seamless integration with the notification system for multi-channel delivery
  • Template registry: Centralized template management with automatic rendering
  • Error handling: Comprehensive error tracking and retry mechanisms
  • Development tools: Hot-reload preview and template development workflow

The system integrates deeply with the notification service, allowing you to send emails as part of broader notification workflows while maintaining separation of concerns.

Architecture

Mail Provider System

The email system is built around the MailProvider class, which orchestrates template rendering, adapter selection, and delivery:

// src/@saas-boilerplate/providers/mail/mail.provider.tsx
const mailProvider = MailProvider.initialize({
  secret: AppConfig.providers.mail.secret,
  from: AppConfig.providers.mail.from,
  adapter: getAdapter(AppConfig.providers.mail.provider),
  templates: {
    welcome: welcomeEmailTemplate,
    'organization-invite': organizationInviteTemplate,
    // ... more templates
  }
})

Email Adapters

The system supports multiple email providers through adapter pattern:

SMTP Adapter (for development/local):

// src/@saas-boilerplate/providers/mail/adapters/smtp.adapter.ts
export const smtpAdapter = MailProvider.adapter((options) => ({
  send: async ({ to, subject, html, text }) => {
    const transport = nodemailer.createTransporter(options.secret)
    await transport.sendMail({ from: options.from, to, subject, html, text })
  }
}))

Resend Adapter (for production):

// src/@saas-boilerplate/providers/mail/adapters/resend.adapter.ts
export const resendAdapter = MailProvider.adapter((options) => ({
  send: async ({ to, subject, html, text, scheduledAt }) => {
    const resend = new Resend(options.secret)
    await resend.emails.create({
      from: options.from,
      to,
      subject,
      html,
      text,
      scheduled_at: scheduledAt?.toISOString()
    })
  }
}))

Template System

Templates are defined with Zod schemas and React components:

// Template definition with schema and component
export const welcomeEmailTemplate = MailProvider.template({
  subject: `Welcome to ${AppConfig.name}`,
  schema: z.object({
    name: z.string().nullable().optional(),
    email: z.string().email()
  }),
  render: WelcomeEmailComponent
})

Notification Integration

The notification service integrates email delivery as a channel:

// src/services/notification.ts
channels: {
  'email': {
    send: async ({ data, template, context }) => {
      // Find recipients and send emails using mail service
      const recipients = await findRecipients(context)
      await Promise.all(recipients.map(recipient => 
        mail.send({
          template: 'notification',
          to: recipient.email,
          data: { /* notification data */ }
        })
      ))
    }
  }
}

Setting Up Email

Configure Email Provider

Set up your email provider in the configuration. For development, use SMTP with MailHog:

// src/config/boilerplate.config.server.ts
export const AppConfig = {
  providers: {
    mail: {
      provider: 'smtp',
      secret: 'smtp://localhost:1025',
      from: 'noreply@yourapp.com'
    }
  }
}

For production, use Resend or another provider:

export const AppConfig = {
  providers: {
    mail: {
      provider: 'resend',
      secret: process.env.RESEND_API_KEY,
      from: 'noreply@yourapp.com'
    }
  }
}

Start MailHog for Development

For local development, run MailHog to capture emails:

# Using Docker (recommended)
docker run -d -p 1025:1025 -p 8025:8025 mailhog/mailhog

# Or using the provided script
npm run docker:up

Access the MailHog web interface at http://localhost:8025 to view sent emails.

Create Email Templates

Create new email templates in src/content/mails/:

// src/content/mails/custom-email.template.ts
import { z } from 'zod'
import { MailProvider } from '@/@saas-boilerplate/providers/mail'
import { CustomEmailComponent } from './custom-email.component'

export const customEmailTemplate = MailProvider.template({
  subject: 'Custom Email Subject',
  schema: z.object({
    userName: z.string(),
    actionUrl: z.string().url()
  }),
  render: CustomEmailComponent
})

Add the template to the mail service registry:

// src/services/mail.ts
export const mail = MailProvider.initialize({
  // ... other config
  templates: {
    // ... existing templates
    custom: customEmailTemplate
  }
})

Preview Templates in Development

Start the email preview server to see templates in real-time:

npm run dev:email

This starts a development server at http://localhost:3001 where you can preview and test email templates with different data.

Backend Usage (Procedures & Controllers)

Sending Emails Directly

Use the mail service directly in your procedures and controllers:

// In a controller or procedure
import { mail } from '@/services/mail'

export const sendWelcomeEmail = igniter.mutation({
  use: [AuthFeatureProcedure()],
  handler: async ({ context, request }) => {
    const session = await context.auth.getSession({
      requirements: 'authenticated'
    })

    // Send welcome email
    await mail.send({
      template: 'welcome',
      to: session.user.email,
      data: {
        name: session.user.name,
        email: session.user.email
      }
    })

    return response.success({ sent: true })
  }
})

Integration with Notifications (Recommended)

For better control and flexibility, integrate emails through the notification system:

// In procedures/controllers - use notification service instead
import { notification } from '@/services/notification'

export const userRegistered = igniter.procedure({
  handler: async ({ context }) => {
    // Send welcome notification (includes email + in-app)
    await notification.send({
      type: 'USER_REGISTERED',
      context: {
        recipientId: userId
      },
      data: {
        userName: user.name,
        welcomeUrl: '/app/dashboard'
      }
    })
  }
})

Template Data Validation

Templates validate data using Zod schemas:

// This will throw if data doesn't match schema
await mail.send({
  template: 'welcome',
  to: 'user@example.com',
  data: {
    name: 'John Doe', // ✅ Valid
    email: 'john@example.com', // ✅ Valid
    invalidField: 'not allowed' // ❌ Would cause validation error
  }
})

Frontend Usage (Client-side)

Email Preview Development

The email preview system allows you to develop templates interactively:

# Start preview server
npm run dev:email

# Visit http://localhost:3001 to see:
# - List of all email templates
# - Live preview with sample data
# - Hot-reload when templates change
# - Test different data scenarios

Template Development Workflow

Develop email templates with React components:

// src/content/mails/custom-email.component.tsx
import * as ReactEmail from '@react-email/components'

export interface CustomEmailProps {
  userName: string
  actionUrl: string
}

export function CustomEmailComponent({ userName, actionUrl }: CustomEmailProps) {
  return (
    <ReactEmail.Html>
      <ReactEmail.Body>
        <ReactEmail.Text>Hello {userName}!</ReactEmail.Text>
        <ReactEmail.Link href={actionUrl}>Click here</ReactEmail.Link>
      </ReactEmail.Body>
    </ReactEmail.Html>
  )
}

Email Templates

Available Templates

Prop

Type

Creating Custom Templates

Create new templates following the established pattern:

// 1. Define the React component
export function CustomTemplate({ data }: CustomTemplateProps) {
  return (
    <ReactEmail.Html>
      {/* Your email HTML */}
    </ReactEmail.Html>
  )
}

// 2. Define the template with schema
export const customTemplate = MailProvider.template({
  subject: 'Custom Subject',
  schema: z.object({
    requiredField: z.string(),
    optionalField: z.string().optional()
  }),
  render: CustomTemplate
})

// 3. Register in mail service
templates: {
  custom: customTemplate
}

Practical Examples

Backend: User Registration Flow

Send welcome email when user registers:

// In user registration procedure
export const registerUser = igniter.procedure({
  handler: async ({ context, request }) => {
    const user = await createUser(request.body)
    
    // Send welcome email via notification system
    await notification.send({
      type: 'USER_REGISTERED',
      context: { recipientId: user.id },
      data: {
        userName: user.name,
        email: user.email,
        dashboardUrl: '/app/dashboard'
      }
    })
    
    return response.created(user)
  }
})

Backend: Organization Invitation

Send invitation emails to new members:

// In organization invite procedure
export const inviteMember = igniter.procedure({
  handler: async ({ context, request }) => {
    const invitation = await createInvitation(request.body)
    
    // Send invitation via direct mail (for one-off emails)
    await mail.send({
      template: 'organization-invite',
      to: invitation.email,
      data: {
        organizationName: invitation.organization.name,
        inviterName: session.user.name,
        role: invitation.role,
        inviteUrl: `/invite/${invitation.token}`
      }
    })
    
    return response.success(invitation)
  }
})

Backend: Billing Notifications

Send billing-related emails through notifications:

// In billing webhook handler
export const handlePaymentSuccess = igniter.procedure({
  handler: async ({ context, request }) => {
    const payment = await processPayment(request.body)
    
    await notification.send({
      type: 'BILLING_SUCCESS',
      context: { recipientId: payment.userId },
      data: {
        amount: payment.amount,
        currency: payment.currency,
        planName: payment.planName
      }
    })
  }
})

Email Data Structure

MailProviderSendParams

Prop

Type

Template Schema

Prop

Type

Troubleshooting

Best Practices

See Also

  • Notifications - Multi-channel notification system that integrates with email
  • Authentication & Sessions - User sessions and email verification flows
  • Organizations and Tenancy - Organization-scoped email delivery
  • Jobs & Queues - Background processing for bulk email operations
  • Content Layer - MDX content system used for email templates

API Reference

Mail Service Methods

Prop

Type

Email Provider Configuration

Prop

Type

Development Commands

Prop

Type

File Storage

S3-compatible file storage system with secure uploads, context-based organization, and real-time progress tracking.

Webhooks

Subscribe to events and handle incoming webhooks securely.

On this page

OverviewArchitectureMail Provider SystemEmail AdaptersTemplate SystemNotification IntegrationSetting Up EmailConfigure Email ProviderStart MailHog for DevelopmentCreate Email TemplatesPreview Templates in DevelopmentBackend Usage (Procedures & Controllers)Sending Emails DirectlyIntegration with Notifications (Recommended)Template Data ValidationFrontend Usage (Client-side)Email Preview DevelopmentTemplate Development WorkflowEmail TemplatesAvailable TemplatesCreating Custom TemplatesPractical ExamplesBackend: User Registration FlowBackend: Organization InvitationBackend: Billing NotificationsEmail Data StructureMailProviderSendParamsTemplate SchemaTroubleshootingBest PracticesSee AlsoAPI ReferenceMail Service MethodsEmail Provider ConfigurationDevelopment Commands
Nitrofy LogoNitrofy

Automatize o envio e a cobrança dos seus contratos

© 2026 Nitrofy, All rights reserved