Introduction
React Email is a brand new email library from the Resend team. It allows us to create powerful dynamic emails with complex layouts, providing value to our users and simplifying the development process. When paired with PayloadCMS, React Email can complement your booking system, subscription list, or even CMS user sign-up flow.
What is PayloadCMS?
For the uninitiated, PayloadCMS is a developer-friendly headless content management system with a heavy focus on rapid development and extendibility. Payload comes with a ton of built-in components, functions, and hooks that let us create full-featured websites, e-commerce platforms, and booking portals. It can even be used to help make games. Nodemailer is the default email provider, with support for Ethereal Mail out of the box to help you test in a safe, free environment.
What is React Email
React Email is an Email-first component library that lets you build your Emails with React and Tailwindcss, before rendering the resulting HTML into a email-friendly format. If you have worked with email design tools before, you'll know how much of a headache it can be to develop well-formatted and stylish emails, all while traversing a mountain of inline css. Fortunately, React Email does all the hard work for us.
Setup
Before we begin, this article won't show you how to set up an email provider. If you would like to learn how to do that, we recommend reading this article by Payload. If you are using Resend, This comment on the Payload Discord provides a full code sample of a custom transport using Resend.
React Email splits its library into individually installable components, as such, you will need to install each component as required. For this, we will install the HTML and Text component and the Render function. Enter the following code into your terminal;
Yarn installation code
yarn add react-email @react-email/html @react-email/text @react-email/render -E
Once your packages have been installed, add a folder called templates at the same level as your Payload.config.ts file. Next, create a file called NewUserEmail.tsx and enter the following code;
NewUserEmail.tsx code
import { Html } from '@react-email/html'
import { Text } from '@react-email/text'
import { render } from '@react-email/render'
type Props = {
name: string;
}
const Template: FC<Props> = ({ name }) => {
return (
<Html>
<Text>Hello, {name}</Text>
</Html>
)
}
export function newUserEmail(data: Props) {
return render(<Template{...data} />);
}
You have just created your first email! Notice that we first create the HTML for our email in the Template component. Then we pass it into the render() function, which converts our React code into email-friendly HTML. We can also pass props to our component, letting us dynamically populate our email. Now it's time to use it...
Sending your first email
We're going to test our email using Ethereal mail. Don't worry, Payload handles most of this for you! We just want to make sure we can access the temporary email address all mail is routed to. Inside your server.ts file, find your payload.init() function and add the following code;
Log Ethereal Mail credentials to the console
payload.init({ email: { fromName: "Admin", fromAddress: "admin@example.com", logMockCredentials: true }
// ...
});
Now your console will display your login details when you start up your app. Be aware, every time your app starts up or refreshes (due to code changes) your credentials will be reset and you will need to log back into your EtherealMail client. The message will look like this;
Resulting console log
[06:37:21] INFO (payload): Starting Payload...
[06:37:22] INFO (payload): Payload Demo Initialized
[06:37:22] INFO (payload): listening on 3000...
[06:37:22] INFO (payload): Connected to MongoDB server successfully!
[06:37:23] INFO (payload): E-mail configured with mock configuration
[06:37:23] INFO (payload): Log into mock email provider at https://ethereal.email
[06:37:23] INFO (payload): Mock email account username: hhav5jw7doo4euev@ethereal.email
[06:37:23] INFO (payload): Mock email account password: VNdGcvDZeyEhtuPBqf
With your transport set up, let's create a scenario where we need to send an email. By default, your Payload code will have a collection called Users. We're going to send an email every time a user is added to Payload. We'll make use of the afterChange hook. This hook fires whenever changes to the collection are saved, for instance, creating a new user. Open your Users.ts file in the collections folder and add the following code;
afterChange hook at the collection level
hooks: {
afterChange: [sendNewUserEmail]
}
At this time, it might be a good idea to add a folder called hooks in your Payload project. Inside of this hooks folder, you can create a new file called sendNewUserEmail.ts. Inside this file, we're going to add an if condition that checks to see if the operation was 'create'. If true, we'll send a new email to the user.
Custom hook code
export const sendNewUserEmail = async ({ res: { payload }, doc, operation }) => {
if (operation === 'create') {
await payload.sendEmail({
to: doc.email,
from: 'Admin',
subject: 'New user added!'
html: newUserEmail({ name: doc.firstName + ' ' + doc.lastName })
})
}
That's it! Spin up your Payload instance, create a new user, and then log in to your EtherealMail account with the mock credentials provided in the console. You should see your newly formatted email! Obviously, it looks a bit boring, but with React Email you can style your component any way you like!