SendGrid (now part of Twilio) is the most widely-used email API. It handles both transactional and marketing email at scale. If you're looking for broad ecosystem support and generous free tier, it's a common choice. This guide shows you exactly how to integrate React Email with SendGrid in a Next.js project — covering environment setup, rendering templates to HTML, sending with both App Router and Pages Router, and handling common errors.
Prerequisites
Before starting, you need:
- A SendGrid account with API credentials
- A Next.js project (App Router or Pages Router — both covered below)
- Node.js 18+
Step 1: Install Dependencies
npm install @sendgrid/mail @react-email/render@react-email/render converts your React Email component to an HTML string, which you then pass to SendGrid's API. Unlike Resend (which accepts React elements directly), most providers require rendered HTML.
Step 2: Configure Environment Variables
Add the following to your .env.local file:
SENDGRID_API_KEY=SG.xxxxxxxxxxxxxxxxxxxxxxxxSENDGRID_API_KEY— Found in the SendGrid dashboard under Settings → API Keys
When deploying, add these variables in your hosting provider's environment settings (Vercel dashboard, Railway, Fly.io, etc.). Variables in .env.local do not deploy automatically.
Step 3: Create a React Email Template
Create an emails/ directory and add your first template. All providers use the same React Email template format — the difference is only in how you send it.
// emails/welcome-email.tsximport * as React from 'react';import { Body, Button, Container, Head, Heading, Html, Preview, Section, Text,} from '@react-email/components';
interface WelcomeEmailProps { username: string; dashboardUrl: string;}
export function WelcomeEmail({ username, dashboardUrl }: WelcomeEmailProps) { return ( <Html> <Head /> <Preview>Your account is ready — let's get started</Preview> <Body style={{ fontFamily: 'sans-serif', backgroundColor: '#f4f4f5' }}> <Container style={{ margin: '0 auto', padding: '40px 20px', maxWidth: '560px' }}> <Heading>Welcome, {username}!</Heading> <Text>Your account is set up and ready to use.</Text> <Section> <Button href={dashboardUrl} style={{ backgroundColor: '#000', color: '#fff', padding: '12px 24px', borderRadius: '6px' }} > Go to Dashboard </Button> </Section> </Container> </Body> </Html> );}
WelcomeEmail.PreviewProps = { username: 'Alex', dashboardUrl: 'https://example.com/dashboard',} as WelcomeEmailProps;
export default WelcomeEmail;Preview locally
Before sending real emails, use the React Email dev server to preview your templates:
npx react-email dev --dir emailsOpen http://localhost:3000 to see your templates rendered exactly as they will appear in email clients.
Step 4: Initialize the SendGrid Client
Create the client once at module level so it's reused across requests:
import sgMail from '@sendgrid/mail';
sgMail.setApiKey(process.env.SENDGRID_API_KEY!);Step 5: Create the API Route
App Router (app/api/send/route.ts)
import { render } from '@react-email/render';import sgMail from '@sendgrid/mail';import { WelcomeEmail } from '../../../emails/welcome-email';
sgMail.setApiKey(process.env.SENDGRID_API_KEY!);
export async function POST(request: Request) { const { username, email } = await request.json();
const html = await render( <WelcomeEmail username={username} dashboardUrl="https://yourdomain.com/dashboard" /> );
await sgMail.send({ to: email, from: 'hello@yourdomain.com', subject: `Welcome, ${username}!`, html, });
return Response.json({ success: true });}Pages Router (pages/api/send.ts)
import type { NextApiRequest, NextApiResponse } from 'next';import { render } from '@react-email/render';import sgMail from '@sendgrid/mail';import { WelcomeEmail } from '../../emails/welcome-email';
sgMail.setApiKey(process.env.SENDGRID_API_KEY!);
export default async function handler(req: NextApiRequest, res: NextApiResponse) { if (req.method !== 'POST') return res.status(405).end();
const { username, email } = req.body;
const html = await render( <WelcomeEmail username={username} dashboardUrl="https://yourdomain.com/dashboard" /> );
await sgMail.send({ to: email, from: 'hello@yourdomain.com', subject: `Welcome, ${username}!`, html, });
return res.status(200).json({ success: true });}SendGrid-Specific Tips
- Your `from` address must match a verified sender identity or authenticated domain in the SendGrid dashboard.
- SendGrid throws on failure (unlike Resend which returns an error object) — wrap calls in try/catch.
- For better deliverability, enable domain authentication in SendGrid rather than using a single sender verification.
- `sgMail.send()` accepts an array of messages for batch sending, or use `sgMail.sendMultiple()` to send the same message to multiple recipients.
Common Errors and Fixes
| Error | Cause | Fix |
|---|---|---|
Forbidden (403) | Sender identity not verified | Verify your From address as a Single Sender or authenticate your domain in the SendGrid dashboard |
Unauthorized (401) | Invalid or missing API key | Check SENDGRID_API_KEY is set correctly and has "Mail Send" permission |
sgMail.send is not a function | CommonJS/ESM interop issue | Use `import sgMail from "@sendgrid/mail"` and ensure your tsconfig has `esModuleInterop: true` |
Organizing Multiple Email Templates
A SaaS app typically needs 8–12 email templates. Keep them organized in a dedicated directory:
emails/
├── welcome-email.tsx
├── otp-email.tsx
├── magic-link.tsx
├── password-reset.tsx
├── payment-receipt.tsx
├── trial-started.tsx
├── trial-ending.tsx
└── security-alert.tsxEach template uses the same @react-email/components primitives and is rendered to HTML with @react-email/render before being passed to SendGrid.
If you don't want to write and cross-client test all these templates from scratch, the React Email Templates bundle includes 12 production-ready templates for the most common SaaS email flows — tested on Gmail, Outlook, Apple Mail, and mobile clients in both light and dark mode.
