You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

NextJS 13服务端Action中使用renderToStaticMarkup报错的解决方法

解决NextJS 13服务端Action中生成HTML邮件的错误及替代方案

一、修复现有代码的两个错误

1. 解决TS错误:'ResetPasswordEmail'被当作类型使用

这个错误是因为你把组件(一个值)当成了TypeScript类型来使用,比如在定义参数类型时写了const fn = (param: ResetPasswordEmail) => {}。解决步骤:

  • 在ResetPasswordEmail.tsx中单独提取并导出Props类型:
// ResetPasswordEmail.tsx
type ResetPasswordEmailProps = {
  firstName: string;
  // 其他需要的props
};

export default function ResetPasswordEmail({ firstName }: ResetPasswordEmailProps) {
  return <div>...</div>;
}

// 导出类型供服务端Action使用
export type { ResetPasswordEmailProps };
  • 在服务端Action中使用导出的Props类型,而非组件本身:
import ResetPasswordEmail, { ResetPasswordEmailProps } from './ResetPasswordEmail';

// 用ResetPasswordEmailProps定义参数类型
async function sendEmail(userData: ResetPasswordEmailProps) {
  // ...
}

2. 解决renderToStaticMarkup的语法错误:Expected '>', got 'firstName'

这个错误是JSX语法解析失败导致的,核心原因是服务端Action所在文件不是.tsx后缀(.ts文件默认不支持JSX)。解决步骤:

  • 将服务端Action所在文件的后缀改为.tsx,确保文件能解析JSX语法。
  • 确保在renderToStaticMarkup中正确使用JSX语法调用组件,而非函数调用:
// 正确写法
import { renderToStaticMarkup } from 'react-dom/server';
import ResetPasswordEmail from './ResetPasswordEmail';

export async function sendResetPasswordEmail() {
  // 用JSX语法传入props
  const html = renderToStaticMarkup(<ResetPasswordEmail firstName="张三" />);
  
  // 此处调用邮件发送逻辑(比如nodemailer)
}

二、服务端Action发送HTML邮件的替代方案

1. 使用react-email库(推荐)

react-email专门用于构建兼容各类邮箱的React邮件模板,支持NextJS 13服务端渲染:

  • 安装依赖:
npm install react-email @react-email/components @react-email/render
  • 创建邮件模板组件:
// ResetPasswordEmail.tsx
import { Html, Body, Container, Heading, Text, Link } from '@react-email/components';

type ResetPasswordEmailProps = {
  firstName: string;
  resetLink: string;
};

export default function ResetPasswordEmail({ firstName, resetLink }: ResetPasswordEmailProps) {
  return (
    <Html>
      <Body style={{ fontFamily: 'Arial, sans-serif' }}>
        <Container style={{ maxWidth: '600px', margin: '0 auto' }}>
          <Heading>Hi {firstName},</Heading>
          <Text>请点击下方链接重置你的密码:</Text>
          <Link href={resetLink} style={{ color: '#0070f3' }}>
            重置密码
          </Link>
        </Container>
      </Body>
    </Html>
  );
}
  • 在服务端Action中渲染并发送:
import { renderAsync } from '@react-email/render';
import ResetPasswordEmail from './ResetPasswordEmail';
import nodemailer from 'nodemailer';

export async function sendResetPasswordEmailAction() {
  const html = await renderAsync(
    <ResetPasswordEmail firstName="张三" resetLink="https://your-domain.com/reset-password" />
  );

  // 配置邮件发送器(以nodemailer为例)
  const transporter = nodemailer.createTransport({
    service: 'Gmail',
    auth: {
      user: 'your-email@example.com',
      pass: 'your-app-password',
    },
  });

  await transporter.sendMail({
    from: 'your-email@example.com',
    to: 'user-email@example.com',
    subject: '重置你的密码',
    html: html,
  });
}

2. 使用第三方邮件服务的模板

比如SendGrid、Mailgun等服务,支持在后台创建邮件模板,只需在服务端Action中传入模板参数即可渲染发送,无需自己生成HTML:

  • 在SendGrid后台创建模板,添加占位符(如{{firstName}}、{{resetLink}})
  • 在服务端Action中调用SendGrid API发送邮件:
import sgMail from '@sendgrid/mail';

sgMail.setApiKey('your-sendgrid-api-key');

export async function sendResetPasswordEmailAction() {
  await sgMail.send({
    to: 'user-email@example.com',
    from: 'your-email@example.com',
    templateId: 'your-template-id',
    dynamicTemplateData: {
      firstName: '张三',
      resetLink: 'https://your-domain.com/reset-password',
    },
  });
}

内容的提问来源于stack exchange,提问作者Sandy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 18:13:12