Send React Email components with PostHog
Contents
React Email lets you write emails as React components. Keep React Email to write your emails, and send them with the Node.js SDK. Pass the component to send as react, and the SDK renders its HTML and plain text. PostHog sends the content as you rendered it. You don't need a template in PostHog.
The Node.js SDK takes react from version 5.69.0. Before you start, create a project secret API key with the Transactional email scope.
Install
The SDK renders the component with @react-email/render, version 2.1.0 or later. It's an optional peer dependency of the SDK, so install it next to posthog-node.
Write an email
Write the email as a component, with the components from react-email:
Set up the client
Reuse the PostHog client your application already creates, and set secretKey to your project secret API key. See set up the client for the host and for local evaluation.
Send an email
Pass the component as react. The SDK renders it to HTML, makes the plain text version from the HTML, and sends both:
- Key:
templateKeynames the email. PostHog groups the email's metrics and sends under it, so use one key for each component, such asorder-shipped. - Text: The SDK makes the plain text with
toPlainTextfrom@react-email/render, which keeps the link of each button and drops the markup. To send your own plain text, passtext. The SDK then sends yourtextand renders only the HTML. - Props: The SDK renders the element after you call
send, before it sends the request. Don't change the objects that you pass as props until the send finishes. - Sender:
fromneeds an address on a domain that your project verified. Without it, PostHog uses the project's default sender. - User: Pass the distinct ID that you pass to
identify()asdistinctId, so PostHog records the send and its engagement events against that user. See link emails to your users. - Tracking: An email with no template in PostHog is sensitive by default, so PostHog doesn't track its clicks. An order email carries no secrets, so you can pass
sensitive: falseto track its clicks.sensitiveneeds version 5.71.0 or later. See open and click tracking. - Retries: The idempotency key identifies the email. A retry with the same key in the 24 hours after PostHog queues the email doesn't send it again. See retry safely and timeouts and retries.
send returns { data, error } and doesn't throw. data.id is the message ID, which you can pass to get to read the email's status.
Errors from a React send
A send with react can return these error codes. For each one, the SDK sends nothing:
| Code | Cause | Fix |
|---|---|---|
invalid_form | The send has react and html, or react and templateId. Or it has sensitive on an SDK version earlier than 5.71.0. error.message names the field. | react replaces html, so pass one of them. A template in PostHog takes no react, because PostHog renders the template. For sensitive, upgrade to version 5.71.0 or later. |
missing_react_renderer | The SDK can't load @react-email/render. | Install @react-email/render with react and react-dom next to posthog-node. |
react_render_failed | The component threw an error, or didn't finish rendering before the email request timeout. The timeout is 15 seconds by default, and emailRequestTimeoutMs on the client changes it. | If the component threw, error.cause holds its error. Fix the component, and render it in a test with the same props to see the error. |
For every other error code, see the errors table.
Send from Next.js
Send from a route handler or a server action on the Node.js runtime, which is the default. React Email doesn't render in a Next.js route on the edge runtime, whether the SDK renders it or you do. A send with react from a route with export const runtime = "edge" returns react_render_failed after the email request timeout, and sends nothing.
Render the email yourself
To keep the rendered HTML, such as to store a copy, or to send with an SDK version earlier than 5.69.0, render the component yourself. Render it with render, make the plain text with toPlainText, and pass both as html and text:
The SDK sends content from your code from version 5.62.0. If you leave out text, PostHog makes it from html.





