Next.js Discord

Discord Forum

Use renderToStaticMarkup to send an email in a server action

American black bear posted this in #help-forum
Open in Discord
American black bearOP
Hi everyone!

I'm attempting to use renderToStaticMarkup in a server action to send the generated HTML via email.

import { renderToStaticMarkup } from "react-dom/server";
import { sendEmail } from "@/infra/email";
import { ResetPasswordEmail } from "@/infra/email/templates";
import { zhrLog } from "@/infra/logging";
import { userRoutes } from "@/routes";

interface SendPasswordResetLink {
  email: string;
  firstName: string;
  passwordResetToken: string;

export const sendPasswordResetLink = async ({ email, firstName, passwordResetToken }: SendPasswordResetLink): Promise<void> => {
  const url = userRoutes.resetPassword.generateUrl(passwordResetToken);
  const subject = `Password reset`;
  const html = renderToStaticMarkup(<ResetPasswordEmail firstName={firstName} url={url} />);
  const result = await sendEmail({ html, subject, toEmail: email, toName: firstName });

  if (result === `error`) {
    zhrLog(`Error sending password reset link to ${email}`);
    throw new Error();

However I'm getting the following error in the backend:
Error: × Expected '>', got 'firstName'

And in VSCode I get red squigly lines and when I hover it says:
'ResetPasswordEmail' refers to a value, but is being used as a type here. Did you mean 'typeof ResetPasswordEmail'?ts(2749)

The ResetPasswordEmail component doesn't have any interactivity, and its filename ends in .tsx.

Any idea how I can fix this, or some other way to send HTML emails in server actions? Thanks!

13 Replies

Eric Burel
Cause TypeScript thinks you are crafting a generic type
you would need the file to be tsx, because it must be first compiled to normal JS
<ResetPasswordEmail is a shortcut to smth like "ReactDOM.render(...)" (ok it's totally not that but you get the point, it is translated to a function call in JS)
maybe give a shot at just changing the file type
I've tried that in the past (before server actions, in an API route), it wasn't rendering properly but I think it was working
honestly you'd be better of by just creating normal functions, you don't have much benefit from using React components, your email client won't run JavaScript like a browser
American black bearOP
The renderToStaticMarkup function will convert the React into normal HTML without any JS. What I like about this is that I can preview the emails I send in an admin page, something like /admin/previews/emails
The ResetPasswordEmail file is already tsx, and I attempted to change sendPasswordResetLink.ts to sendPasswordResetLink.tsx but this didn't fix it
Eric Burel
you can still preview if using play JavaScript function
you can shove the result into a div with "dangerouslySetInnerHTML"
you could try jsx too to avoid ts issues
I mean technically you should be able to output something, it's not an approach I recommend but you are right you could make soemthign that compiles
I remember having smth that works with TS but JSX would avoid any issue
American black bearOP
True, I'll give it a try to see what is output