@convex-dev/resend

中文文档
0.2.10发布于 2026/10/23Apache-2.0TypeScriptES Module近 30 天下载 84.2万

Convex 的再发送组件 .

中文使用文档
文档目录13 节
  1. 安装
  2. 开始
  3. 高级使用
  4. 设置一个 Resend webhook 系统
  5. 正在注册邮件状态处理器 .
  6. 重新发送组件选项并开始生产
  7. 可选电子邮件发送参数
  8. 排队时间
  9. 使用调试模板
  10. 跟踪、获取状态和取消电子邮件
  11. 保留数据
  12. 使用反应邮件
  13. 手动发送电子邮件, 例如附件

重新发送对流组件

npm version

此组件是将Resend电子邮件服务与 你的Convex项目.

特征 :

  • 排队:随想寄多少邮件,随想寄多少电子邮件——都会是 交付(最终交付).
  • Batching: 自动批发多组邮件并发送到 重新发送 /emails/batch 有效结束点.
  • 持久执行: 使用 Convex 工作池确保电子邮件最终实现 即使面对暂时的故障或网络中断,也提供.
  • 同上:管理 Resend idepotency 密钥以保证电子邮件的发送 就一次 防止意外的垃圾邮件重复.
  • 速率限制:荣耀由Resend设定的API速率限制.

见 实例 演示如何将这个钩子融入你的 应用.

Navigate the Email MINEFIELD with the Resend Component!

安装

npm install @convex-dev/resend

开始

创建一个 重新发送 账户并抓取 API 密钥。 准备吧 RESEND_API_KEY 在您的部署环境中.

下一个,通过 Convex 应用程序添加组件 convex/convex.config.ts数字 :

import { defineApp } from "convex/server";
import resend from "@convex-dev/resend/convex.config.js";

const app = defineApp();
app.use(resend);

export default app;

然后,你可以使用它,正如我们看到的 convex/sendEmails.ts数字 :

import { components } from "./_generated/api";
import { Resend } from "@convex-dev/resend";
import { internalMutation } from "./_generated/server";

export const resend: Resend = new Resend(components.resend, {});

export const sendTestEmail = internalMutation({
  handler: async (ctx) => {
    await resend.sendEmail(ctx, {
      from: "Me <[email protected]>",
      to: "[email protected]",
      subject: "Hi there",
      html: "This is a test email",
    });
  },
});

然后,打电话 sendTestEmail 您的应用程序中的任何地方都会发送此测试 电子邮件.

如果您想要向真实地址发送电子邮件, 您需要禁用 testMode。 。 。 . 你可以这样 ResendOptions, (中文(简体) ), 详见下文。 。 。 .

关于测试电子邮件地址的说明 : 重新发送允许使用标签 用于测试电子邮件。 为简单起见, 此组件只允许标签匹配 [a-zA-Z0-9_-]*,比如说. [email protected]。 。 。 .

高级使用

设置一个 Resend webhook 系统

虽然我们到目前为止的设置 将可靠地发送电子邮件, 你没有任何 任何送货、弹出或引发垃圾邮件投诉的反馈。 对于 那,我们需要设置一个网页库!

Convex方面,我们需要在我们的工程上挂上一个 http end point 来引导它 重新发送组件 convex/http.ts数字 :

import { httpRouter } from "convex/server";
import { httpAction } from "./_generated/server";
import { resend } from "./sendEmails";

const http = httpRouter();

http.route({
  path: "/resend-webhook",
  method: "POST",
  handler: httpAction(async (ctx, req) => {
    return await resend.handleResendEventWebhook(ctx, req);
  }),
});

export default http;

如果我们的Convex项目是快乐的 -leopard-123, 我们现在有一个Resend Webhook 为我们 项目运行于 https://happy-leopard-123.convex.site/resend-webhook。 。 。 .

因此,导航到Resend仪表板 并创建一个新的网页hook 在那个URL。 制作 当然可以使所有 email.* 事件; 其他事件类型将被忽略.

最后,从Resend仪表板上复制出"Webhook"的秘密,并将其设定为 RESEND_WEBHOOK_SECRET convex 部署中的环境变量.

您现在应该看到邮件状态的更新, 因为 Resend 正在推进您的 批发!

说到...

正在注册邮件状态处理器 .

如果您的 Webhook 已建立, 您也可以在 您的应用程序在电子邮件状态改变时会收到通知 .

更新您的 sendEmails.ts 看起来像这样:

import { components, internal } from "./_generated/api";
import { internalMutation } from "./_generated/server";
import { vEmailId, vEmailEvent, Resend } from "@convex-dev/resend";

export const resend: Resend = new Resend(components.resend, {
  onEmailEvent: internal.example.handleEmailEvent,
});

export const handleEmailEvent = internalMutation({
  args: vOnEmailEventArgs,
  handler: async (ctx, args) => {
    // Handle however you want
    // args provides { id: EmailId; event: EmailEvent; }
    // see /example/example.ts
  },
});

看看这个 example/ 在此重播中进行一个完整演示.

重新发送组件选项并开始生产

有一个 ResendOptions 参数 定制它的行为.

看看这个 剂量字符串,但值得注意的选择包括:

  • apiKey: 提供 Resend API 密钥,而不是将其读取 环境变量.
  • webhookSecret(笑声) (笑声) (掌声) (掌声) (掌声) (掌声) (掌声) (掌声) (掌声) (掌声) (掌声) (掌声) (掌声) (掌声) (掌声) (掌声) (掌声) (掌声) (掌声) (掌声) (掌声) (掌声) (掌声) (掌声) (掌声) (掌声) (掌声) (掌声) (掌声) (掌声) (掌声) (掌声) (掌声) (掌声) (掌声) .
  • testMode:只允许交付测试地址. 保护你的安全 开发您的项目, testMode 默认 真实您需要明确 设定为 false 允许您将电子邮件排入 手工业地址.
  • onEmailEvent: 您的电子邮件事件召回, 如上所述 ! 看看这个 剂量字符串 事件详情 发射.

可选电子邮件发送参数

除了基本文本机构外 sendEmail 方法允许您提供列表 replyTo 地址和其他电子邮件 头.

排队时间

组件已经向 Resend 发送了 idepotency 密钥, 所以一个批次是 最多交付一次。 防止组件重试 API 拨打,但这并不能阻止您的应用程序在相同的逻辑电子邮件中排序 两次(例如,当商业流动再起火或动作再起时).

要排队,通过一个 idempotencyKey。如果电子邮件内容相同 密钥已经选中, sendEmail 返回已有的 EmailId 换成 排队(和交付)

const emailId = await resend.sendEmail(ctx, {
  from: "Me <[email protected]>",
  to: "[email protected]",
  subject: "Order confirmation",
  html: "...",
  // Derive this from the triggering event so retries collapse to one send.
  idempotencyKey: `order-confirmation:${orderId}`,
});

因为 sendEmail 运行于交易的变异中, 并排 同一个钥匙是安全的:一个赢,另一个得到它 EmailId。 。 。 .

使用调试模板

你用得着 重新发送模板 改为 从您的Resend仪表板上发送带有预设计的模板的电子邮件。 用一个 模板,提供模板ID和任何所需的模板变量:

await resend.sendEmail(ctx, {
  from: "Me <[email protected]>",
  to: "[email protected]",
  subject: "Welcome to our app",
  template: {
    id: "my-template-id",
    variables: {
      name: "John Doe",
      verificationLink: "https://example.com/verify?token=abc123",
    },
  },
});

[大 无法同时使用 template 财务报告和审定财务报表 html编号 :text 中标 电子邮件 如果您需要发送动态 HTML 内容, 请使用模板 模板变量,或使用 html编号 :text 直接字段(可选为 反应电子邮件) (中文(简体) ).

跟踪、获取状态和取消电子邮件

这个 sendEmail 方法返回品牌类型, EmailId。您可以使用这个 少许东西:

  • 在您的邮件事件更改状态时重新连接原始邮件 处理者.
  • 随时使用 resend.status(ctx, emailId)。 。 。 .
  • 要使用 resend.cancelEmail(ctx, emailId)。 。 。 .

如果电子邮件已经发送到Resend API,则无法取消 . 取消不会触发邮件事件 .

程序检查电子邮件状态

使用 status 检查电子邮件当前状态的方法 :

const emailStatus = await resend.status(ctx, emailId);
if (emailStatus) {
  console.log(emailStatus.status); // e.g., "delivered", "bounced", "sent"
  console.log(emailStatus.bounced); // boolean
  console.log(emailStatus.failed); // boolean
  console.log(emailStatus.complained); // spam complaint (boolean)
  console.log(emailStatus.deliveryDelayed); // boolean
  console.log(emailStatus.opened); // if open tracking enabled (boolean)
  console.log(emailStatus.clicked); // if click tracking enabled (boolean)
  console.log(emailStatus.errorMessage); // error details (string | null)
}

在仪表板上查看电子邮件和网络浏览事件

您可以在组件的 Convex 仪表板上直接查看所有电子邮件数据 数据视图。 用一个拼图片点击下放, 上面写着:

Component tables screenshot

  1. 电子邮件表导航到您的 Convex 仪表板 ~ 数据 。 选择 resend 从组件下移,然后选择 emails 页:1 显示所有 具有当前状态的电子邮件、收件人、主题和跟踪 资料.

  2. 交付事件表: 导航到组件 resend → deliveryEvents 页:1 本表存储所有从 Ergine 收到的 Webhook 事件 重新发送,包括:

    • emailId: 链接到电子邮件表格中的电子邮件
    • resendId: 重新发送电子邮件的ID
    • eventType:事件类型(例如, email.delivered, (中文(简体) ), email.bounced, (中文(简体) ), email.opened, (中文(简体) ), email.clicked, (中文(简体) ), email.complained(中文(简体) )
    • createdAt: 事件发生时
    • message: 其他细节(例如弹出理由)

这对调试传送问题、查看电子邮件历史和 知道你发的每封邮件都发生了什么.

保留数据

此组件保留"已定稿"(交付,取消,回弹)电子邮件. 这是 你有责任在自己的日程上清除这些邮件 你们可以跑 cleanupOldEmails 财务报告和审定财务报表 cleanupAbandonedEmails 从仪表板,在 在函数运行器中“ resend” 组件标签, 或设置 cron 任务 .

如果没有通过参数, 它默认删除超过7天的电子邮件 .

如果你不关心历史邮件状况, 建议的方法是 使用 curon 工作,如下所示:

// in convex/crons.ts
import { cronJobs } from "convex/server";
import { components, internal } from "./_generated/api.js";
import { internalMutation } from "./_generated/server.js";

const crons = cronJobs();
crons.interval(
  "Remove old emails from the resend component",
  { hours: 1 },
  internal.crons.cleanupResend,
);

const ONE_WEEK_MS = 7 * 24 * 60 * 60 * 1000;
export const cleanupResend = internalMutation({
  args: {},
  handler: async (ctx) => {
    await ctx.scheduler.runAfter(0, components.resend.lib.cleanupOldEmails, {
      olderThan: ONE_WEEK_MS,
    });
    await ctx.scheduler.runAfter(
      0,
      components.resend.lib.cleanupAbandonedEmails,
      // These generally indicate a bug, so keep them around for longer.
      { olderThan: 4 * ONE_WEEK_MS },
    );
  },
});

export default crons;

使用反应邮件

你用得着 反应电子邮件 生成您的 HTML 从JSX.

首先安装 依赖关系数字 :

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

然后在您的 Convex 目录中创建一个新的.tsx 文件, 例如 . /convex/emails.tsx数字 :

// IMPORTANT: this is a Convex Node Action
"use node";
import { action } from "./_generated/server";
import { render, pretty } from "@react-email/render";
import { Button, Html } from "@react-email/components";
import { components } from "./_generated/api";
import { Resend } from "@convex-dev/resend";

export const resend: Resend = new Resend(components.resend, {
  testMode: false,
});

export const sendEmail = action({
  args: {},
  handler: async (ctx, args) => {
    // 1. Generate the HTML from your JSX
    // This can come from a custom component in your /emails/ directory
    // if you would like to view your templates locally. For more info see:
    // https://react.email/docs/getting-started/manual-setup#5-run-locally
    const html = await pretty(
      await render(
        <Html>
          <Button
            href="https://example.com"
            style={{ background: "#000", color: "#fff", padding: "12px 20px" }}
          >
            Click me
          </Button>
        </Html>,
      ),
    );

    // 2. Send your email as usual using the component
    await resend.sendEmail(ctx, {
      from: "Me <[email protected]>",
      to: "[email protected]",
      subject: "Hi there",
      html,
    });
  },
});

[尖叫声] React Email 需要一些节点依赖, 因此它必须在 Convex 中运行 节点动作 而不是常规行动.

手动发送电子邮件, 例如附件

如果您需要组件不提供的东西( 这是当前) 受Resend中的批量 API 支持的限制,您可以发送电子邮件 手动使用 sendEmailManually不同 sendEmail 编辑电子邮件 并分批地通过 /emails/batch 终点, sendEmailManually 调用调用 /emails 直接结束点而不排队。 这给你 对电子邮件发送过程的精细控制, 同时仍然跟踪它 使用组件状态和 Webhook APIs 进度.

import { components, internal } from "./_generated/api";
import { internalAction } from "./_generated/server";
import { Resend as ResendComponent } from "@convex-dev/resend";
import { Resend } from "resend";

const resendSdk = new Resend("re_xxxxxxxxx");

export const resend = new ResendComponent(components.resend, {});

export const sendManualEmail = internalAction({
  args: {},
  handler: async (ctx, args) => {
    const from = "Acme <[email protected]>";
    const to = ["[email protected]"];
    const subject = "hello world";
    const html = "<p>it works!</p>";

    const emailId = await resend.sendEmailManually(
      ctx,
      { from, to, subject },
      async (emailId) => {
        const {data, error} = await resendSdk.emails.send({
          from,
          to,
          subject,
          html,
          headers: {
            "Idempotency-Key": emailId,
          },
        });
        if (error) {
          throw new Error(`[Email] Failed to send: ${error.message}`);
        }
        return data.id!;
      },
    );
  },
});

使用 sendEmailManually 当您需要批量 API 不支持的特性时, 例如附件,或当您想立即发送电子邮件时,不带 等待分批系统.

版本与发布记录

@convex-dev/resend 共发布 32 个版本,首次发布于 2025/06/14;过去 12 个月发布了 11 个版本。

版本发布日期距今
0.2.10latest2026/10/2318 天前
0.2.92026/10/101 个月前
0.2.82026/09/022 个月前
0.2.72026/08/222 个月前
0.2.62026/07/283 个月前
0.2.52026/06/174 个月前

其他发布通道:alpha → 0.1.6-alpha.1。

关于 @convex-dev/resend 的常见问题

@convex-dev/resend 是什么?

Convex 的再发送组件 .

如何安装 @convex-dev/resend?

在项目目录运行 npm install @convex-dev/resend,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:convex(^1.43.0)、convex-helpers(^0.1.106)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@convex-dev/resend 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@convex-dev/resend 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@convex-dev/resend 可以商用吗?

@convex-dev/resend 使用 Apache-2.0 许可。宽松许可:允许商业使用、修改和再分发,并附带明确的专利授权;分发时需保留许可与 NOTICE 文件,修改过的文件要注明改动。以上为概括,不构成法律意见,请以许可原文为准。

@convex-dev/resend 的下载量有多少?

根据 npm 官方下载统计,@convex-dev/resend 在 2026/10/11 – 2026/11/09 这 30 天内被下载 842,038 次,日均约 28,068 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@convex-dev/resend 还在维护吗?

最新版本 0.2.10 发布于 2026/10/23(18 天前);至今共发布 32 个版本,其中过去 12 个月发布了 11 个;首次发布于 2025/06/14。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。