Python web apps built with the Bottle web framework can send and receive SMS text messages. In this tutorial we will go beyond texting and learn how to dial outbound phone calls. The calls will read a snippet of text then play an MP3 file, but they can then be easily modified to create conference lines and many other voice features in your Python web apps.
Tools We Need
You should have either Python 2 or 3 installed to create your Bottle app, although Python 3 is recommended for new applications. We also need:
- pip and virtualenv to handle application dependencies
- Ngrok for localhost tunneling to our Bottle application while it's running on our local development environment
- Bottle web framework
- Free Twilio account to use their phone calling web API
- Twilio's Python helper library, which is open source on GitHub and available for download from PyPI
Take a look at this guide on setting up Python 3, Bottle and Gunicorn on Ubuntu 16.04 LTS if you need help getting your development environment configured before continuing on through the remainder of this tutorial.
You can snag all the open source code for this tutorial in the python-bottle-phone GitHub repository under the outbound directory. Use and copy the code however you want - it's all open source under the MIT license.
Installing Our Application Dependencies
Our Bottle app needs a helper code library to make it easy to dial outbound phone calls. Bottle and the Twilio helper library are installable from PyPI into a virtualenv. Open your terminal and use the virtualenv
command to create a new virtualenv:
- virtualenv bottlephone
Use the activate
script within the virtualenv, which makes this virtualenv the active Python installation. Note that you need to do this in every terminal window that you want this virtualenv to be used.
- source bottlephone/bin/activate
The command prompt will change after activating the virtualenv to something like (bottlephone) $
. Here is a screenshot of what my environment looked like when I used the activate
script.
Next use the pip
command to install the Bottle and Twilio Python packages into your virtualenv.
- pip install bottle twilio
After the installation script finishes, we will have the required dependencies to build our app. Time to write some Python code to dial outbound phone calls.
Bottle and Twilio
Our simple Bottle web app will have three routes:
/
- returns a text string to let us know our Bottle app is running/twiml
- responds with TwiML (a simple subset of XML) that instructs Twilio what to do when someone picks up the call to them from our Bottle web app/dial-phone/
, where "outbound_phone_number" is a phone number in the format "+12025551234" - this route uses the Twilio helper library to send a POST request to the Twilio Voice API to dial a phone call
We can build the structure of our Bottle app and the first route right now. Create a new file named app.py
with the following contents to start our app.
- import os
- import bottle
- from bottle import route, run, post, Response
- from twilio import twiml
- from twilio.rest import TwilioRestClient
- app = bottle.default_app()
- # plug in account SID and auth token here if they are not already exposed as
- # environment variables
- twilio_client = TwilioRestClient()
- TWILIO_NUMBER = os.environ.get('TWILIO_NUMBER', '+12025551234')
- NGROK_BASE_URL = os.environ.get('NGROK_BASE_URL', 'https://c6c6d4e8.ngrok.io')
- @route('/')
- def index():
- """
- Returns a standard text response to show the app is up and running.
- """
- return Response("Bottle app running!")
- if __name__ == '__main__':
- run(host='127.0.0.1', port=8000, debug=False, reloader=True)
Make sure you are in the directory where you created the above app.py
file. Run the app via the Bottle development server with the following command. Make sure your virtualenv is still activated so our code can rely on the Bottle code library.
- python app.py
We should see a successful development server start up like this:
- (bottlephone) matt@ubuntu:~/bottlephone$ python app.py
- Bottle v0.12.9 server starting up (using WSGIRefServer())...
- Listening on http://127.0.0.1:8000/
- Hit Ctrl-C to quit.
Here is what the development server message looks like in my environment on Ubuntu:
Let's test out the app by going to localhost:8000 in the web browser. We should get a simple success message that the app is running and responding to requests.
Next we need to obtain a phone number that our Bottle app can use to call other phone numbers.
Obtain a Phone Number
Our basic Bottle web app is running but what we really want to do is dial outbound calls - which will be handled by Twilio.
In your web browser go to the Twilio website and sign up for a free account. You can also sign into your existing Twilio account if you already have one.
The Twilio trial account allows you to dial and receive phone calls to your own validated phone number. To dial and receive calls from any phone number then you need to upgrade your account (hit the upgrade button on the top navigation bar to do that). Trial accounts are great for initial development before your application goes live but upgraded accounts are where the real power comes in.
Once you are signed into your Twilio account, go to the manage phone numbers screen. On this screen you can buy one or more phone numbers or click on an existing phone number in your account to configure it.
There is nothing for us to configure right now on the phone number configuration page because we are making outbound phone calls for this tutorial. Now that we have a phone number in hand, let's add the final bit of code to our Bottle app to get this app working.
Making Phone Calls
We need to add two new routes to our Bottle app so it can dial outbound phone calls. Modify your existing app.py file with the two new functions below, twiml_response
and outbound_call
. None of the other code in this file needs to change other than adding those two new functions to what we wrote in the previous section.
- import os
- import bottle
- from bottle import route, run, post, Response
- from twilio import twiml
- from twilio.rest import TwilioRestClient
- app = bottle.default_app()
- # plug in account SID and auth token here if they are not already exposed as
- # environment variables
- twilio_client = TwilioRestClient()
- # add your Twilio phone number here
- TWILIO_NUMBER = os.environ.get('TWILIO_NUMBER', '+16093002984')
- # plug in your Ngrok Forwarding URL - we'll set it up in a minute
- NGROK_BASE_URL = os.environ.get('NGROK_BASE_URL', 'https://c6c6d4e8.ngrok.io')
- @route('/')
- def index():
- """
- Returns a standard text response to show the app is up and running.
- """
- return Response("Bottle app running!")
- @post('/twiml')
- def twiml_response():
- """
- Provides TwiML instructions in response to a Twilio POST webhook
- event so that Twilio knows how to handle the outbound phone call
- when someone picks up the phone.
- """
- response = twiml.Response()
- response.say("Sweet, this phone call is answered by your Bottle app!")
- response.play("https://api.twilio.com/cowbell.mp3", loop=10)
- return Response(str(response))
- @route('/dial-phone/<outbound_phone_number>')
- def outbound_call(outbound_phone_number):
- """
- Uses the Twilio Python helper library to send a POST request to
- Twilio telling it to dial an outbound phone call from our specific
- Twilio phone number (that phone number must be owned by our
- Twilio account).
- """
- # the url must match the Ngrok Forwarding URL plus the route defined in
- # the previous function that responds with TwiML instructions
- twilio_client.calls.create(to=OUTBOUND_NUMBER, from_=BLOG_POST_NUMBER,
- url=NGROK_BASE_URL + '/twiml')
- return Response('phone call placed to ' + outbound_phone_number + '!')
- if __name__ == '__main__':
- run(host='127.0.0.1', port=8000, debug=False, reloader=True)
There is just one problem with our current setup if you're developing on a local environment: Twilio won't be able to reach that /twiml
route. We need to deploy our app to a reachable server, or just use a localhost tunneling tool like Ngrok. Ngrok provides an external URL that connects to a port running on your machine. Download and install the Ngrok application that is appropriate for your operating system.
We run Ngrok locally and expose our Bottle app that is running on port 8000. Run this command within the directory where the Ngrok executable is located.
- ./ngrok http 8000
Ngrok will start up and provide us with a Forwarding URL, with both HTTP and HTTPS versions.
We can use the Forwarding URL to instruct Twilio how to handle the outbound phone call when someone picks up. Insert the Ngrok forwarding URL into the app.py
file where NGROK_BASE_URL
is specified.
If Ngrok is useful to you, make sure to read this 6 awesome reasons to use Ngrok when testing webhooks post to learn even more about the tool.
Time to test out our app, let's give it a quick spin.
Making Phone Calls
Make sure your Bottle development server is still running or re-run it with the python app.py
command in a shell where your virtualenv is still activated.
Bring up the application in a browser, this time test out the phone calling capabilities. Go to "localhost:8000/dial-phone/my-phone-number", where "my-phone-number" is a number in the "+12025551234" format. For example, here is what happens when I dialed +12023351278:
And here is the inbound phone call!
When we pick up the phone call we also see the /twiml
route get called via Ngrok.
With just two routes in our Bottle app and Twilio we were able to make outbound phone calls. Not bad!
What's next?
Sweet, we can now dial outbound phone calls to any phone number from our Bottle web application. Next you may want to try one of these tutorials to add even more features to your app:
- Upgrade your Bottle app to also send and respond to text messages
- Create a phone-calling Slack bot
- Implement call tracking for both inbound and outbound phone calls made through your app
Questions? Contact me via Twitter @fullstackpython or @mattmakai. I'm also on GitHub as mattmakai.
Something wrong with this post? Fork this page's source on GitHub.
Learn more about these concepts
Web Frameworks Bottle APIs API Integration Twilio API Twilio Docs …or view all topics.
This site is based on Matt Makai's project Full Stack Python, thanks for his excellent work!
此网站由 @haiiiiiyun 和 开源爱好者们 共同维护。 若发现错误或想贡献,请访问: Github fullstackpython.cn 项目