Saturday, November 2, 2024
How to send emails in React using Resend and React Email ?
Posted by
Why Resend & React Email for your application ?
When developing applications it is common to send emails such as transactional emails, notifications to your users. However, email templates are notorious of being painful to create due to:
- Inconsistent rendering across email clients
- Responsive email design challenges
- Limited CSS support
This is where Resend and React Email comes into the picture
- Resend helps us to send the actual emails.
- React Email helps us to create responsive emails using React components.
If you are a React developer, this will be great email solution for your React/NextJS application.
Let's go through how I setup my Resend + React Email Setup.
Step 1: Install dependencies
npm i @react-email/components resend
npm install --save-dev react-email
Step 2: Create some folders
The following is how I prefer to setup my folder structure for emails. The email sending functions and email templates are all being stored here.
.
├── ...
├── modules/
│ ├── email/
│ │ └── emails/
│ │ ├── ... // This is where we put the email templates
│ │ └── index.ts
│ └── index.ts // Where we put the send email handler
└── ...
Step 3: Get your Resend API key
You will need to sign up for a Resend account and create a Resend API key.
The generated API key will be used to initialise Resend for email sending.
import { Resend } from "resend";
const resendToken = process.env.RESEND_TOKEN;
// const resendToken = import.meta.env.RESEND_TOKEN; // For Vite based React projects
const resend = new Resend(resendToken);
Step 4: Create the sendEmail function
What I like to do it to create a wrapper function over Resend's API. So I can have global control over the emails that I wanted to send from my applications.
import { type CreateEmailOptions, type CreateEmailRequestOptions, Resend } from "resend";
import { getEnvVariables } from "../utils/getEnvVariables";
import * as emails from "./emails";
import React from "react";
const resendToken = process.env.RESEND_TOKEN;
// const resendToken = import.meta.env.RESEND_TOKEN; // For Vite based React projects
const resend = new Resend(resendToken);
const SENDER = '[email protected]';
// Define the type for the emails object
type Emails = typeof emails;
// Define a union type of the keys of the emails object
type EmailTemplateName = keyof Emails;
// The sendEmail function with type inference for props
export default async function sendEmail<T extends EmailTemplateName>(
{ payload, templateProps, options, template }: {
payload: Omit<Omit<CreateEmailOptions, 'react'>, 'from'>,
options?: CreateEmailRequestOptions,
template: T,
templateProps: React.ComponentProps<typeof emails[T]>
}
) {
const emailComponent = emails[template];
// @ts-ignore
const reactElement = React.createElement(emailComponent, templateProps);
return resend.emails.send(
{
...payload,
from: SENDER,
react: reactElement,
},
options
);
}
Lots of things happening here. In essence what it does is it defines all available emails templates & their corresponding props exported from the emails
folder as a type for the sendEmail
function.
This implementation ensures type safety by inferring props based on the selected email template, reducing runtime errors. It simplifies email sending with a reusable function that supports dynamic template selection, enhances developer experience, improves code maintainability, and leverages React and TypeScript for scalable and reliable email handling.
Step 5: Add some templates.
Next is to add some emails into the emails
folder. I refered emails from the React Email Demo Page.
I will pick the Welcome Email as a sample.
import { Body, Button, Column, Container, Head, Heading, Html, Img, Link, Preview, Row, Section, Text, Tailwind, } from "@react-email/components";
interface WelcomeEmailProps {
steps?: {
id: number;
Description: React.ReactNode;
}[];
links?: string[];
}
const baseUrl = process.env.VERCEL_URL
? `https://${process.env.VERCEL_URL}`
: "";
const PropDefaults: WelcomeEmailProps = {
steps: [
{
id: 1,
Description: (
<li className="mb-20" key={1} >
<strong>Deploy your first project.</strong>{" "}
< Link > Connect to Git, choose a template</ Link >, or manually deploy a
project you've been working on locally.
</li>
),
},
],
links: ["Visit the forums", "Read the docs", "Contact an expert"],
};
export const Welcome = ({
steps = PropDefaults.steps,
links = PropDefaults.links,
}: WelcomeEmailProps) => {
return (
<Html>
<Head />
<Preview> Netlify Welcome </Preview>
<Tailwind
config={{
theme: {
extend: {
colors: { brand: "#2250f4", offwhite: "#fafbfb" },
spacing: { 0: "0px", 20: "20px", 45: "45px" },
},
},
}
}
>
<Body className="bg-offwhite text-base font-sans" >
<Img
src={`${baseUrl}/static/netlify-logo.png`}
width="184"
height="75"
alt="Netlify"
className="mx-auto my-20"
/>
<Container className="bg-white p-45" >
<Heading className="text-center my-0 leading-8" >
Welcome to Netlify
</Heading>
< Section >
<Row>
<Text className="text-base" >
Congratulations! You're joining over 3 million developers
around the world who use Netlify to build and ship sites,
stores, and apps.
</Text>
< Text className="text-base" > Here's how to get started:</Text>
</Row>
</Section>
<ul> {steps?.map(({ Description }) => Description)}</ul>
<Section className="text-center" >
<Button className="bg-brand text-white rounded-lg py-3 px-[18px]" >
Go to your dashboard
</Button>
</Section>
<Section className="mt-45" >
<Row>
{links?.map((link) => (
<Column key={link} >
<Link className="text-black underline font-bold" >
{link}
</Link>{" "}
< span className="text-green-500" >→</span>
</Column>
))}
</Row>
</Section>
</Container>
< Container className="mt-20" >
<Section>
<Row>
<Column className="text-right px-20" >
<Link>Unsubscribe </Link>
</Column>
< Column className="text-left" >
<Link>Manage Preferences </Link>
</Column>
</Row>
</Section>
< Text className="text-center text-gray-400 mb-45" >
Netlify, 44 Montgomery Street, Suite 300 San Francisco, CA
</Text>
</Container>
</Body>
</Tailwind>
</Html>
);
};
export default Welcome;
Export the email template from the emails
folder. This template will be registered as a props of the sendEmail
function
...
export * from "./welcome-email"
...
Step 6: Try it out.
Invoke your sendEmail
function in your project as so, you can set to:
as your personal email to try it out.
You should see available email templates in the autocomplete.
import {sendEmail} from "@/modules/email";
await sendEmail({
payload: {
subject: "Please reply to me now",
to: "[email protected]",
},
template: "Welcome",
templateProps: {
steps: [
{
id: 1,
Description: "Some description",
},
],
},
});
How to preview your email templates ?
Resend provides a neat way to preview your email templates. Head over to your package.json
.
Add a new script email dev --dir <-directory of your email templates->
...
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint",
"email-dev": "email dev --dir src/modules/email/emails"
},
...
Running npm run email-dev
should give you a neat previewer like below. The email in the previewer should reflect the changes that you made within the email folder.
Automatic setup
To automate the setup above of React Email & Resend to your project. You can utilize c0nfig to automate the process.
Initialise c0nfig
npx k0nfig@latest init
Run email command
npx k0nfig@latest run https://c0nfig.dev/cli/email-setup.json
Add in more email templates
npx k0nfig@latest run https://c0nfig.dev/cli/email-add.json
Conclusion
By integrating Resend and React Email into your React application, you can overcome the common challenges of creating email templates—such as inconsistent rendering across clients and limited CSS support. This approach allows you to leverage your React skills to build responsive and maintainable email templates efficiently. The sendEmail
function provides a type-safe, reusable way to send emails with dynamic templates, enhancing developer experience and code reliability. Additionally, using tools like c0nfig can automate and streamline the setup process, saving you time and effort. With these tools, you can focus on delivering great features to your users without getting bogged down by the complexities of email template development.