mcpField
T
twilio-communications

twilio-communications

github.com/davila7开发33.0k213 次安装1 天前更新
代码仓库

关于 twilio-communications

面向 Twilio 通信开发的技能指南,整理 SMS、Verify 验证和 TwiML 语音 IVR 的实现模式,并提示常见安全与交付问题。

主要功能

  1. 01SMS 发送与状态回调
  2. 02Verify 手机验证与多因素认证
  3. 03TwiML 交互式语音菜单
  4. 04凭据、签名与频率限制注意事项

适用场景

  1. 01发送通知、交易消息和提醒
  2. 02为注册、登录或交易添加号码验证
  3. 03构建电话菜单、语音支持或语音信箱

安装

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

$npx skills add https://github.com/davila7/claude-code-templates --skill twilio-communications

安装后在 Claude Code 中输入/twilio-communications确认已加载。

详细介绍

Twilio 通信

模式

SMS 发送模式

使用 Twilio 发送 SMS 消息的基本模式。 涵盖核心内容:电话号码格式、消息投递 和投递状态回调。

关键注意事项:

  • 电话号码必须采用 E.164 格式(+1234567890)
  • 默认速率限制:每秒 80 条消息(MPS)
  • 超过 160 个字符的消息会被拆分(费用也会更高)
  • 运营商过滤可能会拦截消息(尤其是发送至美国号码时)

适用场景:['向用户发送通知', '事务性消息(订单确认、发货通知)', '警报和提醒']

from twilio.rest import Client
from twilio.base.exceptions import TwilioRestException
import os
import re

class TwilioSMS:
    """
    SMS sending with proper error handling and validation.
    """

    def __init__(self):
        self.client = Client(
            os.environ["TWILIO_ACCOUNT_SID"],
            os.environ["TWILIO_AUTH_TOKEN"]
        )
        self.from_number = os.environ["TWILIO_PHONE_NUMBER"]

    def validate_e164(self, phone: str) -> bool:
        """Validate phone number is in E.164 format."""
        pattern = r'^\+[1-9]\d{1,14}$'
        return bool(re.match(pattern, phone))

    def send_sms(
        self,
        to: str,
        body: str,
        status_callback: str = None
    ) -> dict:
        """
        Send an SMS message.

        Args:
            to: Recipient phone number in E.164 format
            body: Message text (160 chars = 1 segment)
            status_callback: URL for delivery status webhooks

        Returns:
            Message SID and status
        """
        # Validate phone number format
        if not self.validate_e164(to):
            return {
                "success": False,
                "error": "Phone number must be in E.164 format (+1234567890)"
            }

        # Check message length (warn about segmentation)
        segment_count = (len(body) + 159) // 160
        if segment_count > 1:
            print(f"Warning: Message will be sent as {segment_count} segments")

        try:
            message = self.client.messages.create(
                to=to,
                from_=self.from_number,
                body=body,
                status_callback=status_callback
            )

            return {
                "success": True,
                "message_sid": message.sid,
                "status": message.status,
                "segments": segment_count
            }

        except TwilioRestException as e:
            return self._handle_error(e)

    def _handle_error(self, error: Twilio
Twilio Verify 模式(2FA/OTP)

使用 Twilio Verify 进行电话号码验证和 2FA。 负责处理验证码生成、发送、速率限制和欺诈防范。

相比自行实现 OTP 的主要优势:

  • Twilio 负责管理验证码的生成和过期
  • 内置欺诈防范(已帮助客户节省超过 8200 万美元,拦截 7.47 亿次尝试)
  • 自动处理速率限制
  • 支持多种渠道:SMS、语音、电子邮件、推送、WhatsApp

Google 发现,SMS 2FA 可拦截“100% 的自动化机器人、96% 的批量 网络钓鱼攻击,以及 76% 的定向攻击。”

适用场景:['用户注册时验证电话号码', '双重身份验证(2FA)', '密码重置验证', '高价值交易确认']

from twilio.rest import Client
from twilio.base.exceptions import TwilioRestException
import os
from enum import Enum
from typing import Optional

class VerifyChannel(Enum):
    SMS = "sms"
    CALL = "call"
    EMAIL = "email"
    WHATSAPP = "whatsapp"

class TwilioVerify:
    """
    Phone verification with Twilio Verify.
    Never store OTP codes - Twilio handles it.
    """

    def __init__(self, verify_service_sid: str = None):
        self.client = Client(
            os.environ["TWILIO_ACCOUNT_SID"],
            os.environ["TWILIO_AUTH_TOKEN"]
        )
        # Create a Verify Service in Twilio Console first
        self.service_sid = verify_service_sid or os.environ["TWILIO_VERIFY_SID"]

    def send_verification(
        self,
        to: str,
        channel: VerifyChannel = VerifyChannel.SMS,
        locale: str = "en"
    ) -> dict:
        """
        Send verification code to phone/email.

        Args:
            to: Phone number (E.164) or email
            channel: SMS, call, email, or whatsapp
            locale: Language code for message

        Returns:
            Verification status
        """
        try:
            verification = self.client.verify \
                .v2 \
                .services(self.service_sid) \
                .verifications \
                .create(
                    to=to,
                    channel=channel.value,
                    locale=locale
                )

            return {
                "success": True,
                "status": verification.status,  # "pending"
                "channel": channel.value,
                "valid": verification.valid
            }

        except TwilioRestException as e:
            return self._handle_verify_error(e)

    def check_verification(self, to: str, code: str) -> dict:
        """
        Check if verification code is correct.

        Args:
            to: Phone number or email that received code
            code: The code entered by user

        R
TwiML IVR 模式

使用 TwiML 构建交互式语音应答(IVR)系统。 TwiML(Twilio 标记语言)是一种 XML,用于告知 Twilio 接到来电时 应执行的操作。

核心 TwiML 动词:

  • :文本转语音
  • :播放音频文件
  • :收集按键或语音输入
  • :连接到另一个号码
  • :录制来电者的语音
  • :跳转到另一个 TwiML 端点

关键要点:Twilio 会向你的 webhook 发起 HTTP 请求,你返回 TwiML,Twilio 随即执行。由于此过程无状态,因此请使用 URL 参数或会话。

适用场景:['电话菜单系统(按 1 联系销售……)', '自动化客户支持', '带确认功能的预约提醒', '语音信箱系统']

from flask import Flask, request, Response
from twilio.twiml.voice_response import VoiceResponse, Gather
from twilio.request_validator import RequestValidator
import os

app = Flask(__name__)

def validate_twilio_request(f):
    """Decorator to validate requests are from Twilio."""
    def wrapper(*args, **kwargs):
        validator = RequestValidator(os.environ["TWILIO_AUTH_TOKEN"])

        # Get request details
        url = request.url
        params = request.form.to_dict()
        signature = request.headers.get("X-Twilio-Signature", "")

        if not validator.validate(url, params, signature):
            return "Invalid request", 403

        return f(*args, **kwargs)
    wrapper.__name__ = f.__name__
    return wrapper

@app.route("/voice/incoming", methods=["POST"])
@validate_twilio_request
def incoming_call():
    """Handle incoming call with IVR menu."""
    response = VoiceResponse()

    # Gather digits with timeout
    gather = Gather(
        num_digits=1,
        action="/voice/menu-selection",
        method="POST",
        timeout=5
    )
    gather.say(
        "Welcome to Acme Corp. "
        "Press 1 for sales. "
        "Press 2 for support. "
        "Press 3 to leave a message."
    )
    response.append(gather)

    # If no input, repeat
    response.redirect("/voice/incoming")

    return Response(str(response), mimetype="text/xml")

@app.route("/voice/menu-selection", methods=["POST"])
@validate_twilio_request
def menu_selection():
    """Route based on menu selection."""
    response = VoiceResponse()
    digit = request.form.get("Digits", "")

    if digit == "1":
        # Transfer to sales
        response.say("Connecting you to sales.")
        response.dial(os.environ["SALES_PHONE"])

    elif digit == "2":
        # Transfer to support
        response.say("Connecting you to support.")
        response.dial(os.environ["SUPPORT_PHONE"])

    elif digit == "3":
        # Voicemail
        response.say("Please leave a message after 

⚠️ 易踩坑之处

问题严重程度解决方案
问题高## 在数据库中跟踪退订状态
问题中## 为临时故障实现重试逻辑
问题高## 注册 A2P 10DLC(美国要求)
问题严重## 始终验证签名
问题高## 跟踪每位用户的会话窗口
问题严重## 切勿将凭据硬编码
问题中## 同时实现应用层速率限制

评论

支持 Markdown