đ Executive Summary
TL;DR: On-call teams often face bottlenecks sharing 2FA codes from physical phones. This solution details building a robust Twilio-to-email forwarder using a Python Flask webhook to automatically deliver SMS codes to a team distribution list, eliminating coordination overhead.
đŻ Key Takeaways
- A Python Flask application serves as the webhook endpoint, receiving incoming SMS from Twilio and processing them for email forwarding.
- Environment variables, loaded via
python-dotenvfrom aconfig.envfile, are crucial for securely managing sensitive credentials like Twilio Account SID/Auth Token and email service API keys. - Proper configuration of the Twilio phone numberâs âA MESSAGE COMES INâ webhook URL to point to the publicly accessible Flask application endpoint (e.g.,
https://your-app-name.com/sms) is essential for functionality.
Forwarding SMS from Twilio to Email for 2FA Sharing
Darian Vance here. Letâs talk about a common headache in any team that shares on-call duties or access to a central service: the dreaded 2FA code. For a while, my team had a physical âon-call phoneâ that weâd pass around. It was a mess. The phone would get left at the office, run out of battery, you name it. We were constantly blocked. I finally decided to solve this properly, and this Twilio-to-email forwarder is the result. Itâs a simple, robust solution that turns SMS codes into emails sent to a team distribution list. It saved us countless hours of coordination overhead, and I think it can do the same for you.
Letâs get this set up. Itâs faster than you think.
Prerequisites
Before we dive in, make sure you have the following ready to go:
- A Twilio account with an active phone number. Youâll need your Account SID and Auth Token.
- An email delivery service account. Iâm a fan of SendGrid for its reliability, but others like Mailgun or AWS SES work just as well. Youâll need an API key.
- A Python environment. Weâll be using Flask to create a simple web server to act as our webhook.
The Guide: Building the Forwarder
Step 1: Set Up Your Project and Environment
First things first, get your project directory organized. Iâll skip the standard virtualenv setup since you likely have your own workflow for that. Just make sure you have a clean environment to work in. Youâll need to install a few Python packages. I use pip for this, so youâd run the commands to install twilio, flask, python-dotenv, and your email providerâs library (e.g., sendgrid).
Next, create a file named config.env. This is where weâll store our secrets. Storing credentials directly in the code is a huge security risk, and this method keeps them separate and safe. Your file should look like this:
# Twilio Credentials
TWILIO_ACCOUNT_SID=ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
TWILIO_AUTH_TOKEN=your_twilio_auth_token
# Email Configuration
SENDGRID_API_KEY=SG.xxxxxxxxxxxxxxxxxxxxxxxxxxxxx
FROM_EMAIL=sms-bot@yourdomain.com
TO_EMAIL=your-team-dl@yourdomain.com
Step 2: The Python Webhook Script
This is where the magic happens. Weâll write a small Flask application that listens for incoming messages from Twilio. When Twilio receives an SMS on your number, it will send a POST request to our applicationâs endpoint. Our script will then parse that request and use our email service to forward the message content.
Create a file, letâs call it app.py, and add the following code:
import os
from dotenv import load_dotenv
from flask import Flask, request
from twilio.twiml.messaging_response import MessagingResponse
from sendgrid import SendGridAPIClient
from sendgrid.helpers.mail import Mail
# Load environment variables from config.env
load_dotenv('config.env')
app = Flask(__name__)
# Fetch credentials from environment
SG_API_KEY = os.getenv('SENDGRID_API_KEY')
FROM_EMAIL = os.getenv('FROM_EMAIL')
TO_EMAIL = os.getenv('TO_EMAIL')
@app.route("/sms", methods=['POST'])
def sms_webhook():
"""
Receives an SMS from Twilio and forwards it via SendGrid.
"""
# Get the SMS message body and sender number from the request
message_body = request.values.get('Body', 'No content')
from_number = request.values.get('From', 'Unknown sender')
# Prepare the email content
email_subject = f"New SMS from {from_number}"
email_content = f"<h2>SMS Received</h2><p><strong>From:</strong> {from_number}</p><p><strong>Message:</strong></p><pre>{message_body}</pre>"
# Create the Mail object
message = Mail(
from_email=FROM_EMAIL,
to_emails=TO_EMAIL,
subject=email_subject,
html_content=email_content
)
try:
# Use the SendGrid client to send the email
sg = SendGridAPIClient(SG_API_KEY)
response = sg.send(message)
print(f"Email sent with status code: {response.status_code}")
except Exception as e:
# In a real app, I'd have more robust logging here
print(f"Error sending email: {e}")
# Even if email fails, we respond to Twilio to avoid an error loop
pass
# Respond to Twilio to acknowledge receipt of the SMS
twiml_response = MessagingResponse()
return str(twiml_response)
if __name__ == "__main__":
app.run(debug=True, port=5002)
Pro Tip: Validate Twilio Requests
In my production setups, I never trust an open webhook. Twilio cryptographically signs its requests, and you should validate that signature. The
twilioPython library includes aRequestValidatorhelper class. Youâd initialize it with your Auth Token and then check if the request is legitimate before processing it. This prevents anyone on the internet from spamming your email forwarder by just sending POST requests to your URL.
Step 3: Deploy and Configure the Webhook
This Flask app needs to be running on a server with a public IP address or URL so Twilio can reach it. You could use a small cloud VM, a PaaS like Heroku, or a serverless function. For a quick test, a tool like ngrok is fantastic for exposing your local development server to the internet.
Once your application is live and you have its public URL (e.g., https://your-app-name.herokuapp.com/sms), you need to tell Twilio where to send the messages.
- Go to your Twilio console and navigate to âPhone Numbersâ > âManageâ > âActive Numbersâ.
- Click on the number youâre using for this forwarder.
- Scroll down to the âMessagingâ section.
- Under âA MESSAGE COMES INâ, select âWebhookâ.
- Paste your public URL into the text box and ensure the method is set to âHTTP POSTâ.
- Click âSaveâ.
Thatâs it! Send a test SMS to your Twilio number, and you should see an email arrive in the inbox you specified in config.env moments later.
Common Pitfalls (Where I Usually Mess Up)
-
Environment Variables Not Loaded: The most common issue. The script fails silently or with an authentication error because it canât find the API keys. Always double-check that your
config.envfile is in the right place and named correctly. -
Incorrect Webhook URL: A simple typo in the URL you paste into the Twilio console can stop the whole thing from working. I always copy-paste and then double-check. Also, ensure you include the
/smspath. - Firewall Blocking: If youâre self-hosting on a VM, make sure your serverâs firewall allows incoming traffic on the port your Flask app is running on.
- Email Spam Filters: Initially, some of our forwarded emails landed in spam. Make sure your sending domain is properly authenticated with your email provider (using SPF and DKIM records) to improve deliverability.
Conclusion
And there you have it. A simple, server-side solution that completely removes the bottleneck of a shared physical phone for 2FA. This setup is lightweight, cheap to run, and infinitely more scalable than passing a device around. Itâs one of those small DevOps improvements that pays dividends in team sanity and efficiency every single day. Hope this helps you out!
đ Read the original article on TechResolve.blog
â Support my work
If this article helped you, you can buy me a coffee:

Top comments (0)