Respond to Incoming SMS with Python and GCP Cloud Functions

April 15, 2025
Written by
Reviewed by

Respond to Incoming SMS with Python and GCP Cloud Functions

Have you ever wanted to build an app that automatically responds to text messages? Since I love working with serverless technologies, I wanted to share how you can create a serverless SMS responder using Google Cloud Functions.

What We'll Build

We're going to create a serverless function that handles incoming text messages. The best part? You don't need to manage any servers - Google Cloud Functions takes care of all that for you.

By the end of this tutorial, you'll have:

  • A working SMS responder using Twilio's API
  • A serverless function deployed on Google Cloud
  • A foundation for building more complex messaging applications

Prerequisites

Before we begin, make sure you have the following:

  1. A Twilio Account: Sign-up here
  2. A Google Cloud Account: Register at Google Cloud's website to open an account
  3. Python 3.9+ installed locally
  4. Google Cloud CLI installed and configured
  5. A code editor (VS Code, PyCharm, etc.)

Once you have all these prerequisites in place, you're ready to start building.

Understanding the building blocks

Let's break down the key components we'll be working with:

Twilio's Webhook system

Think of webhooks as real-time notifications between systems. When someone texts your Twilio number, Twilio immediately pings your application with all the message details. Your application then decides how to respond.

Twilio uses two main types of webhooks for SMS:

  • Incoming Message Webhook: Gets triggered when someone texts your number
  • Status Callback Webhook: Lets you know if your message was delivered successfully

These webhook calls expect responses in TwiML (Twilio Markup Language), which looks like this:

<?xml version="1.0" encoding="UTF-8"?>
<Response>
    <Message>Thanks for your message! We'll get back to you soon.</Message>
</Response>

Google Cloud Functions

Instead of setting up and maintaining a server to handle these webhooks, we'll use Google Cloud Functions. It's a serverless platform that lets you run code in response to events - perfect for handling incoming messages!

Ready to start building? Let's dive into the setup!

Project Setup

First, let's set up our local development environment:

Create a new project directory:

mkdir sms-responder
cd sms-responder

Create a virtual environment”

python -m venv .venv
source .venv/bin/activate  # On Windows: .venv\Scripts\activate

Create project files:

touch main.py requirements.txt .gitignore

Add the following to your .gitignore:

.venv/
venv/ 
__pycache__/ 
.env 
*.pyc

Add the required dependencies to requirements.txt:

functions-framework==3.* 
twilio
google-cloud-pubsub==2.*

Install the dependencies:

pip install -r requirements.txt

Implementing the Function

Create your main.py file with the following code:

import functions_framework
from twilio.twiml.messaging_response import MessagingResponse
import random
# Programming jokes for responses
jokes = [
    "Why do programmers prefer dark mode? Because light attracts bugs!",
    "What's a programmer's favorite place in the house? The function room!",
    "Why do Python programmers wear glasses? Because they can't C#!",
    "Why was the JavaScript developer sad? Because he didn't Node how to Express himself!",
    "What's a programmer's favorite hangout spot? Foo Bar!"
]
@functions_framework.http
def receive_sms(request):
    """HTTP Cloud Function that responds to incoming SMS messages."""
    try:
        # Get the incoming message
        message_body = request.form.get('Body', '')
        sender = request.form.get('From', '')
        # Log incoming message (optional)
        print(f"Received message: '{message_body}' from {sender}")
        # Create response
        resp = MessagingResponse()
        resp.message(random.choice(jokes))
        return str(resp), 200, {'Content-Type': 'text/xml'}
    except Exception as e:
        print(f"Error processing request: {e}")
        return str(e), 500

This implements the function by using the twilio package to create a TwiML response that includes a random Programming Joke.

Note: For production deployments, you should validate that requests are genuinely from Twilio using the request signature. See Twilio's Security Documentation for implementation details.

Testing the Function locally

To test locally using the Functions Framework, run the command:

functions-framework --target receive_sms --debug

Now you can use curl or go to localhost:8080 in your browser.

curl  -X GET http://localhost:8080
XML file with a programmer joke about a function room displayed on a colorful gradient background.

Deploying to Google Cloud

To deploy the function to Google Cloud, make sure you have gcloud CLI installed and configured. Alternatively, you can do this in the Google Cloud Console as well.

Now, make sure you have the right project selected:

# List your projects 
gcloud projects list 
# Set the active project 
gcloud config set project YOUR_PROJECT_ID

After you have configured your project, deploy the function:

gcloud functions deploy receive-sms \
  --runtime python39 \
  --trigger-http \
  --allow-unauthenticated \
  --entry-point receive_sms

This command deploys our local function to cloud with configuration:

  • Using Python 3.9 runtime
  • HTTP Triggered function
  • Unauthenticate requests are allowed for the function
  • Entry point is receive_sms

If this is your first time using Google Cloud Functions on the GCP project, you may get a prompt about the API not being enabled, enter Y to enable the API:

API [cloudfunctions.googleapis.com] not enabled on project [YOUR-PROJECT-ID]. Would you
like to enable and retry (this will take a few minutes)? (y/N)?  Y
Enabling service [cloudfunctions.googleapis.com] on project [YOUR-PROJECT-ID]...

Once enabled, it will deploy your local function to the cloud. You will receive a URL for your function. Save this URL as you’ll need it for the Twilio webhook configuration.

Deploying function (may take a while - up to 2 minutes)...done.
automaticUpdatePolicy: {}
availableMemoryMb: 256
buildName: projects/85xxxxxxxxxx/locations/us-central1/builds/xxxxx-xxxx-xxxx-xxxx-xxxxxxx
buildServiceAccount: projects/YOUR-PROJECT-ID/serviceAccounts/xxxxxxxxx@developer.gserviceaccount.com
dockerRegistry: ARTIFACT_REGISTRY
entryPoint: receive_sms
httpsTrigger:
  securityLevel: SECURE_OPTIONAL
  url: https://us-central1-YOUR-PROJECT-ID.cloudfunctions.net/receive-sms
ingressSettings: ALLOW_ALL
runtime: python39
status: ACTIVE
timeout: 60s
updateTime: '2025-02-20T21:18:35.441Z'

[Note]: Based on your Organization restrictions/policies, you might not be able to generate/access the Function URL.

Configuring Twilio

To send a message, first you will need to buy a phone number, ideally from the region you are based in to avoid roaming charges. To do this, go to the Twilio Console and search for a number you’d like to buy.

Twilio dashboard showing search options and results for purchasing phone numbers.

Now let’s configure the number.

  • Go to the Twilio Console and navigate to your phone number
  • In the Messaging Configuration section, paste your Cloud Function URL as the webhook for incoming messages
  • Ensure the HTTP method is set to POST
Screenshot of Twilio platform's messaging configuration settings, showing routing and webhook options.

Now, let’s test if it all works. Grab your phone and send a text message to your Twilio number, you should receive back a random programming joke!

SMS conversation with a joke about a JavaScript developer who didn't know how to express himself.

Monitoring and Logging

You can monitor your functions logs via the console or via the CLI as well.To view your function's logs using the CLI:

gcloud functions logs read receive-sms
Log entries showing the execution of a receive-sms function capturing SMS messages with timestamps and status codes.

If you want to clean up the resources (cloud function) we deployed to GCP, you can use the following command to delete the function.

gcloud functions delete receive-sms

Conclusion

That's it! We've built a serverless SMS responder using Google Cloud Functions that can handle incoming messages and respond automatically. Having worked with both Twilio's APIs and Google Cloud, I can tell you this combination is powerful for building scalable communication solutions.

This is just the beginning. Maybe I will do another post where I can show you how to handle long-running processes using Google Cloud Pub/Sub, perfect for scenarios where you need to process messages asynchronously or integrate with AI services.

I'd love to see what you build with this! Feel free to reach out to me on LinkedIn or Twitter/X if you have questions or want to share your project. Keep building, keep learning!

If you found this helpful, check out my other tutorials on Cloud, Python and DevOps and on my YouTube Channel.