Marcio Cunha

How to Send Dynamic Data Templates in Node.js and React Using React Email

Learn how to build and dispatch complex transactional emails by combining Node.js robustness with React component flexibility and the React Email library.

Marcio Cunha12 min
Also available in:EspañolPortuguês
Summary
  • Building emails in raw HTML and inline CSS creates chronic compatibility issues across different email service providers.
  • The React Email ecosystem solves this pain by allowing reusable components to structure messages with high visual predictability.
  • Injecting dynamic data in Node.js happens directly inside component properties, simplifying mass personalization.
  • The rendering step converts the React element tree into an optimized HTML string before actual transport dispatch.
  • Adopting this architecture standardizes the communication workflow and eliminates rework when maintaining transactional message layouts.

The Historical Challenge of Developing Transactional Emails

Creating email messages that render flawlessly across dozens of different mail clients, such as Gmail, Outlook, and Apple Mail, remains one of the greatest headaches for developers. Historically, this required nested HTML tables and styles applied directly inline, an archaic practice reminiscent of late-nineties web development. In practice, this means a simple welcome layout could break completely simply because Outlook interpreted a margin differently.

When we add dynamic data to this equation, such as user names, purchase histories, or personalized invoices, complexity explodes. Legacy systems relied on plain text template engines where typos went unnoticed until a customer received a corrupted email. Modern engineering needed an approach that brought type safety and componentization, which we already use in everyday web interface development, straight into our messaging workflows.

The Arrival of React Email in the Node.js Ecosystem

React Email emerges as an elegant solution to this chronic software engineering problem. It is an open-source library designed to enable the creation of emails using familiar React components, automatically translating this structure into the highly compatible HTML that mail clients demand. In practice, you write clean, modular code, and the tool handles compatibility adjustments behind the scenes.

For developers working with Node.js on the server side, this technology fits seamlessly into existing development stacks. There is no need to learn a brand-new template syntax or install dozens of unknown packages to handle text formatting and basic conditionals. The ecosystem benefits from the exact same mental model applied to modern web applications, unifying the company technology stack from end to end.

Structuring the Project and Installing Dependencies

The first practical step to implement this solution involves setting up a clean Node.js environment and installing the required libraries. Alongside the React ecosystem itself, we need the core React Email package and a transport service to effectively dispatch messages to the internet, such as Resend or traditional Nodemailer. In practice, run the installation command in your terminal to pull in the essential packages.

npm install react react-dom @react-email/components @react-email/render nodemailer

With dependencies installed, the project folder structure should clearly separate visual email components from backend business logic and Node.js API routes. This separation of concerns ensures template maintenance occurs in complete isolation, allowing any developer to alter a message's visual aspect without touching server-side sending rules.

Creating the First Email Component with Dynamic Data

Let us build a practical transactional email component for a payment receipt. Instead of concatenating strings in text files, we utilize semantic elements provided by the library, such as Html, Head, Container, and Text. In practice, these components encapsulate raw HTML tags and automatically apply styling rules that guarantee proper rendering across mobile apps and desktop clients.

To accept dynamic data, we define a TypeScript interface or type that describes the properties expected by the component, such as the customer name, transaction amount, and order number. The following code demonstrates how to structure this template in a clean, reusable way within your project directory:

import { Html, Head, Container, Text, Heading } from '@react-email/components';

interface ReceiptEmailProps {
  customerName: string;
  amount: number;
  orderId: string;
}

export function ReceiptEmail({ customerName, amount, orderId }: ReceiptEmailProps) {
  return (
    <Html>
      <Head />
      <Container>
        <Heading>Hello, {customerName}!</Heading>
        <Text>We have received your payment of ${amount.toFixed(2)} regarding order #{orderId}.</Text>
      </Container>
    </Html>
  );
}

Rendering the Component to an HTML String on the Server

Node.js cannot send a React component directly to an SMTP mail server because mail clients interpret only traditional HTML. Therefore, we need the render function provided by the package to convert the component tree into a pure text string before dispatching. In practice, the render function takes our component filled with data and spits out the final HTML code ready for transit.

This step happens at the exact moment a business event triggers on your backend, such as after confirming an order in the database. The code snippet below illustrates how this conversion happens inside an asynchronous Node.js function:

import { render } from '@react-email/render';
import { ReceiptEmail } from './emails/ReceiptEmail';

const emailHtml = render(
  <ReceiptEmail 
    customerName='Jane Doe' 
    amount={150.00} 
    orderId='98765' 
  />
);

Integrating with the Sending Service and Dispatching the Message

Once we have the rendered HTML string in memory, the next logical step involves handing it over to a transport service so the email reaches the end user's inbox. We can use Nodemailer configured with a traditional SMTP server or modern developer-focused APIs. In practice, we pass the generated string from the previous step into the html parameter of the sending function.

Keeping this routine encapsulated in a dedicated service inside your backend prevents code duplication and centralizes network error handling. If the email provider rejects the connection, the application can log the incident and retry in the background without blocking the user's primary request.

import nodemailer from 'nodemailer';

const transporter = nodemailer.createTransport({
  host: 'smtp.example.com',
  port: 587,
  auth: { user: 'user', pass: 'password' }
});

await transporter.sendMail({
  from: '[email protected]',
  to: '[email protected]',
  subject: 'Order Confirmation',
  html: emailHtml,
});

Final Considerations on Maintainability and Scalability

Adopting React Email combined with Node.js radically transforms how engineering teams handle transactional communication. By eliminating the need to manually manipulate legacy HTML files and introducing static typing and componentization, we drastically reduce visual bugs in production. In practice, this results in emails that look better, remain predictable, and are easier to update as the business evolves.

Investing time into correctly structuring this communication layer early in a project ensures that user base expansion happens smoothly. Whether sending receipts, security alerts, or automated campaigns, the React and Node.js stack provides the stability and agility required to sustain modern, efficient digital products.