mcpField
S
send-email-to-mailing-list

send-email-to-mailing-list

github.com/schemavaults生产力095 次安装2 周前更新
代码仓库

关于 send-email-to-mailing-list

这是一个便携式 Claude Skill,可从服务端 JavaScript/TypeScript 项目或 Claude Code 工作流向邮件列表发送通知。支持模板和原始内容,并可用 CLI 先验证请求而不实际发送。

主要功能

  1. 01从服务端代码发送邮件列表通知
  2. 02使用模板或原始文本与 HTML
  3. 03通过 CLI 发送单次通知
  4. 04用 dry-run 验证请求

适用场景

  1. 01通知邮件列表用户注册或账单事件
  2. 02报告后台任务错误和运维告警
  3. 03由 Claude Code 发送工作流完成通知

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/schemavaults/send-email --skill send-email-to-mailing-list

安装后在 Claude Code 中输入/send-email-to-mailing-list确认已加载。

详细介绍

向邮件列表发送邮件

此技能教会 Claude 如何向邮件列表发送邮件,既可以(a)从导入 @schemavaults/send-email 的任意服务端 TypeScript/JavaScript 项目发送,也可以(b)直接从 Claude Code 会话发送——例如,在任务结束时发送一封“我刚完成这项工作流”的通知。在这两种情况下,sendEmailToMailingList() 辅助函数都会封装 SchemaVaults 邮件服务器的 POST /api/send 路由,并自动从环境变量中解析 API 密钥。此技能独立且可移植——将它放入任意项目的 .claude/skills/ 文件夹即可使用。

何时使用此技能

此技能适用于两种不同的用例:

(a)应用程序代码需要向邮件列表受众发送通知。 例如:

  • 新用户注册/首次购买事件
  • 后台作业或 cron 任务中未处理的错误
  • 计费/订阅生命周期事件(试用即将结束、付款失败)
  • 运维提醒(部署成功、触发速率限制、健康检查失败)
  • 任何面向邮件列表受众的临时“请知悉,刚刚发生了此事”消息

(b)Claude Code 本身想在工作流结束时通知邮件列表。 例如:

  • Claude 刚完成一项功能的实现并推送了分支。
  • Claude 完成了 PR 审查并发布了评论。
  • 长时间运行的构建、迁移或 CI 任务已完成(成功或失败)。
  • Claude 正在执行的定时维护脚本已完成。

有关用例(b),请参阅下方的“用法 -- Claude Code 工作流后通知”部分。

不要将其用于:

  • 向单个最终用户发送邮件(请改用 sendEmail() 并传入电子邮件地址字符串)
  • 客户端/浏览器代码(API 密钥属于机密)
  • 每次发送超过 50 位收件人的大批量群发(邮件服务器限制每次发送最多 50 位收件人)

前提条件

  1. 在目标项目中安装辅助包:

    bun add @schemavaults/send-email
    # or: npm install @schemavaults/send-email
    
  2. 在代码运行的所有环境中设置两个环境变量(本地开发、CI、生产环境):

    • SCHEMAVAULTS_MAIL_API_KEY -- 从邮件服务器的 api_keys 表中签发的 Bearer 令牌。始终以 svlts_mail_pk_ 开头。请像对待其他机密信息一样妥善保管;切勿提交到版本库,也不要发送到浏览器。
    • SCHEMAVAULTS_MAILING_LIST_ID -- 邮件服务器 MAILING_LISTS 表中目标邮件列表的 UUID。

    如果不直接传入值,则两者均为必填项——只要缺少其中任意一个,辅助函数就会抛出 Error("Failed to load ... from environment variable ...")。

  3. 第三个环境变量为可选项: SCHEMAVAULTS_APP_ENVIRONMENT = "production" | "development" | "staging"。如果未设置,辅助函数会默认使用 production,并将请求发送到生产环境邮件服务器。仅当你明确要访问非生产环境时才设置此变量。

  4. 只能从服务端代码调用——API 路由、服务端操作、cron 处理程序、后台工作进程。切勿从 React 客户端组件或浏览器代码包调用。

用法 -- 模板形式(推荐)

如果邮件服务器目录中已有 React Email 模板,请通过 template_id 引用该模板,以便在邮件服务器上完成渲染(HTML + 纯文本)。使用 @schemavaults/send-email 中的 listEmailTemplates()(或参阅 list-email-templates 技能)来查找可用的模板 ID。

import { sendEmailToMailingList } from "@schemavaults/send-email";

export async function notifyMailingListOfSignup(userName: string): Promise<void> {
  await sendEmailToMailingList({
    body: {
      subject: `New signup: ${userName}`,
      message: {
        template_id: "<template-id-from-GET-/api/templates>",
        template_props: {
          /* prop shape per the template's description field */
        },
      },
    },
  });
}

**如果没有适合通知需求的已注册模板,**请改用下方的原始 text/html 形式,而不是勉强套用不匹配的模板。

用法 -- 原始 HTML/text 形式(临时通知)

对于无需专门创建 React Email 模板的一次性通知,可直接提供 text 和 html。这两个字段都是必填项。

import { sendEmailToMailingList } from "@schemavaults/send-email";

export async function notifyMailingListOfError(err: Error, context: string): Promise<void> {
  const subject = `[alert] ${context}: ${err.message}`;
  const text =
    `An error occurred in ${context}.\n\n` +
    `Message: ${err.message}\n\n` +
    `Stack:\n${err.stack ?? "(no stack)"}\n`;
  const html =
    `<p>An error occurred in <code>${context}</code>.</p>` +
    `<p><strong>Message:</strong> ${err.message}</p>` +
    `<pre>${err.stack ?? "(no stack)"}</pre>`;

  await sendEmailToMailingList({
    body: { subject, message: { text, html } },
  });
}

如果用户提供的值可能包含 </>/&,在将其嵌入 html 前请先转义——邮件服务器不会替你清理这些内容。

用法 -- 显式传入邮件列表 ID

默认情况下,sendEmailToMailingList 会从 SCHEMAVAULTS_MAILING_LIST_ID 环境变量读取邮件列表 UUID。你可以在每次调用时覆盖此值:

await sendEmailToMailingList({
  mailingListId: "00000000-0000-0000-0000-000000000000",
  body: {
    subject: "Hello from a specific list",
    message: { text: "Hello", html: "<p>Hello</p>" },
  },
});

用法 -- CLI(推荐用于一次性/临时发送)

@schemavaults/send-email 附带一个名为 schemavaults-send-email 的二进制文件,用于封装同一个辅助函数。对于任何一次性发送——手动通知、快速冒烟测试、bash 定时任务,或 Claude Code 在工作流结束时发出的一封邮件——CLI 都是最简单的方式。无需 /tmp/ 脚本,也无需 bun run。

# Raw text/html (both required)
bunx schemavaults-send-email send-to-mailing-list \
  --subject "[ops] nightly backup finished" \
  --text  "Backup completed at $(date -u +%FT%TZ). 0 errors." \
  --html  "<p>Backup completed at $(date -u +%FT%TZ). <strong>0 errors.</strong></p>"

# Template-based
bunx schemavaults-send-email send-to-mailing-list \
  --subject "Welcome aboard, Alice" \
  --template-id welcome-email \
  --template-props '{"name":"Alice"}'

# Override the mailing list per-call
bunx schemavaults-send-email send-to-mailing-list \
  --mailing-list-id 00000000-0000-0000-0000-000000000000 \
  --subject "..." --text "..." --html "..."

# Route through a specific mail-server transport (global flag, before the subcommand)
bunx schemavaults-send-email --transport smtp-primary send-to-mailing-list \
  --subject "..." --text "..." --html "..."

# Long bodies: read from files instead of inline strings
bunx schemavaults-send-email send-to-mailing-list \
  --subject "weekly digest" \
  --text-file /tmp/digest.txt \
  --html-file /tmp/digest.html

# Or supply the entire request body as a JSON file (validated server-side)
bunx schemavaults-send-email send-to-mailing-list --body-file /tmp/payload.json

(如果无法使用 bun,请将 bunx 替换为 npx。)CLI 与辅助函数一样,会从环境变量读取 SCHEMAVAULTS_MAIL_API_KEY 和 SCHEMAVAULTS_MAILING_LIST_ID;失败时会以单行错误信息返回非零退出码,收到 mail-server 的成功响应(200)时则返回 0。

运行 bunx schemavaults-send-email send-to-mailing-list --help 查看完整的标志参考。

发送前验证(--dry-run)

由于发送到邮件列表会将邮件群发给所有订阅者,切勿通过实际发送来验证请求。使用 --dry-run,让请求经过服务器验证并往返检查 Zod body、template_props 结构以及 API 密钥/邮件列表的范围,而不会实际发送任何内容:

bunx schemavaults-send-email send-to-mailing-list --dry-run \
  --subject "Welcome aboard, Alice" \
  --template-id welcome-email \
  --template-props '{"name":"Alice"}'

dry-run 成功时会打印 [dry-run] mailing-list request validated; no email sent. 并以退出码 0 结束。请求格式错误时会以非零退出码结束,并显示服务器返回的验证错误。

用法 -- Claude Code 工作流结束通知

Claude 本身可以在依赖 @schemavaults/send-email 的任何仓库中,使用此技能在工作流结束时向邮件列表发送一次性通知(此仓库已经如此配置)。

首选:直接调用 CLI

对于大多数工作流结束通知(几句话加简短的项目符号列表),CLI 是合适的工具——只需一条 shell 命令,无需临时文件:

bunx schemavaults-send-email send-to-mailing-list \
  --subject "[claude-code] workflow finished: <short description>" \
  --text "$(printf 'Claude just finished a workflow.\n\nSummary:\n- <bullet 1>\n- <bullet 2>\n- <bullet 3>\n')" \
  --html "$(printf '<p>Claude just finished a workflow.</p><p><strong>Summary:</strong></p><ul><li>&lt;bullet 1&gt;</li><li>&lt;bullet 2&gt;</li><li>&lt;bullet 3&gt;</li></ul>')"

将 <short description> 和项目符号占位内容替换为具体摘要。主题长度应控制在约 70 个字符以内,正文应便于快速浏览(通常 3-5 个项目符号就足够了)。非零退出码表示辅助函数抛出了错误——应在给用户的摘要中说明错误,而不是悄悄重试。

备用方案:编写 /tmp/ 脚本

只有在正文足够长,或包含足够多的模板内容,以至于在 shell 中处理字符串引号很麻烦时,才使用脚本形式(例如多段 HTML、动态数据组装、条件内容):

// /tmp/send-notification-after-workflow.ts
import { sendEmailToMailingList } from "@schemavaults/send-email";

async function main(): Promise<void> {
  await sendEmailToMailingList({
    body: {
      subject: "[claude-code] workflow finished: <short description>",
      message: {
        text:
          "Claude just finished a workflow.\n\n" +
          "Summary:\n" +
          "- <bullet 1>\n" +
          "- <bullet 2>\n" +
          "- <bullet 3>\n",
        html:
          "<p>Claude just finished a workflow.</p>" +
          "<p><strong>Summary:</strong></p>" +
          "<ul>" +
          "<li>&lt;bullet 1&gt;</li>" +
          "<li>&lt;bullet 2&gt;</li>" +
          "<li>&lt;bullet 3&gt;</li>" +
          "</ul>",
      },
    },
  });
  console.log("[notify] sent");
}

main().catch((err) => {
  console.error("[notify] failed:", err);
  process.exit(1);
});

从仓库根目录运行,以便 Bun 通过仓库的 node_modules/ 解析 @schemavaults/send-email:

bun run /tmp/send-notification-after-workflow.ts
何时触发

在工作流结束时发送恰好一条通知,并确保所有提交和推送都已完成,这样邮件才会反映最终状态。

注意事项
  • Claude 的进程中必须设置环境变量 SCHEMAVAULTS_MAIL_API_KEY 和 SCHEMAVAULTS_MAILING_LIST_ID。如果缺少这些变量,辅助函数(以及 CLI)会抛出清晰的错误——应向用户报告,而不是盲目重试。
  • 每个工作流只发送一条通知,而不是每个步骤一条。 如果工作流没有产生有意义的结果(例如“用户提了一个问题,Claude 作了回答”),则完全跳过通知。不要让收件箱变得嘈杂。
  • 工作尚未完成时不要发送通知。 先推送,再通知。
  • 如果用户尚未明确同意接收工作流结束通知,请在发送前征求同意。发送邮件会产生其他人可见的副作用;对于用户未要求发送邮件的任务,不要悄悄发送。
  • 切勿向邮件列表发送空白或“测试”邮件来验证请求。 请使用 --dry-run(CLI)或 dryRun: true(辅助函数 body)。mail-server 会在不向受众发送邮件的情况下验证完整请求,包括 template_props 结构。误发的实际测试邮件会送达所有订阅者。

请求 body 结构

sendEmailToMailingList 接受 Omit<SendEmailRequestBody, "to" | "cc" | "bcc">——受众是邮件列表,因此有意不允许使用 to、cc 和 bcc。允许的字段:

type MailingListNotificationBody = {
  subject: string;
  message:
    | { template_id: string; template_props?: unknown }
    | { text: string; html: string };
  from?: string;      // defaults to the mail-server's configured sender
  replyTo?: string;   // optional reply-to override
  dryRun?: boolean;   // server validates without dispatching
  transport?: string; // which mail-server transport to deliver with
};

// Full call signature:
type ISendEmailToMailingListOpts = {
  body: MailingListNotificationBody;
  mailingListId?: string; // override SCHEMAVAULTS_MAILING_LIST_ID
  bearerToken?: string;   // override SCHEMAVAULTS_MAIL_API_KEY; rarely needed
  mailServerUrl?: string; // override the server origin; rarely needed
  environment?: "production" | "development" | "staging";
  dryRun?: boolean;       // convenience; sets body.dryRun
  transport?: string;     // convenience; sets body.transport
};

错误处理

该辅助函数会在收到任何非 200 响应时抛出错误——如果失败的通知不应中断调用方的主要流程,请始终使用 try/catch 包裹调用:

try {
  await sendEmailToMailingList({
    body: {
      subject: `New signup: ${userName}`,
      message: { text, html },
    },
  });
} catch (notifyErr) {
  console.error("[notify] failed to send mailing list notification", notifyErr);
}

常见失败情况:

错误原因
Failed to load API key from environment variable 'SCHEMAVAULTS_MAIL_API_KEY'运行时环境中未设置环境变量(或其值为空字符串)。
Failed to load mailing list ID from environment variable 'SCHEMAVAULTS_MAILING_LIST_ID'运行时环境中未设置环境变量(或其值为空字符串)。
Bad request body to send email with!body 与架构不匹配——通常是缺少 subject、缺少 text/html 字段对,或包含未知字段。
Invalid or revoked API key.(HTTP 401)SCHEMAVAULTS_MAIL_API_KEY 错误、已过期或已撤销。
This API key is not permitted...(HTTP 403)API 密钥已加入允许列表,但对应的邮件列表与目标邮件列表不同。
Failed to parse request body!(HTTP 400)服务端 Zod 解析失败;通常是模板的 template_props 结构不匹配。
未知传输方式错误(HTTP 400)transport 指定了邮件服务未配置的传输方式。客户端只检查名称格式是否正确;该名称是否存在由服务端决定。

环境目标

默认情况下,该辅助函数会解析 production 环境的邮件服务 URL。如需明确指定 staging 或 development 环境:

await sendEmailToMailingList({
  environment: "development",
  body: {
    subject: "dev smoke test",
    message: { template_id: "my-test-email", template_props: { name: "test" } },
  },
});

或者,在进程级别设置 SCHEMAVAULTS_APP_ENVIRONMENT——当未传入 opts.environment 时,该辅助函数会通过 @schemavaults/app-definitions 中的 getAppEnvironment() 读取该变量。

将此技能添加到其他项目

  1. 将此文件复制到目标项目的 .claude/skills/ 文件夹中。
  2. 在目标项目中安装辅助程序包:
    bun add @schemavaults/send-email
    
  3. 通过项目常用的密钥管理方式填充这两个环境变量(例如,开发时使用 .env.local,生产环境使用托管服务提供商的密钥存储):
    SCHEMAVAULTS_MAIL_API_KEY=svlts_mail_pk_...
    SCHEMAVAULTS_MAILING_LIST_ID=00000000-0000-0000-0000-000000000000
    
  4. 提交技能文件。该仓库中的下一个 Claude Code 会话将自动发现此技能。

参考

已安装程序包中的源文件(node_modules/@schemavaults/send-email/dist/)——需要权威信息时请查阅这些文件:

  • send-email-to-mailing-list.{d.ts,js}——sendEmailToMailingList() 辅助函数及其 ISendEmailToMailingListOpts 接口。
  • send-email.{d.ts,js}——底层的 sendEmail() 实现,包括 getSchemaVaultsMailApiKey() 和服务器 URL 解析。
  • send-email-request-body-schema.{d.ts,js}——用于校验请求体的 Zod 架构(createSendEmailRequestBodySchema),客户端辅助函数和邮件服务路由都会使用该架构。
  • index.d.ts——程序包入口点;列出所有导出符号。

评论

支持 Markdown