跳到正文
FunCoding

搜索

搜索文档、Skill 和 MCP

SMS

Twilio SMS 渠道设置、访问控制和 Webhook 配置

OpenClaw 通过 Twilio 电话号码或 Messaging Service 接收和发送 SMS。Gateway 网关会注册入站 Webhook 路由(默认值为 /webhooks/sms),默认验证 Twilio 请求签名,并通过 Twilio 的 Messages API 发回回复。

状态:官方插件,需单独安装。仅支持文本:不支持 MMS/媒体,仅支持私信。

开始之前

你需要:

  • 使用 openclaw plugins install @openclaw/sms 安装官方 SMS 插件。
  • 一个 Twilio 账户,以及支持 SMS 的电话号码或 Twilio Messaging Service。
  • Twilio Account SID 和 Auth Token。
  • 一个可访问 OpenClaw Gateway 网关的公共 HTTPS URL。
  • 选择发送者策略:私用选择 pairing(默认),预先批准的电话号码选择 allowlist,仅在有意开放公共 SMS 访问时选择 open。

如果一个 Twilio 号码同时具备两项能力,则可同时用于 SMS 和语音通话。SMS Webhook 和语音 Webhook 在 Twilio 中分别配置,并使用不同的 Gateway 网关路径;本页仅介绍 SMS Webhook。

快速设置

安装插件

openclaw plugins install @openclaw/sms

创建或选择 Twilio 发送方

在 Twilio 中,打开 Phone Numbers > Manage > Active numbers,然后选择一个支持 SMS 的号码。保存以下信息:

  • Account SID,例如 ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
  • Auth Token
  • 发送方电话号码,例如 +15551234567

如果使用 Messaging Service 而不是固定发送方号码,请保存 Messaging Service SID,例如 MGxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx。

配置 SMS 渠道

将以下内容保存为 sms.patch.json5,并修改占位符:

{
  channels: {
    sms: {
      enabled: true,
      accountSid: "ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
      authToken: "twilio-auth-token",
      fromNumber: "+15551234567",
      publicWebhookUrl: "https://gateway.example.com/webhooks/sms",
      dmPolicy: "pairing",
    },
  },
}

应用配置:

openclaw config patch --file ./sms.patch.json5 --dry-run
openclaw config patch --file ./sms.patch.json5

将 Twilio 指向 Gateway 网关 Webhook

在 Twilio 电话号码设置中,打开 **Messaging**,并将 **A message comes in** 设置为:
https://gateway.example.com/webhooks/sms
使用 HTTP `POST`。默认本地路径为 `/webhooks/sms`;如需使用其他路由,请更改 `channels.sms.webhookPath`。

暴露确切的 SMS Webhook 路径

公共 URL 必须将 SMS 路径路由到 Gateway 网关进程(默认端口为 `18789`)。如果使用 Tailscale Funnel 进行本地测试,请显式暴露 `/webhooks/sms`:
tailscale funnel --bg --set-path /webhooks/sms http://127.0.0.1:<gateway-port>/webhooks/sms
tailscale funnel status
语音通话和 SMS 使用不同的 Webhook 路径。如果同一个 Twilio 号码同时处理两者,请在 Twilio 和隧道中保留这两条路由的配置。

启动 Gateway 网关并批准第一个发送者

openclaw gateway

向 Twilio 号码发送一条短信。第一条消息会创建配对请求。批准该请求:

openclaw pairing list sms
openclaw pairing approve sms <CODE>
配对码将在 1 小时后过期。

配置示例

所有键都位于 channels.sms 下(每个账户的键位于 channels.sms.accounts.<id> 下):

键默认值用途
enabledtrue启用或禁用渠道/账户。
accountSid—Twilio Account SID(AC...)。
authToken—Twilio Auth Token;纯文本字符串或 SecretRef。
fromNumber—E.164 发送方号码。
messagingServiceSid—未解析出 fromNumber 时使用的 Messaging Service SID(MG...)。
defaultTo—发送流程未指定明确目标时使用的默认目标。
webhookPath/webhooks/sms用于接收入站 Twilio Webhook 的 Gateway 网关 HTTP 路径。
publicWebhookUrl—在 Twilio 中配置的公共 URL;签名验证需要此项。
dangerouslyDisableSignatureValidationfalse跳过 X-Twilio-Signature 检查;仅用于本地隧道测试。
dmPolicy"pairing"pairing、allowlist、open 或 disabled。
allowFrom[]允许的 E.164 发送者号码,或将 "*" 与 dmPolicy: "open" 配合使用。
textChunkLimit1500每个出站 SMS 分块的最大字符数。
accounts, defaultAccount—多账户映射和默认账户 ID。

配置文件

如果希望渠道定义随 Gateway 网关配置一起管理,请使用配置文件进行设置:

{
  channels: {
    sms: {
      enabled: true,
      accountSid: "ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
      authToken: "twilio-auth-token",
      fromNumber: "+15551234567",
      publicWebhookUrl: "https://gateway.example.com/webhooks/sms",
      dmPolicy: "pairing",
    },
  },
}

环境变量

环境变量仅应用于默认账户;配置值的优先级高于环境变量值。

变量映射到
TWILIO_ACCOUNT_SIDaccountSid
TWILIO_AUTH_TOKENauthToken
TWILIO_PHONE_NUMBER(别名 TWILIO_SMS_FROM)fromNumber
TWILIO_MESSAGING_SERVICE_SIDmessagingServiceSid
SMS_PUBLIC_WEBHOOK_URLpublicWebhookUrl
SMS_WEBHOOK_PATHwebhookPath
SMS_ALLOWED_USERSallowFrom(以逗号分隔)
SMS_TEXT_CHUNK_LIMITtextChunkLimit
SMS_DANGEROUSLY_DISABLE_SIGNATURE_VALIDATIONdangerouslyDisableSignatureValidation("true")
export TWILIO_ACCOUNT_SID="ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
export TWILIO_AUTH_TOKEN="<twilio-auth-token>"
export TWILIO_PHONE_NUMBER="+15551234567"
export SMS_PUBLIC_WEBHOOK_URL="https://gateway.example.com/webhooks/sms"

然后在配置中启用该渠道:

{
  channels: {
    sms: {
      enabled: true,
      dmPolicy: "pairing",
    },
  },
}

SecretRef 身份验证令牌

authToken 可以是 SecretRef(source: "env" | "file" | "exec")。如果希望 Gateway 网关从 OpenClaw 密钥运行时解析 Twilio Auth Token,而不是以纯文本配置形式存储,请使用此方式:

{
  channels: {
    sms: {
      enabled: true,
      accountSid: "ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
      authToken: { source: "env", provider: "default", id: "TWILIO_AUTH_TOKEN" },
      fromNumber: "+15551234567",
      publicWebhookUrl: "https://gateway.example.com/webhooks/sms",
      dmPolicy: "pairing",
    },
  },
}

引用的环境变量或密钥提供商必须对 Gateway 网关运行时可见。更改主机环境变量后,请重启托管的 Gateway 网关进程。

Messaging Service 发送方

如果应由 Twilio 通过 Messaging Service 选择发送方,请使用 messagingServiceSid 而不是 fromNumber:

{
  channels: {
    sms: {
      enabled: true,
      accountSid: "ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
      authToken: "twilio-auth-token",
      messagingServiceSid: "MGxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
      publicWebhookUrl: "https://gateway.example.com/webhooks/sms",
      dmPolicy: "pairing",
    },
  },
}

如果配置和环境变量解析后同时存在 fromNumber 和 messagingServiceSid,则使用 fromNumber。

默认出站目标

如果自动化或智能体发起的投递流程在未指定明确目标时应有默认目标,请设置 defaultTo:

{
  channels: {
    sms: {
      enabled: true,
      accountSid: "ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
      authToken: "twilio-auth-token",
      fromNumber: "+15551234567",
      defaultTo: "+15557654321",
      publicWebhookUrl: "https://gateway.example.com/webhooks/sms",
    },
  },
}

访问控制

channels.sms.dmPolicy 控制直接 SMS 访问:

  • pairing(默认):未知发送者会收到配对码;使用 openclaw pairing approve sms 批准。
  • allowlist:仅处理 allowFrom 中的发送者。如果 allowFrom 为空,则拒绝所有发送者(Gateway 网关会记录启动警告)。
  • open:配置验证要求 allowFrom 包含 "*"。如果没有通配符,则只有列出的号码可以聊天。
  • disabled:丢弃所有入站私信。

allowFrom 条目应为 E.164 电话号码,例如 +15551234567。系统接受并规范化 sms: 和 twilio-sms: 前缀。对于私人助理,建议将 dmPolicy: "allowlist" 与明确的电话号码配合使用:

{
  channels: {
    sms: {
      enabled: true,
      accountSid: "ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
      authToken: "twilio-auth-token",
      fromNumber: "+15551234567",
      publicWebhookUrl: "https://gateway.example.com/webhooks/sms",
      dmPolicy: "allowlist",
      allowFrom: ["+15557654321"],
    },
  },
}

发送 SMS

选择 SMS 渠道后,目标可以是纯 E.164 号码,也可以带有 sms: 前缀:

openclaw message send --channel sms --target sms:+15551234567 --message "hello"

隐式选择渠道时,twilio-sms: 前缀会选择此渠道,同时不会占用 sms: 服务前缀;iMessage 使用后者为自己的目标选择运营商 SMS 投递:

openclaw message send --target twilio-sms:+15551234567 --message "hello"

CLI 要求显式指定 --target。defaultTo 用于可从渠道配置中解析目标的自动化和智能体发起的投递路径。

来自入站 SMS 对话的智能体回复会通过已配置的 Twilio 发送方自动发回给发送者。

SMS 输出为纯文本。OpenClaw 会移除 Markdown、展平围栏代码块、将链接重写为 label (url),并在通过 Twilio 发送前,将较长的回复拆分为每块最多 textChunkLimit 个字符(默认 1500)的分块。

验证设置

Gateway 网关启动后:

  1. 确认 Gateway 网关日志中显示 SMS webhook 路由。
  2. 运行 Twilio 端探测(检查已配置的 Twilio webhook URL/方法和近期入站错误):
openclaw channels capabilities --channel sms
openclaw channels status --channel sms --probe --json
  1. 用你的手机向 Twilio 号码发送一条 SMS。
  2. 运行 openclaw pairing list sms。
  3. 使用 openclaw pairing approve sms 批准配对码。
  4. 再发送一条 SMS,并确认智能体进行了回复。

如需仅测试出站发送,请使用:

openclaw message send --channel sms --target sms:+15557654321 --message "OpenClaw SMS test"

从 macOS iMessage/SMS 进行端到端测试

在可通过 Messages 发送运营商 SMS 的 Mac 上,你可以使用 imsg 驱动发送方,而无需操作手机:

imsg send --to "+15551234567" --service sms --text "OpenClaw SMS E2E $(date -u +%Y%m%dT%H%M%SZ)" --json
openclaw pairing list sms
openclaw pairing approve sms <CODE>
imsg send --to "+15551234567" --service sms --text "reply exactly SMS pong" --json

第一条消息应创建配对请求。第二条消息应通过 Twilio 收到智能体回复。

Webhook 安全

默认情况下,OpenClaw 使用 publicWebhookUrl 和 authToken 验证 X-Twilio-Signature。请确保 publicWebhookUrl 的端点部分与 Twilio 中配置的 URL 逐字节一致,包括协议、主机、路径和查询字符串。按照 Twilio 的要求,OpenClaw 在计算签名时会排除 Twilio 连接覆盖片段(#...)。

独立于签名验证,webhook 路由还会强制执行以下规则:

  • 仅允许 POST。
  • 每个 SMS 账户、webhook 路由和解析出的客户端地址每分钟最多可有 300 个失败请求。所有请求都会计入此预算,但仅当请求未通过正文解析、Twilio 验证或 AccountSid 匹配后,才会应用 HTTP 429。
  • 通过上述检查后,每个 SMS 账户、webhook 路由和解析出的客户端地址每分钟最多接受 30 个可分发的回调(超过时返回 HTTP 429)。如果禁用签名验证,此每分钟 30 次的限制即为未经身份验证的分发上限。
  • 客户端地址通过共享的 Gateway 网关可信代理规则解析。如果 gateway.trustedProxies 包含转发 Twilio 回调的反向代理,OpenClaw 会根据转发的客户端地址应用这些限制;否则会回退到直接套接字地址。
  • 有效载荷中的 AccountSid 必须与已配置的 accountSid 匹配(否则返回 HTTP 403)。
  • 重复使用的 MessageSid 值会在 10 分钟内去重。
  • 每个 SMS 账户的重放缓存最多保留 10,000 个仍然有效的消息 SID。当所有槽位均有效时,该账户的新 webhook 会以 HTTP 429 和 Retry-After 标头采用失败关闭方式拒绝,直至最早的槽位过期。
  • 超过 32 KB 的请求正文会被拒绝。

Twilio 默认不会重试 HTTP 429,也未说明支持 Retry-After。#rp=4xx 和 #rp=all 连接覆盖会启用 4xx 重试,但 Twilio 将完整重试事务限制在 15 秒内,因此重试仍可能在重放缓存槽位过期前结束。如果必须由其他处理程序接收投递失败的消息,请配置备用 URL;应将 429 视为失败关闭式拒绝,而非可靠的背压机制。

仅用于本地隧道测试时,可以设置:

{
  channels: {
    sms: {
      dangerouslyDisableSignatureValidation: true,
    },
  },
}

不要在公共 Gateway 网关上禁用签名验证。

多账户配置

运营多个 Twilio 号码时,请使用 accounts:

{
  channels: {
    sms: {
      accounts: {
        support: {
          enabled: true,
          accountSid: "ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
          authToken: "twilio-auth-token",
          fromNumber: "+15551234567",
          publicWebhookUrl: "https://gateway.example.com/webhooks/sms/support",
          webhookPath: "/webhooks/sms/support",
          dmPolicy: "allowlist",
          allowFrom: ["+15557654321"],
        },
      },
    },
  },
}

每个账户必须使用不同的 webhookPath;如果某个路径已归另一个账户所有,Gateway 网关会拒绝注册使用该路径的 webhook 路由。TWILIO_*/SMS_* 环境变量回退仅适用于默认账户;设置 defaultAccount 可更改默认账户。

故障排除

Twilio 返回 403 或 OpenClaw 拒绝 webhook

检查 publicWebhookUrl 是否与 Twilio 中配置的 URL 完全匹配,包括协议、主机、路径和查询字符串。Twilio 会对公共 URL 字符串签名,因此代理重写和备用主机名可能导致签名验证失败。

出现包含 Invalid account 的 403,表示入站有效载荷中的 AccountSid 与已配置的 accountSid 不匹配;请检查 webhook 是否指向拥有该号码的账户。

未出现配对请求

检查 Twilio 号码的 Messaging webhook URL 和方法。它必须指向 SMS webhook URL,并使用 POST。还要确认 Gateway 网关可从公共互联网或通过你的隧道访问。

如果 Twilio 消息日志显示错误 11200,则表示 Twilio 已接受入站 SMS,但无法访问你的 webhook。请检查:

  • Twilio 的 Messaging > A message comes in 是否指向 publicWebhookUrl。
  • 方法是否为 POST。
  • 隧道或反向代理是否公开了完全一致的 webhookPath;对于 Tailscale Funnel,请运行 tailscale funnel status 并确认其中列出了 /webhooks/sms。
  • publicWebhookUrl 是否使用 Twilio 发送时相同的协议、主机、路径和查询字符串,以便签名验证可以重现已签名的 URL。

openclaw channels status --channel sms --probe 会同时显示不匹配的 Twilio webhook 设置和近期 11200 错误。

出站发送失败

确认 accountSid、authToken 以及 fromNumber 或 messagingServiceSid 已解析。如果使用 Twilio 试用账户,可能需要先在 Twilio 中验证目标号码,才能发送出站 SMS。

消息已送达,但智能体未回复

检查 dmPolicy 和 allowFrom。使用默认的 pairing 策略时,必须先批准发送者,才能处理正常的智能体轮次。