send-email-to-mailing-list

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Send Email to Mailing List

发送邮件到邮件列表

This skill teaches Claude how to send an email to a mailing list, either (a) from any server-side TypeScript/JavaScript project that imports
@schemavaults/send-email
, or (b) directly from a Claude Code session — for example, to send a "I just finished this workflow" notification at the end of a task. In both cases the
sendEmailToMailingList()
helper wraps the SchemaVaults mail-server
POST /api/send
route and automatically resolves the API key from environment variables. The skill is self-contained and portable — drop it into any project's
.claude/skills/
folder and you're done.
本技能教Claude如何向邮件列表发送邮件,两种方式可选:(a) 在导入了
@schemavaults/send-email
的服务端TypeScript/JavaScript项目中发送;(b) 直接在Claude Code会话中发送——例如,在任务结束时发送“我已完成此工作流”的通知。无论哪种方式,
sendEmailToMailingList()
辅助函数都会封装SchemaVaults邮件服务器的
POST /api/send
路由,并自动从环境变量中解析API密钥。该技能独立且可移植,只需将其放入任意项目的
.claude/skills/
文件夹即可使用。

When to use this skill

使用场景

There are two distinct use cases. Either fits this skill:
(a) Application code needs to send a notification to a mailing list audience. For example:
  • New user signup / first-purchase events
  • Unhandled errors in background jobs or cron tasks
  • Billing / subscription lifecycle events (trial ending, payment failed)
  • Ops alerts (deploy succeeded, rate-limit tripped, healthcheck failed)
  • Any ad-hoc "FYI, this just happened" message intended for a mailing list audience
(b) Claude Code itself wants to notify a mailing list at the end of a workflow. For example:
  • Claude just finished implementing a feature and pushed the branch.
  • Claude finished reviewing a PR and posted comments.
  • A long-running build, migration, or CI task finished (success or failure).
  • A scheduled maintenance script Claude was orchestrating completed.
For use case (b), see the "Usage -- Claude Code post-workflow notification" section below.
Do not use it for:
  • Sending to individual end users (use
    sendEmail()
    with an email string instead)
  • Client-side / browser code (the API key is a secret)
  • High-volume broadcasts beyond 50 recipients per send (the mail-server caps each send call at 50 recipients)
本技能适用于两种截然不同的场景:
(a) 应用代码需要向邮件列表受众发送通知。例如:
  • 新用户注册 / 首次购买事件
  • 后台任务或定时任务中的未处理错误
  • 账单 / 订阅生命周期事件(试用即将结束、支付失败)
  • 运维告警(部署成功、触发速率限制、健康检查失败)
  • 任何针对邮件列表受众的临时“仅供参考,刚刚发生了这件事”消息
(b) Claude Code自身需要在工作流结束时通知邮件列表。例如:
  • Claude刚完成一个功能的实现并推送了分支
  • Claude完成了PR评审并发布了评论
  • 长时间运行的构建、迁移或CI任务完成(成功或失败)
  • Claude编排的定时维护脚本执行完毕
对于场景(b),请参阅下方的“用法——Claude Code工作流结束后通知”章节。
请勿用于以下场景:
  • 向单个终端用户发送邮件(请改用带邮箱字符串参数的
    sendEmail()
  • 客户端/浏览器代码(API密钥是敏感信息)
  • 单次发送超过50个收件人的大规模广播(邮件服务器对每次调用的收件人数上限为50)

Prerequisites

前提条件

  1. Install the helper package in the target project:
    bash
    bun add @schemavaults/send-email
    # or: npm install @schemavaults/send-email
  2. Set two environment variables wherever the code runs (local dev, CI, production):
    • SCHEMAVAULTS_MAIL_API_KEY
      -- Bearer token issued from the mail-server's
      api_keys
      table. Always starts with
      svlts_mail_pk_
      . Treat it like any other secret; never commit it, never ship it to browsers.
    • SCHEMAVAULTS_MAILING_LIST_ID
      -- UUID of the target mailing list from the mail-server's
      MAILING_LISTS
      table.
    Both are mandatory when not passing values directly -- the helper throws
    Error("Failed to load ... from environment variable ...")
    if either is missing.
  3. Optional third env var:
    SCHEMAVAULTS_APP_ENVIRONMENT
    =
    "production"
    |
    "development"
    |
    "staging"
    . If unset, the helper falls back to
    production
    and targets the production mail-server. Only set this when you explicitly want to hit a non-prod environment.
  4. Call only from server-side code -- API routes, server actions, cron handlers, background workers. Never from a React client component or browser bundle.
  1. 在目标项目中安装辅助包
    bash
    bun add @schemavaults/send-email
    # 或: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路由、服务端动作、定时任务处理器、后台工作进程。绝不要从React客户端组件或浏览器包中调用。

Usage -- template form (preferred)

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

When a React Email template already exists in the mail-server catalog, reference it by
template_id
so the rendering (HTML + plain text) happens on the mail-server. Use
listEmailTemplates()
from
@schemavaults/send-email
(or see the
list-email-templates
skill) to discover available template IDs.
ts
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 */
        },
      },
    },
  });
}
If none of the registered templates fits your notification, use the raw
text
/
html
form below instead of trying to bend a mismatched template.
当邮件服务器目录中已存在React Email模板时,可通过
template_id
引用它,这样渲染(HTML + 纯文本)会在邮件服务器端完成。使用
@schemavaults/send-email
中的
listEmailTemplates()
(或查看
list-email-templates
技能)来发现可用的模板ID。
ts
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: {
          /* 属性格式需符合模板的description字段定义 */
        },
      },
    },
  });
}
如果没有已注册的模板适合你的通知,请改用下方的原生
text
/
html
形式,不要强行使用不匹配的模板。

Usage -- raw HTML/text form (ad-hoc)

用法——原生HTML/纯文本形式(临时场景)

For one-off notifications where spinning up a dedicated React Email template is overkill, supply
text
and
html
directly. Both fields are required.
ts
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 } },
  });
}
Escape user-supplied values before embedding them in
html
if they can contain
<
/
>
/
&
-- the mail-server does not sanitize this for you.
对于无需专门创建React Email模板的一次性通知,可直接提供
text
html
内容。两个字段均为必填项
ts
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}.\
\
` +
    `Message: ${err.message}\
\
` +
    `Stack:\
${err.stack ?? "(no stack)"}\
`;
  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
之前进行转义——邮件服务器不会为你执行此清理操作。

Usage -- passing a mailing list ID explicitly

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

By default
sendEmailToMailingList
reads the mailing list UUID from the
SCHEMAVAULTS_MAILING_LIST_ID
env var. You can override this per-call:
ts
await sendEmailToMailingList({
  mailingListId: "00000000-0000-0000-0000-000000000000",
  body: {
    subject: "Hello from a specific list",
    message: { text: "Hello", html: "<p>Hello</p>" },
  },
});
默认情况下,
sendEmailToMailingList
会从
SCHEMAVAULTS_MAILING_LIST_ID
环境变量中读取邮件列表UUID。你可以在每次调用时覆盖此值:
ts
await sendEmailToMailingList({
  mailingListId: "00000000-0000-0000-0000-000000000000",
  body: {
    subject: "Hello from a specific list",
    message: { text: "Hello", html: "<p>Hello</p>" },
  },
});

Usage -- CLI (preferred for one-off / ad-hoc sends)

用法——CLI(适合一次性/临时发送)

@schemavaults/send-email
ships a
schemavaults-send-email
binary that wraps the same helper. For any one-off send -- a manual notification, a quick smoke test, a
bash
cron entry, or Claude Code firing off a single end-of-workflow email -- the CLI is the simplest path. No
/tmp/
script, no
bun run
.
bash
undefined
@schemavaults/send-email
包附带了一个
schemavaults-send-email
二进制文件,它封装了相同的辅助函数。对于任何一次性发送——手动通知、快速冒烟测试、
bash
定时任务,或Claude Code发送工作流结束邮件——CLI是最简单的方式,无需创建
/tmp/
脚本或使用
bun run
bash
undefined

Raw text/html (both required)

原生文本/HTML(均为必填项)

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>"
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"}'
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 "..."
bunx schemavaults-send-email send-to-mailing-list \ --mailing-list-id 00000000-0000-0000-0000-000000000000 \ --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
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)

或通过JSON文件提供整个请求体(服务端会验证)

bunx schemavaults-send-email send-to-mailing-list --body-file /tmp/payload.json

(Substitute `npx` for `bunx` if `bun` is unavailable.) The CLI reads `SCHEMAVAULTS_MAIL_API_KEY` and `SCHEMAVAULTS_MAILING_LIST_ID` from the environment exactly like the helper, exits non-zero with a one-line error on failure, and exits `0` on a successful 200 from the mail-server.

Run `bunx schemavaults-send-email send-to-mailing-list --help` for the full flag reference.
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`,失败时会返回非零退出码并输出一行错误信息,成功从邮件服务器收到200响应时返回0。

运行`bunx schemavaults-send-email send-to-mailing-list --help`查看完整的参数说明。

Validating before sending (
--dry-run
)

发送前验证(
--dry-run

Because a mailing-list send fans out to every subscriber, never use a real send to validate your request. Use
--dry-run
to round-trip Zod body +
template_props
shape + API-key/mailing-list scoping through the server without dispatching anything:
bash
bunx schemavaults-send-email send-to-mailing-list --dry-run \
  --subject "Welcome aboard, Alice" \
  --template-id welcome-email \
  --template-props '{"name":"Alice"}'
A successful dry-run prints
[dry-run] mailing-list request validated; no email sent.
and exits
0
. A malformed request exits non-zero with the server's validation error.
由于邮件列表发送会扩散到每个订阅者,绝不要使用真实发送来验证请求。请使用
--dry-run
参数,在不发送任何邮件的情况下,让服务器验证Zod请求体 +
template_props
格式 + API密钥/邮件列表权限:
bash
bunx schemavaults-send-email send-to-mailing-list --dry-run \\
  --subject "Welcome aboard, Alice" \\
  --template-id welcome-email \\
  --template-props '{"name":"Alice"}'
成功的试运行会打印
[dry-run] mailing-list request validated; no email sent.
并返回0。格式错误的请求会返回非零退出码并输出服务器的验证错误信息。

Usage -- Claude Code post-workflow notification

用法——Claude Code工作流结束后通知

Claude itself can use this skill to send a one-shot notification to a mailing list at the end of a workflow in any repo that depends on
@schemavaults/send-email
(this repo already does).
Claude自身可以使用此技能,在任何依赖
@schemavaults/send-email
的仓库(本仓库已依赖)的工作流结束时,向邮件列表发送一次性通知。

Preferred: invoke the CLI directly

推荐方式:直接调用CLI

For most end-of-workflow notifications (a few sentences plus a short bullet list) the CLI is the right tool -- one shell command, no scratch file:
bash
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>')"
Replace the
<short description>
and bullet placeholders with a concrete summary. Keep the subject under ~70 characters and the body scannable (3-5 bullets is usually enough). A non-zero exit means the helper threw -- surface the error in your summary to the user rather than retrying silently.
对于大多数工作流结束通知(几句话加简短项目符号列表),CLI是合适的工具——只需一条shell命令,无需临时文件:
bash
bunx schemavaults-send-email send-to-mailing-list \\
  --subject "[claude-code] workflow finished: <short description>" \\
  --text "$(printf 'Claude just finished a workflow.\
\
Summary:\
- <bullet 1>\
- <bullet 2>\
- <bullet 3>\
')" \\
  --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个项目符号足够)。非零退出码表示辅助函数抛出了错误——请在摘要中向用户显示错误信息,不要静默重试。

Fallback: write a
/tmp/
script

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

Reach for the script form only when the body is large enough or templated enough that string-quoting in shell is awkward (e.g. multi-paragraph HTML, dynamic data assembly, conditional content):
ts
// /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);
});
Run from the repo root so Bun resolves
@schemavaults/send-email
through the repo's
node_modules/
:
bash
bun run /tmp/send-notification-after-workflow.ts
仅当内容过长或模板化程度过高,导致在shell中引用字符串过于麻烦时(例如多段落HTML、动态数据组装、条件内容),才使用脚本形式:
ts
// /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.\
\
" +
          "Summary:\
" +
          "- <bullet 1>\
" +
          "- <bullet 2>\
" +
          "- <bullet 3>\
",
        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
bash
bun run /tmp/send-notification-after-workflow.ts

When to trigger this

触发时机

Send exactly one notification at the end of a workflow, after all commits and pushes have landed, so the email reflects the final state.
在工作流结束时发送恰好一条通知,确保所有提交和推送都已完成,这样邮件才能反映最终状态。

Cautions

注意事项

  • The env vars
    SCHEMAVAULTS_MAIL_API_KEY
    and
    SCHEMAVAULTS_MAILING_LIST_ID
    must be set in Claude's process. If they're missing, the helper (and CLI) throws a clear error -- report it to the user instead of retrying blindly.
  • One notification per workflow, not per step. If a workflow had no meaningful outcome (e.g. "user asked a question, Claude answered"), skip the notification entirely. The inbox should not become chatty.
  • Do not send the notification before the work is finished. Push first, notify second.
  • Ask before sending if the user hasn't explicitly opted in to post-workflow notifications. Sending email is a side effect visible to other humans; don't do it silently on tasks where the user hasn't asked for it.
  • Never send a blank or "test" email to a mailing list to validate a request. Use
    --dry-run
    (CLI) or
    dryRun: true
    (helper body). The mail-server validates the full request -- including
    template_props
    shape -- without dispatching to the audience. A misfired real test reaches every subscriber.
  • Claude进程中必须设置环境变量
    SCHEMAVAULTS_MAIL_API_KEY
    SCHEMAVAULTS_MAILING_LIST_ID
    。如果缺失,辅助函数(和CLI)会抛出清晰的错误——请向用户报告,不要盲目重试。
  • 每个工作流仅发送一条通知,而非每个步骤。如果工作流没有有意义的结果(例如“用户提问,Claude回答”),请完全跳过通知。不要让收件箱变得嘈杂。
  • 不要在工作完成前发送通知。先推送,再通知。
  • 如果用户未明确选择接收工作流结束通知,请先询问再发送。发送邮件是会被其他人看到的副作用;不要在用户未要求的任务中静默发送。
  • 绝不要向邮件列表发送空白或“测试”邮件来验证请求。请使用
    --dry-run
    (CLI)或
    dryRun: true
    (辅助函数参数)。邮件服务器会验证完整请求——包括
    template_props
    格式——而不会向受众发送邮件。误发的真实测试邮件会送达每个订阅者。

Request body shape

请求体格式

sendEmailToMailingList
accepts
Omit<SendEmailRequestBody, "to" | "cc" | "bcc">
-- the audience is the mailing list, so
to
,
cc
, and
bcc
are intentionally not allowed. Allowed fields:
ts
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
};

// 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
};
sendEmailToMailingList
接受
Omit<SendEmailRequestBody, "to" | "cc" | "bcc">
类型的参数——受众是邮件列表,因此
to
cc
bcc
是不允许的。允许的字段如下:
ts
type MailingListNotificationBody = {
  subject: string;
  message:
    | { template_id: string; template_props?: unknown }
    | { text: string; html: string };
  from?: string;      // 默认使用邮件服务器配置的发件人
  replyTo?: string;   // 可选的回复地址覆盖
  dryRun?: boolean;   // 服务器验证但不发送邮件
};

// 完整调用签名:
type ISendEmailToMailingListOpts = {
  body: MailingListNotificationBody;
  mailingListId?: string; // 覆盖SCHEMAVAULTS_MAILING_LIST_ID
  bearerToken?: string;   // 覆盖SCHEMAVAULTS_MAIL_API_KEY;很少需要
  mailServerUrl?: string; // 覆盖服务器地址;很少需要
  environment?: "production" | "development" | "staging";
  dryRun?: boolean;       // 便捷参数;设置body.dryRun
};

Error handling

错误处理

The helper throws on any non-200 response -- wrap the call in
try/catch
whenever a failed notification should not break the caller's primary flow:
ts
try {
  await sendEmailToMailingList({
    body: {
      subject: `New signup: ${userName}`,
      message: { text, html },
    },
  });
} catch (notifyErr) {
  console.error("[notify] failed to send mailing list notification", notifyErr);
}
Common failure modes:
ErrorCause
Failed to load API key from environment variable 'SCHEMAVAULTS_MAIL_API_KEY'
Env var not set (or empty string) in the runtime environment.
Failed to load mailing list ID from environment variable 'SCHEMAVAULTS_MAILING_LIST_ID'
Env var not set (or empty string) in the runtime environment.
Bad request body to send email with!
Your
body
does not match the schema -- typically a missing
subject
, missing
text
/
html
pair, or unknown fields.
Invalid or revoked API key.
(HTTP 401)
SCHEMAVAULTS_MAIL_API_KEY
is wrong, expired, or revoked.
This API key is not permitted...
(HTTP 403)
The API key is allowlisted to a different mailing list than the one targeted.
Failed to parse request body!
(HTTP 400)
Server-side Zod parsing failed; usually a template
template_props
shape mismatch.
辅助函数会在任何非200响应时抛出错误——当通知失败不应中断调用方的主流程时,请将调用包裹在
try/catch
中:
ts
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!
请求体不符合 schema——通常是缺少
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
格式不匹配

Environment targeting

环境目标

By default the helper resolves the mail-server URL for the
production
environment. To hit staging or development explicitly:
ts
await sendEmailToMailingList({
  environment: "development",
  body: {
    subject: "dev smoke test",
    message: { template_id: "my-test-email", template_props: { name: "test" } },
  },
});
Or set
SCHEMAVAULTS_APP_ENVIRONMENT
at the process level -- the helper reads it via
getAppEnvironment()
from
@schemavaults/app-definitions
when
opts.environment
is not passed in.
默认情况下,辅助函数会解析
production
环境的邮件服务器URL。要明确指向staging或development环境:
ts
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()
读取该变量。

Adding this skill to another project

将此技能添加到其他项目

  1. Copy this file into the target project's
    .claude/skills/
    folder.
  2. In the target project, install the helper package:
    bash
    bun add @schemavaults/send-email
  3. Populate the two environment variables via the project's normal secret management (e.g.
    .env.local
    for local dev, your hosting provider's secret store for production):
    bash
    SCHEMAVAULTS_MAIL_API_KEY=svlts_mail_pk_...
    SCHEMAVAULTS_MAILING_LIST_ID=00000000-0000-0000-0000-000000000000
  4. Commit the skill file. The next Claude Code session in that repo will automatically discover the skill.
  1. 将此文件复制到目标项目的
    .claude/skills/
    文件夹中。
  2. 在目标项目中安装辅助包:
    bash
    bun add @schemavaults/send-email
  3. 通过项目的常规密钥管理方式设置两个环境变量(例如本地开发使用
    .env.local
    ,生产环境使用托管提供商的密钥存储):
    bash
    SCHEMAVAULTS_MAIL_API_KEY=svlts_mail_pk_...
    SCHEMAVAULTS_MAILING_LIST_ID=00000000-0000-0000-0000-000000000000
  4. 提交技能文件。该仓库中的下一次Claude Code会话会自动发现此技能。

Reference

参考

Source files inside the installed package (
node_modules/@schemavaults/send-email/dist/
) -- read these when you need ground truth:
  • send-email-to-mailing-list.{d.ts,js}
    -- the
    sendEmailToMailingList()
    helper and its
    ISendEmailToMailingListOpts
    interface.
  • send-email.{d.ts,js}
    -- the underlying
    sendEmail()
    implementation, including
    getSchemaVaultsMailApiKey()
    and server-URL resolution.
  • send-email-request-body-schema.{d.ts,js}
    -- the Zod schema (
    createSendEmailRequestBodySchema
    ) that both the client helper and the mail-server route use to validate bodies.
  • index.d.ts
    -- package entry point; lists every exported symbol.
已安装包内的源文件(
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 schema(
    createSendEmailRequestBodySchema
    ),用于验证请求体。
  • index.d.ts
    ——包入口点;列出所有导出的符号。",