Skip to main content
The @react-email/render package provides different builds optimized for Node.js, edge runtimes, and browsers.

Installation

npm install @react-email/render

render

Converts a React email component into an HTML string.
import { render } from '@react-email/render';
import { Email } from './emails/welcome';

const html = await render(<Email />);

Parameters

node
React.ReactNode
required
The React component to render as an email
options
Options
Configuration options for rendering

Returns

html
Promise<string>
A promise that resolves to the rendered HTML string with DOCTYPE declaration, or plain text if plainText option is enabled

Usage Examples

Node.js

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

// Basic rendering
const html = await render(<WelcomeEmail name="John" />);

// With pretty formatting
const prettyHtml = await render(<WelcomeEmail name="John" />, {
  pretty: true,
});

// Convert to plain text
const plainText = await render(<WelcomeEmail name="John" />, {
  plainText: true,
});

Edge Runtime (Vercel, Cloudflare Workers)

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

export const config = {
  runtime: 'edge',
};

export default async function handler(req: Request) {
  const html = await render(<WelcomeEmail name="Sarah" />);
  
  return new Response(html, {
    headers: {
      'Content-Type': 'text/html',
    },
  });
}

Next.js App Router

import { render } from '@react-email/render';
import { WelcomeEmail } from '@/emails/welcome';
import { NextResponse } from 'next/server';

export async function POST(request: Request) {
  const { name } = await request.json();
  
  const html = await render(<WelcomeEmail name={name} />);
  
  // Send email with your provider
  // await sendEmail({ html, ... });
  
  return NextResponse.json({ success: true });
}

Browser (Client-Side)

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

const PreviewButton = () => {
  const handlePreview = async () => {
    const html = await render(<NewsletterEmail />);
    
    // Open preview in new window
    const newWindow = window.open();
    newWindow?.document.write(html);
  };
  
  return <button onClick={handlePreview}>Preview Email</button>;
};

Utility Functions

toPlainText

Converts HTML content to plain text format.
import { toPlainText } from '@react-email/render';

const html = '<h1>Welcome</h1><p>Thank you for signing up!</p>';
const plainText = toPlainText(html);
// Output: "Welcome\n\nThank you for signing up!"

Parameters

html
string
required
The HTML string to convert to plain text
options
HtmlToTextOptions
Configuration options for the conversion. See html-to-text documentation

Returns

text
string
The plain text representation of the HTML

pretty

Formats HTML with proper indentation and formatting using Prettier.
import { pretty } from '@react-email/render';

const html = '<div><h1>Title</h1><p>Content</p></div>';
const formatted = pretty(html);

Parameters

str
string
required
The HTML string to format
options
Options
Prettier formatting options. Defaults to { endOfLine: 'lf', tabWidth: 2, bracketSameLine: true, parser: 'html' }

Returns

formatted
string
The formatted HTML string

Advanced Usage

Custom Plain Text Options

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

const plainText = await render(<Email />, {
  plainText: true,
  htmlToTextOptions: {
    wordwrap: 80,
    selectors: [
      { selector: 'a', options: { hideLinkHrefIfSameAsText: true } },
      { selector: 'img', format: 'skip' },
    ],
  },
});

Combining Options

import { render, toPlainText } from '@react-email/render';
import { Email } from './emails/receipt';

// Render both HTML and plain text versions
const html = await render(<Email />, { pretty: true });
const text = toPlainText(html);

// Use both versions when sending email
await sendEmail({
  html,
  text,
  subject: 'Your Receipt',
  to: '[email protected]',
});

Runtime Compatibility

The package automatically uses the correct build based on your environment:
  • Node.js: Uses renderToPipeableStream or renderToReadableStream (Node.js 20+)
  • Edge Runtimes: Optimized for Vercel Edge, Cloudflare Workers, Deno
  • Browser: Client-side rendering support

TypeScript

import { render, type Options } from '@react-email/render';
import type { ReactNode } from 'react';

interface SendEmailParams {
  component: ReactNode;
  options?: Options;
}

async function sendEmail({ component, options }: SendEmailParams) {
  const html = await render(component, options);
  // Send email...
}

Best Practices

The render function is asynchronous and returns a Promise. Make sure to use await or handle the Promise properly.
// Good
const html = await render(<Email />);

// Also good
render(<Email />).then(html => {
  // Use html
});
Many email clients and spam filters prefer emails with both HTML and plain text versions.
const html = await render(<Email />);
const text = await render(<Email />, { plainText: true });

await sendEmail({ html, text });
When debugging email templates, use the pretty option to make the HTML more readable.
const html = await render(<Email />, {
  pretty: process.env.NODE_ENV === 'development',
});

Build docs developers (and LLMs) love