关于 send-email-to-mailing-list
这是一个便携式 Claude Skill,可从服务端 JavaScript/TypeScript 项目或 Claude Code 工作流向邮件列表发送通知。支持模板和原始内容,并可用 CLI 先验证请求而不实际发送。
主要功能
- 01从服务端代码发送邮件列表通知
- 02使用模板或原始文本与 HTML
- 03通过 CLI 发送单次通知
- 04用 dry-run 验证请求
适用场景
- 01通知邮件列表用户注册或账单事件
- 02报告后台任务错误和运维告警
- 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 位收件人)
前提条件
-
在目标项目中安装辅助包:
bun add @schemavaults/send-email # or: npm install @schemavaults/send-email -
在代码运行的所有环境中设置两个环境变量(本地开发、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 ...")。 -
第三个环境变量为可选项:
SCHEMAVAULTS_APP_ENVIRONMENT="production"|"development"|"staging"。如果未设置,辅助函数会默认使用production,并将请求发送到生产环境邮件服务器。仅当你明确要访问非生产环境时才设置此变量。 -
只能从服务端代码调用——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><bullet 1></li><li><bullet 2></li><li><bullet 3></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><bullet 1></li>" +
"<li><bullet 2></li>" +
"<li><bullet 3></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() 读取该变量。
将此技能添加到其他项目
- 将此文件复制到目标项目的
.claude/skills/文件夹中。 - 在目标项目中安装辅助程序包:
bun add @schemavaults/send-email - 通过项目常用的密钥管理方式填充这两个环境变量(例如,开发时使用
.env.local,生产环境使用托管服务提供商的密钥存储):SCHEMAVAULTS_MAIL_API_KEY=svlts_mail_pk_... SCHEMAVAULTS_MAILING_LIST_ID=00000000-0000-0000-0000-000000000000 - 提交技能文件。该仓库中的下一个 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——程序包入口点;列出所有导出符号。