Twilio Communications
Build communication features with Twilio: SMS messaging, voice calls, WhatsApp Business API, and user verification (2FA). Covers the full spectrum from simple notifications to complex IVR systems and multi-channel authentication. Critical focus on compliance, rate limits, and error handling.
Patterns
SMS Sending Pattern
Basic pattern for sending SMS messages with Twilio. Handles the fundamentals: phone number formatting, message delivery, and delivery status callbacks.
Key considerations:
- Phone numbers must be in E.164 format (+1234567890)
- Default rate limit: 80 messages per second (MPS)
- Messages over 160 characters are split (and cost more)
- Carrier filtering can block messages (especially to US numbers)
When to use: Sending notifications to users,Transactional messages (order confirmations, shipping),Alerts and reminders
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: TwilioRestException) -> dict: """Handle Twilio-specific errors.""" error_handlers = { 21610: "Recipient has opted out. They must reply START.", 21614: "Invalid 'To' phone number format.", 21211: "'From' phone number is not valid.", 30003: "Phone is unreachable (off, airplane mode, no signal).", 30005: "Unknown destination (invalid number or landline).", 30006: "Landline or unreachable carrier.", 30429: "Rate limit exceeded. Implement exponential backoff.", }
return { "success": False, "error_code": error.code, "error": error_handlers.get(error.code, error.msg), "details": str(error) }
Usage
sms = TwilioSMS() result = sms.send_sms( to="+14155551234", body="Your order #1234 has shipped!", status_callback="https://your-app.com/webhooks/twilio/status" )
Anti_patterns
- Not validating E.164 format before sending
- Hardcoding Twilio credentials in code
- Ignoring delivery status callbacks
- Not handling the opted-out (21610) error
Twilio Verify Pattern (2FA/OTP)
Use Twilio Verify for phone number verification and 2FA. Handles code generation, delivery, rate limiting, and fraud prevention.
Key benefits over DIY OTP:
- Twilio manages code generation and expiration
- Built-in fraud prevention (saved customers $82M+ blocking 747M attempts)
- Handles rate limiting automatically
- Multi-channel: SMS, Voice, Email, Push, WhatsApp
Google found SMS 2FA blocks "100% of automated bots, 96% of bulk phishing attacks, and 76% of targeted attacks."
When to use: User phone number verification at signup,Two-factor authentication (2FA),Password reset verification,High-value transaction confirmation
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
Returns: Verification result """ try: check = self.client.verify \ .v2 \ .services(self.service_sid) \ .verification_checks \ .create( to=to, code=code )
return { "success": True, "valid": check.status == "approved", "status": check.status # "approved" or "pending" }
except TwilioRestException as e: # Code was wrong or expired return { "success": False, "valid": False, "error": str(e) }
def _handle_verify_error(self, error: TwilioRestException) -> dict: """Handle Verify-specific errors.""" error_handlers = { 60200: "Invalid phone number format", 60203: "Max send attempts reached for this number", 60205: "Service not found - check VERIFY_SID", 60223: "Failed to create verification - carrier rejected", }
return { "success": False, "error_code": error.code, "error": error_handlers.get(error.code, error.msg) }
Usage Example - Signup Flow
verify