This guide shows you how to build a Flask app using the Infobip Python SDK that can send text messages to your phone. If you want to see the finished code, you can check out the GitHub repo. Read on to see what we built, and how to do it yourself!

Prerequisites

  • An Infobip account (a free trial account works fine)
  • A little Python knowledge

Setup

First, create a new folder in your file system called ‘jokes-with-python’. This folder will be your working directory for the duration of this guide, and when you run terminal commands, you’ll do so from within this directory. 

In a terminal window, navigate to this directory. Create and activate a virtual environment to keep all your project dependencies isolated from the rest of your machine:

python3 -m venv .venv
source .venv/bin/activate

Alternatively, the GitHub repository also includes the necessary configuration to set up a dev container, which will provide you with a working environment in which to write and run your Flask app. Read more about using dev containers in GitHub Codespaces, PyCharm or Visual Studio Code.

We’ll be building a tiny Flask application with a single page. That page has a button on it, and when you click that button, it sends a programming-related pun to your phone via SMS. 

To do this, we’ll need to install the following Python packages:

pip install Flask 
pip install jokeapi
pip install infobip-api-python-sdk

Flask lets us build and serve an application using Python. jokeapi is a Python wrapper for Sv443’s Joke API, which we’ll be using to retrieve jokes. Lastly, we’ll need the Infobip SDK to write Pythonic code to send SMS messages.

Creating our app.py

When you build a Flask app, you usually put the main entry point for that app in a file or package called app.py. Our app is going to be a single file of Python, so we’ll create a file called app.py in the top level of our working directory.

jokes-with-python/
    app.py

If you like, you can also run the following command from your working directory to keep a record of your currently installed packages:

pip freeze > requirements.txt

That will result in a directory structure like this:

jokes-with-python/
    app.py
    requirements.txt

Open up your app.py file in your code editor of choice, and add the following lines:

from flask import Flask

app = Flask(__name__)

@app.route('/')
def index():
    return “hello world”

Now run flask run from the command line in your working directory. By default, this will serve your Flask app at https://localhost:5000, and show you a very simple page with the words ‘hello world’ on it.

Adding an HTML template

Next, we’ll add some HTML for our app to serve us. Flask requires its HTML files to be in a particular place, so create a new directory underneath your working directory called templates. Within that directory, add a file called app.html, and add the following code to it:

<html>
   <head>
       <title>Puns with Python</title>
       <link rel="icon" type="image/favicon" href="https://avatars.githubusercontent.com/u/1288491">
       <link href="https://fonts.googleapis.com/css2?family=Lora:wght@600&display=swap" rel="stylesheet">
   </head>
   <body>
       <form action="{{ url_for('index')}}" method="POST">
           <button type="submit"><p>Text me a pun!</p></button>
       </form>
   </body>
</html>

Your directory structure now looks like this:

jokes-with-python/
    app.py
    requirements.txt
    templates/
        app.html

The <head> section contains some information to help the browser display our page, such as the title and icon. We also use this to set a font for our page’s content, which can be anything you like.

In the <body> section, there’s a button component that lives within an HTML <form>. When that button is clicked, it sends a POST request to our index page. To handle this kind of request, we’ll need to update the Python function that Flask runs when we access our index page.

In your app.py file, update your imports line to include render_template and request from Flask:

from Flask import Flask, render_template, request

 Update your index() function as follows:

@app.route('/', methods=['GET', 'POST'])
def index():
   if request.method == 'GET':
       pass
   else:
       print(‘You clicked the button!’)
   return render_template('app.html')

Here, we’ve updated the @app.route decorator to specify that this URL should accept both GET and POST requests, and in the body of the function we use an if statement to handle the two types of request differently.

With a POST request, we’ll run through the else statement in our code and hit the print statement. When run our Flask app from a terminal window, and click our button in the browser, we’ll see the results of that print statement in that terminal window.

The last change here is that the function now serves our new HTML, instead of just a string saying ‘hello world’.

Now, run flask run again. Your app now serves a page at https://localhost:5000 that has a button, and when you click that button, you should see the text ‘You clicked the button!’ appear in your terminal.

If you like, you can also add some CSS styling to your HTML so that the page looks shiny and cool; in the GitHub repo, the app.html file includes CSS within a <style> tag, which can be copy-pasted into your version.

Getting jokes from Sv443’s Joke API

Next, we’ll add a Python function to query the Joke API. The jokeapi library uses asynchronous programming to do this, so we’ll need to use the async and await keywords in our joke function. Add the following imports into your app.py file:

import asyncio
from jokeapi import Jokes

Now add the following function:

async def get_joke_from_api():
   jokes = await Jokes()
   joke = await jokes.get_joke(category=['programming', 'pun'], blacklist=['nsfw'])
   if joke["type"] == "single":
       joke = joke["joke"]
   else:
       joke = f'{joke["setup"]}\n\n{joke["delivery"]}'
   return joke

This code comes almost exactly from the example in the jokeapi documentation – which makes sense, since we’re following a very obvious use-case for this API! We only make a couple of changes to the documentation example: we specify that we’d like the jokes returned to be in classes of programming and pun, and that we’d like all our jokes to use work-safe humour.

Now update your index function to print a joke when the button is clicked:

@app.route('/', methods=['GET', 'POST'])
def index():
   if request.method == 'GET':
       pass
   else:
       joke = asyncio.run(get_joke_from_api())
       print(joke)
   return render_template('app.html')

Here we use asyncio.run() to execute our asynchronous joke function.

Run flask run as before, and when you click on the button, you should see a joke printed to your terminal!

Adding SMS messaging to our app

Now we’ll add some Infobip magic into our app. To get started with this, you’ll need the following bits of information:

  • Your Infobip API key
  • Your Infobip Base URL
  • The number to which you’d like to send SMS messages., If you’re using a trial account, this should be the number you’ve verified in association with your account.

You can manage and create API credentials at https://portal.infobip.com/dev/api-keys after logging in to your Infobip account. Your Base URL is also visible in your portal homepage; see the documentation for more.

When setting the destination phone number, make sure you’re using the correct format.

Add these variables to your environment by running the following commands in your terminal:

export IB_API_KEY=<your API key goes here>
export IB_BASE_URL=<your Base URL goes here>
export DESTINATION_NUMBER=<your phone number goes here>

The first two variables are used directly by the Infobip Python SDK, and we’ll use the phone number ourselves from code using os.environ.

Next, you’ll need to add the following imports to your app.py:

from infobip_channels.sms.channel import SMSChannel
import os

Next, add another function:

def send_sms_from_app(text):
   channel = SMSChannel.from_env()
   sms_response = channel.send_sms_message({
       'messages': [{
           'from': 'PythonPuns',
           'text': text,
           'destinations': [{
               'to': os.environ['DESTINATION_NUMBER']
           }],
       }]
   })
   print(sms_response)

This function uses the Infobip Python SDK to send an SMS message. The first line sets up an SMS Channel using the environment variables that we just set. The next line uses that channel to send a message. To learn more about what each part of the arguments to send_sms_message are doing, check out the documentation for the SDK and the API endpoint.

At the end of this function, we print out the response from the API, so we can know that the SMS message was sent.

Now, we need to actually use this function! Update your `index` function one last time:

@app.route('/', methods=['GET', 'POST'])
def index():
   if request.method == 'GET':
       pass
   else:
       joke = asyncio.run(get_joke_from_api())
       send_sms_from_app(joke)
   return render_template('app.html')

All we’ve changed here is that we’re now calling our new SMS function with our joke, rather than printing the joke to the terminal.

Now, run flask run again, click the button, and you should see an SMS message sent to the phone number that you specified in DESTINATION_NUMBER!

Going even further

This toy example could be extended in lots of fun ways. You could add a second button that sends a link to a random Wikipedia page to your phone, or include input from the web app itself by adding an <input type=”text”> element to the form in your HTML. If you build anything cool, be sure to head over to our Discord and share it with us!