In this comprehensive guide, I'll walk you through building a production-ready SMS gateway using Python and FastAPI. We'll cover everything from basic setup to advanced features like rate limiting, multi-provider support, and delivery tracking.
Why Build Your Own SMS Gateway?
While services like Twilio and Telnyx offer excellent APIs, building your own gateway gives you:
- Cost control: Route messages through the cheapest provider
- Redundancy: Automatic failover between providers
- Customization: Tailor features to your exact needs
- Analytics: Deep insights into your messaging patterns
Project Architecture
sms-gateway/
├── app/
│ ├── main.py # FastAPI application
│ ├── providers/ # SMS provider adapters
│ │ ├── twilio.py
│ │ ├── telnyx.py
│ │ └── vonage.py
│ ├── services/
│ │ ├── router.py # Message routing logic
│ │ └── rate_limiter.py
│ └── models/
│ └── message.py
├── tests/
└── requirements.txt
Getting Started
First, install the required dependencies:
pip install fastapi uvicorn httpx redis
Core Implementation
Here's the main FastAPI application:
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from typing import Optional
app = FastAPI(title="SMS Gateway")
class SMSRequest(BaseModel):
to: str
message: str
provider: Optional[str] = None
@app.post("/api/v1/send")
async def send_sms(request: SMSRequest):
# Validate phone number
if not validate_phone(request.to):
raise HTTPException(400, "Invalid phone number")
# Route to appropriate provider
provider = select_provider(request.provider)
# Send message
result = await provider.send(request.to, request.message)
return {"status": "sent", "message_id": result.id}
Rate Limiting with Redis
To prevent abuse and respect provider limits:
import redis
from functools import wraps
class RateLimiter:
def __init__(self, redis_url: str):
self.redis = redis.from_url(redis_url)
def check_limit(self, key: str, limit: int, window: int) -> bool:
current = self.redis.incr(key)
if current == 1:
self.redis.expire(key, window)
return current <= limit
Multi-Provider Support
The key to a robust gateway is supporting multiple providers:
class ProviderRouter:
def __init__(self):
self.providers = {
'twilio': TwilioProvider(),
'telnyx': TelnyxProvider(),
'vonage': VonageProvider()
}
async def send(self, to: str, message: str) -> dict:
# Try providers in order of priority
for name, provider in self.providers.items():
try:
return await provider.send(to, message)
except ProviderError:
continue
raise AllProvidersFailedError()
Conclusion
Building your own SMS gateway gives you complete control over your messaging infrastructure. The code shown here is a starting point - you can extend it with features like:
- Webhook callbacks for delivery status
- Message queuing with Celery
- Geographic routing
- A/B testing for message content
Check out my full implementation on GitHub: cloud-sms-gateway
Found this helpful? Follow me for more Python and API development content!
Top comments (0)