用模板发欢迎邮件

文案放在模板里,发送时只需要一个 id 和几个变量。

欢迎邮件写一次,之后由运营一直改下去。放进模板,这些修改就永远不需要发版——你的注册代码只知道模板 id 和要填进去的值。

1. 创建模板(只做一次)

管理模板需要 full_access 密钥(或者用控制台的 Templates 页面)。在你自己的电脑或初始化脚本里跑,而不是在应用里。

curl -X POST https://api.rovela.dev/templates \
  -H "Authorization: Bearer re_your_full_access_key" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Welcome",
    "subject": "欢迎来到 Acme,{{first_name}}",
    "html": "<h1>{{first_name}},你好</h1><p>你的工作区 <strong>{{workspace}}</strong> 已经准备好了。</p><p><a href=\"{{login_url}}\">打开 Acme</a></p>",
    "text": "{{first_name}},你好\n\n你的工作区 {{workspace}} 已经准备好了。\n打开 Acme:{{login_url}}"
  }'

记下返回的 id,应用发信时用的就是它。

{"object": "template", "id": "3b0e7c52-...", "name": "Welcome", ...}

2. 在注册接口里发送

sending_access 密钥就够了。请求里没有 subject 也没有 html:两者都来自模板,用变量渲染。

const WELCOME_TEMPLATE_ID = process.env.WELCOME_TEMPLATE_ID

// 模板变量是原样插入的,不做 HTML 转义。用户填的内容先过一遍这个函数,
// 否则一个叫 <img src=x> 的名字会变成你邮件里的标记。
function escapeHtml(s) {
  return String(s)
    .replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;")
    .replace(/"/g, "&quot;").replace(/'/g, "&#39;")
}

export async function sendWelcome(user) {
  const res = await fetch("https://api.rovela.dev/emails", {
    method: "POST",
    headers: {
      Authorization: "Bearer " + process.env.ROVELA_API_KEY,
      "Content-Type": "application/json",
      // 每个用户只发一封欢迎信,不管注册流程重试了多少次。
      "Idempotency-Key": "welcome-" + user.id,
    },
    body: JSON.stringify({
      from: "Acme <hello@mail.acme.com>",
      to: user.email,
      template: {
        id: WELCOME_TEMPLATE_ID,
        variables: {
          first_name: escapeHtml(user.firstName),
          workspace: escapeHtml(user.workspaceName),
          login_url: "https://app.acme.com/login",
        },
      },
    }),
  })
  if (!res.ok) throw new Error("welcome email failed: " + res.status)
}
同一组变量也会填进主题和 text 部分,所以转义过的值在那里会显示成实体——Tom &amp; Jerry 而不是 Tom & Jerry。如果你的用户名里可能有 & 或 <,就给 HTML 和纯文本各用一个变量。

可能出的问题

  • 收件箱里出现字面量 {{first_name}}。没有匹配键的占位符会原样保留。键是精确匹配的,firstName 填不了 {{first_name}}。
  • 有人直接改了线上模板。修改对下一次发送生效,包括已定时的。先复制一份、改副本、测试,再切换 WELCOME_TEMPLATE_ID。
  • 批量发送。/emails/batch 不接受 template;欢迎信本来也是每个用户一次请求。

变量、草稿和发布的更多内容见 邮件模板。