Summary

Looking for another tool?

Share

How to create a simple SMS voting system (Python)

Understand the evolution of how to create a simple sms voting system (python).

Logo of Callr

The best way to learn is to do stuff. With that in mind, this tutorial is meant to help you figure out the challenges of building a simple SMS voting system. We’ll set up a number where people can vote through SMS. To keep it simple, there will be 2 different possible votes only: Bob and Dylan. So, if we translate this in a more functional perspective, we’ll need to:

  1. Acquire a mobile phone number to receive SMS on.
  2. Receive the SMS sent on a given number using the sms.get method and store the content of the message received in a list for processing.
  3. Process the answers and determine if it’s a vote for Bob or Dylan.
  4. Get back to all voters to thank them for their vote and announce the winner.

This cookbook is meant to display a way of building a simple SMS voting system in Python. It’s designed to be followed step by step, entering commands in the terminal on the flow. The goal is to familiarize yourself with CALLR's API. If you need to freshen up on CALLR’s API, please read our getting started with CALLR’s API article that covers the basics. Looking for the code with no extra fluff? Just click here.

STEP #1: Buying a mobile phone number

To buy numbers with CALLR's API, you need to do a reservation with the did/store.reserve method (doc) and then initiate a buy order with the did/store.buy_order method (doc).

The did/store.reserve method

A quick look at the doc for the did/store.reserve tells us it requires four parameters:

  • An area code ID: You’ll have to use the did/areacode.get_list method (doc) to figure this one out.
  • A class (string): type of numbers. “GOLD” numbers are high repetitive numbers (easy to remember). For our test sake, “CLASSIC” will do just fine.
  • A quantity (int): one will suffice in our case.
  • And an assignment mode (string): irrelevant when you’re only buying one.

Figuring out the desired area code

The did/areacode.get_list method (doc) requires two parameters:

  • The desired country code (string): for this example, we’ll buy a French number.
  • And the number type (string): here since we want to receive SMS, we have no choice but “MOBILE”.

Given our desired number, here is the API call:# Fetching the list available mobile French numbersnbarray = api.call("did/areacode.get_list", "FR", "MOBILE")And here's the output:

Two types of mobile numbers exist in France: those starting with +33 6 (id:67) and those starting with +33 7 (id:68); either will do.

Reserving and then buying the number

Now that we have our area code (67 or 68), we have everything we need to make our DID reservation.Here is the call made to reserve the number:# Reserving a mobile (06) French numbernbreserve = api.call("did/store.reserve", 68, "CLASSIC", 1, "RANDOM") # or "SEQUENTIAL" both will doThe only thing left to do now is to buy it, given you have enough credit on your account:# Buying the number using the reservation token obtained at the previous stepnbtoken = "%s" % nbreserve[‘token’]nbbuy = api.call(“did/store.buy_order”, nbtoken)

Checking the number we bought

We are now the proud owners of a French cell phone number. We’ll need to know the number to receive SMS on, so let’s check it out using the app.get_dids method (doc). In the following preview, I used the PrettyPrint module to improve the readability. The boolean (here "False") depends on the assignment of the number to a voiceapp. Since we just bought it, the number is unassigned (False).# Importing PrettyPrint and setting it upimport pprintpp = pprint. PrettyPrinter(indent=4)# Checking the phone numbers we own that are not assigned to an appdid = api.call("apps.get_dids", False)pp.pprint(did)And here's the output, with our newly bought number highlighted:

Now that have a number, we're ready for the next steps.

STEP #2: Getting SMS sent on our number

Fetching the IDs of the SMS received on the number

The sms.get method (doc) lets us fetch the content of an SMS we received. It needs to have the hash ID of the desired SMS as a parameter. To find it, we’ll use the sms.search method (doc).The sms.search method needs two parameters that are both arrays:

  • Filters: the SMS.SearchFilters object (doc) will help us fetch the SMS received on the number.
  • Options: We don’t need any options so we can set this one None.

We need two options to filter SMS according to two parameters: SMS received (“type”: “IN”) and those received on the number we bought (“to”: “+33644630378”)We’ll also need to send ourselves an SMS for testing purposes (so we have something to fetch). You can do this with your own cellphone, or with the API:# Sending ourselves a test smstestsms = api.call("sms.send", "SMS", "+33644630378", "Testing reception on my French mobile number", None)Now it’s time to set up our filter and search for the SMS we just sent ourselves:# Creating a SMSSearchFilters object matching our need and testing it
SMSSearchFilters = { "to": "+33644630378", "type": "IN"}
SMSIN = api.call("sms.search", SMSSearchFilters, None)
pp.pprint(SMSIN)
print(SMSIN['hits'][0]['text'])And here's the output:

Reception is working just fine! We'll need more than one text to test our system though, so we'll send ourselves a batch of SMS to process:# Sending a list of test SMS to ourselvesimport callrapi = callr.Api("callr_28","uXczARj50q")L = ["One vote for Bob", "Please Bob, save us from this cruel world", "Bob is my hero!", "Je vote bob", "Dylan I love you, will you marry me?", "Dylan is a cool guy, let him have my vote"]def send(L): api.call("sms.send", "SMS", "+336XXXXXXXX", L[i], None)for i, item in enumerate(L): send(L)

Fetching the content of the received SMS

The sms.search method returns various data about the received SMS, we’ll only need the content of the text, and later on, the number who sent it. Python offers an effortless way to do this, using lists. The body of the message sent is stored in the ‘hits’ which is itself stored SMSIN list. In the following command we basically tell Python: fetch me the first entry (list starts at index 0) of the ‘hits’ list and within this first entry fetch me the ‘text’ value:# LOLOLO

Fetching the content of all received SMS

We need to iterate over the previous step to fetch the text of all the SMS we received. We can do this quite elegantly with a for loop and store the data in a list so it’s easy to process. First, we need to create an empty list that will store all the text entries for the received SMS, you can name it as you like (ALLSMSIN). Now, we need to iterate through the SMSIN hits list and append (i.e add to the end of the list) each ‘text’ entry to the new list we created:# LOLOLOHere is what I get - the 7 texts I sent to myself (I and I are very talkative):

We now have the content of all SMS sent to our number, which marks the end of our second step and the biggest half of our SMS voting system. Now, we only need to process the texts and figure out the winner.

STEP #3: Counting the votes and finding the winner

Counting the votes of each contestant

Python has built in function to count the occurrences of substrings in a string. We’ll turn our ALLSMSIN list into a string and use this function to easily count the votes. We then print each variable to check that our script behaves as expected:# LOLOLOAnd here's the output, so far so good:

Figuring out the winner and announcing it

Almost done! Now we just have to compare Bob’s and Dylan’s total amount of votes and announce the winner. We have three possible scenarios that are self-explanatory if you look at the code:# LOLOLOAnd here’s what I get for my 7 texts, congrats Bob:

With our winner figured out, it's time to announce it to every participant to finish our simple SMS voting system.

STEP #4: Announcing the winner to all participants

For this last step, we’ll need to go back to our SMSIN dictionary and fetch the “from” entry of each hit. We did the same with the texts, so we just need to adapt our previous code:# LOLOLOHere’s what I get. Since I all the text to myself from the same number, we get a list containing 7 iterations of it:

Now we can go back the function we wrote in step #3 and include the body of the text message we will send to our participants in our if / elif loop: We get exactly the same result except that, this time, the message is stored in the resultsms variable. Now, we just have to send a SMS containing the resultsms variable to each number in the numbers list. Since the target of the sms.send method must be a string, we need another enumerate loop. I also append the ID of each SMS sent to yet another list, finalSMSID:# LOLOLOHere’s the result on my terminal:

And my phone's getting harassed by Bob's victory announcement:

Final notes

For the sake of simplicity, we only did the bare minimum of what is required. A fully functional SMS voting system used in production would need some form of pre-processing of the votes received. With the system detailed above, a vote for Bob spelled “bob” or “BOB” would not work. Feel free to build on it yourself, it’s the perfect follow-up exercise. Moreover, instead of running your script from the terminal, you will probably want to host it somewhere and make use of web hooks to add newly received SMS to your processing list dynamically. We'll explore web deployment and webhooks in our next cookbooks.[cta href="https://www.callr.com/p/python-sms-api/" txt="Looking for a smart and accessible Python SMS solution?" btn="Check out our API"]

We own our network

Global coverage

Order numbers in just one click in over 220 countries, including premium, vanity or toll-numbers.

Encrypted and secure

We offer state-of-the-art data encryption with HTTPS, SIP TLS & SRTP.

Reliable network

With multiple data centers and servers around the world, we offer a robust service you can rely on.

Registered carrier

We operate our own network for better performance, localization and support.

Illustrations that represent Callr's global network