Forwarding Voicemail Transcriptions to Email - Python


This guide will show how you can easily take a voicemail message from incoming callers, transcribe the recording, and email the transcription. We will use the SignalWire Python SDK to record a voicemail and transcribe it along with the MailGun API to send an email.

What do I need to run this code?

As we said before, there are a few packages and resources you will want to have ready to go before running this script. You can find out more information about them here! Once you've got these on hand, you're ready to go!

There are two ways you could run this script easily. The first way is through using our pre-built docker image for the script or by building your own. You could also run it through Flask! Here are some more resources around those:

As with all guides and snippets, you will need your API credentials (SignalWire Space URL, API Token, and Project ID). These can be found under the API tab of your SignalWire Space. For more information around that, check here.

Code Breakdown

Setting Up Your Environment File

  1. Copy from 'example.env' and fill in your values
  2. Save the new file as '.env'

Your file should look something like this, where SIGNALWIRE_SPACE is the full name of your SignalWire Space. e.g.:, SIGNALWIRE_PROJECT is your SignalWire Project ID, and SIGNALWIRE_TOKEN is your SignalWire API token.

[email protected]
[email protected]
EMAIL_SUBJECT=Transcribed Voicemail

The Code Itself

Our first route is the entry point for all incoming calls. In this route, we will use Say to play a quick prompt and Record to take a message. We will redirect to the /hangup route when the recording is finished as specified by the action URL. We will also make use of recording status callbacks and transcription status callbacks so that SignalWire will send an http request to our specified routes when the recordings and transcriptions are complete.

# Entry point for incoming calls, prompts to leave a voice mail for processing.
@app.route('/voice_entry', methods=['GET', 'POST'])
def voice_entry():
    # instantiate voice response 
    response = VoiceResponse()
    # play voicemail prompt and record voicemail that will finish on # key 
    response.say("Please leave a message at the beep. Press the pound key when finished.")
    response.record(finishOnKey="#", maxLength="1", action="/hangup", transcribe="true", transcribeCallback="/transcribe_webhook", recordingStatusCallback="/recording_webhook")
    # return response
    return str(response)

Our next route /hangup is the action URL that will execute when the recording is complete. We will play a short message to say goodbye and then use Hangup to end the call.

# Terminates the call
@app.route('/hangup', methods=['GET','POST'])
def hangup():
    # instantiate voice response 
    response = VoiceResponse()
    # say goodbye and hangup 
    response.say('Thank you! Good Bye!')
    # return response 
    return str(response)

Now we will define a function send_email(body) that will utilize the MailGun API to send an email using the variables from our .env file.

# Sends the email provided using mailgun
def send_email(body):
        "" + os.environ['MAILGUN_DOMAIN'] + "/messages",
        auth=("api", os.environ['MAILGUN_API_TOKEN']),
        data={"from": os.environ['EMAIL_FROM'],
              "to": [os.environ['EMAIL_TO']],
              "subject": os.environ['EMAIL_SUBJECT'],
              "text": body })

This route /recording_webhook will be called when the recording is completed. We will use it for information purposes only - for the sake of printing to console all the necessary information about recordings. Read more about recording status callbacks in our status callbacks super guide or check out our snippet for sending recordings via SMS!

# The webhook that is called on recording updates
@app.route('/recording_webhook', methods=['GET','POST'])
def recording_webhook():
    # For information only, and to show what is returned.

    return "200"

Our last route/transcribe_webhook will be used to handle the transcription status callback when the transcription is complete. We will use the TranscriptionText parameter as the body in our send_email(body) function.

# The webhook that is called when a transcription is received, this will process the transcription actions.
@app.route('/transcribe_webhook', methods=['GET','POST'])
def transcribe_webhook():
        # get all request values 

    # Recording Information
    recording_duration = request.values.get("RecordingDuration")
    recording_url = request.values.get("RecordingUrl")
    # Send Email
    return "200"


After all is said and done, you'll start receiving voicemail transcriptions of any incoming voicemail that has gone to whatever phone number(s) you've decided to run it on. And as we said, there are two ways you could run this.

Build and Run on Docker

  1. Use our pre-built image from Docker Hub
docker pull signalwire/snippets-voicemail-transcription:latest

(or build your own image)

  1. Build your image
docker build -t snippets-voicemail-transcription .
  1. Run your image
docker run --publish 5000:5000 --env-file .env snippets-voicemail-transcription
  1. The application will run on port 5000

Build and Run Natively

To run the application, execute export then run flask run.

You may need to use an SSH tunnel for testing this code if running on your local machine. – we recommend ngrok. You can learn more about how to use ngrok here.

Sign Up Here

If you would like to test this example out, you can create a SignalWire account and space here.

Please feel free to reach out to us on our Community Slack or create a Support ticket if you need guidance!

What’s Next

Check out the full code on our SignalWire Github Repo!

Did this page help you?