Section 7.3. Example Service: Conference Messaging

Using an SMS Aggregator > Example Service: Conference Messaging

7.3. Example Service: Conference Messaging

Let's imagine we're organizing a large conference and wish to allow participants and organizers to communicate with one another via SMS. In the hypothetical service, participants will register with their:

  • Phone number

  • Nickname

Aggregators such as Clickatell allow you to lease a phone number with exclusive access to send and receive SMSs from that number. They also allow batch messages to be created that allow large amounts of messages to be quickly sent. So, for the purposes of our example, our service supports the following functionality:

  • Conference organizers can broadcast messages via a web interface.

  • Other participants broadcast messages ("shout") to conference participants by prefixing their messages with '!'.

  • Any message not prefixed by '!' will be considered feedback for the organizers and simply stored for later review.

For example, the conference organizer wants to let participants know that the party that was scheduled for the opening evening has been moved from 6:00 to 8:00 p.m. She navigates to an internal web page and types:

Tonight's party has been moved from 6:00pm to 8:00pm

Every conference participant receives a message on their phone:

TestCon says: 'Tonight's party has been moved from 6:00pm to 8:00pm'

After learning that the time of the party has changed, one of the participants decides to organize a dinner event. He replies to the text message sent by the admin:

!I'm going to Luigi's for dinner @6:30, anyone want to join? Msg me

Our service looks for messages pre-pended with '!' and broadcasts it to every conference participant's mobile phone. Each participant will see:

Bob(2063333333) says: I'm going to Luigi's for dinner @ 6:30, anyone want to join? Msg me

7.3.1. How to: Conference messaging using Clickatell

To illustrate how we would build our conference messaging service using an SMS aggregator, we will use the APIs provided by Clickatell. Clickatell is one of the most accessible SMS aggregators: You pay only for the messages sent and received (i.e., there is no set-up fee) and they give you 10 free credits on sign-up for testing. You can sign-up for a free developer account, its APIs are well documented, it connects to more than 600 different carrier networks, and it offer connectivity via a wide variety of protocols (e.g., HTTP/S, SMPP, SMTP, FTP, XML, and COM).

7.3.1.1. What you'll need

To implement this service, you'll need a few things:

  • A Clickatell developer account (http://www.clickatell.com/products/sms_gateway.php)

  • Python 2.4 or higher (http://www.python.org/download)

  • A web server that can execute Python CGI scripts (most web hosting providers support this). The following files described in this section will need to be placed in the web server's root path:

    • config.py: Static configuration data that is unique for each project.

    • broadcast.py: Functions that support sending SMSs to all registered participants.

    • admin.html: A web form that allows the conference admins to send broadcasts to all the participants.

    • admin_send.py : The script that processes the form that admin.html submits. It actually sends the SMSs.

    • responder.py : A script that is called by Clickatell when participants send SMSs to our leased number.

NOTE

Testing the incoming SMS portion of this example requires leasing a phone line from Clickatell, which can be expensive if you're just getting your feet wet. However, you can test just the web-based broadcast (outbound only) portion of this example with a free account.

7.3.1.2. Clickatell basics

We'll be using the Clickatell HTTP/S API for implementing our service. HTTP/S is one the simplest ways to access Clickatell, but it's also very feature rich. The API Guide is available at (http://www.clickatell.com/downloads/http/Clickatell_HTTP.pdf).

7.3.1.3. Static configuration

Our project relies on certain configuration elements that will be unique to every person running the example. You'll need to edit this file to match your particular situation.

config.py:

#change these to match your registration info api_id = '12345678' user = 'test' passwd = 'testpasswd' reply_num = '13334445555' conference = 'TestCon' nick_number_dict = {        '14445556666' : 'bob',        '15556667777' : 'ted',        '16667778888' : 'teresa' }

Our Clickatell set up require four pieces of configuration:

This example uses two other pieces of configuration data:

7.3.1.4. Simple Clickatell script

Let's take a look at a short Python script that will use the Clickatell HTTP API to send one message. This script is just an example, and isn't one of the files you'll be installing on your web server to implement the conference messaging service. It still relies on our configuration data though.

simple_send.py:

import urllib import config def send_message(to, text):        paramdict = {               'api_id': config.api_id,               'user' : config.user,               'password' : config.passwd,               'to' : to,               'from' : config.reply_num,               'text' : text        }        params = urllib.urlencode(paramdict)        result = urllib.urlopen("https://api.clickatell.com/http/sendmsg", params)        print result.readlines() if __name__ == "__main__":        #change the phone number to your own        send_message('13334445555', 'test message')     

The first thing this script does is import urllib and config. Python comes with urllib, it allows communication over most common Internet protocols including HTTPS, which is what we'll be using it for. We created config ourselves in the last section.

We then define a function called send_message that takes two parameters:

The send message function creates a dictionary that contains all the parameters that we'll need to send to Clickatell's sendmsg function.

The script then calls urlencode (from the urllib module), which converts the dictionary into a string that is URL-encoded.

All we need to do now is send a POST request to the sendmsg command at Clickatell. We use the urlopen command to do so, passing the URL as the first parameter and the POST variables as the second.

Lastly, we print out the response so you can see what it looks like.

The simple script above can be run on any computer with python installed. The send_message function takes a phone number and a message. Change the number to your own, and the message to whatever you'd like, then invoke the script (from the command line):

python simple_send.py

or on Windows:

python.exe simple_send.py

You could use this method to implement the conference broadcast functionality of our example service, but Clickatell provides a better mechanism.

7.3.1.5. Batching

The example above sends an individual message, but most aggregators provide a batching mechanism that will allow you to a message to a large number of people using only one API invocation. This will speed up the sending of the messages and reduce the likelihood of messages getting dropped.

Batching using Clickatell's API consists of two steps (three if you use the auth command to obtain a session ID we just pass our credentials each time):

Broadcast.py implements two methods: batch_setup and broadcast.

In order to send a message to all the conference participants, broadcast is called. It calls batch_setup to set a new batch up, and then sends a message to everyone in the configuration file.

This file can be executed at the command prompt as with simple_send.py. It will send two messages to every number in your configuration file (so make sure it's accurate it should probably only have your number in it at this point).

broadcast.py:

import urllib import re import config def batch_setup(message):        batch_setup_params = {               'api_id': config.api_id,               'user' : config.user,               'password': config.passwd,               'from' : config.reply_num, # the number replies go to               'mo' : '1', # allow responses               'template' : message        }        batch_id_re = re.compile("ID:[ ]*([0-9a-f]+)")        params = urllib.urlencode(batch_setup_params)        res = urllib.urlopen(               "https://api.clickatell.com/http_batch/startbatch", params        )        bid = 0        # extract the batch id from the response        for line in res.readlines():               print line               m = batch_id_re.search(line)               if m:                      bid = m.group(1)                      print "BID: %s" % bid                      return bid        return None def broadcast(msg, shout_from = None):        if shout_from:               nick = config.nick_number_dict[shout_from]               message = '%s(%s) says: %s' %(nick, shout_from, msg)        else:               message = '%s Announcement: %s' %(config.conference, msg)        bid = batch_setup(message)        if not bid:               raise Exception("Error Getting Batch ID")        # get a comma-delimited list of numbers from our dictionary        to_nums = ','.join(config.nick_number_dict.keys())        batch_send_params = {               'api_id': config.api_id,               'user' : config.user,               'password' : config.passwd,               'batch_id' : bid,               'to' : to_nums        }        params = urllib.urlencode(batch_send_params)        res=urllib.urlopen(               "https://api.clickatell.com/http_batch/quicksend", params        )        print res.readlines() # simple test if we run the file directly # it will send a message to all the numbers # in conf.py if __name__ == "__main__":        broadcast('test message', '12063497060')        broadcast('test message')     

Our function broadcast takes two parameters:

The first thing broadcast does is create the text of the message based on the contents of the shout_from parameter. It then calls the batch_setup function, passing it the message we wish to send. The command is set up by submitting a POST with the following parameters to (https://api.clickatell.com/http_batch/startbatch).

The code calls this URL from batch_setup in the way that it called sendmsg in our first example. Clickatell replies with a batch_id that will be used to actually send our message. Our code uses a regular expression to parse out the batch_id and returns it to the user.

Once broadcast has retrieved the batch_id, it takes all of the phone numbers listed in our configuration file and joins them together into one long string, with each number separated by commas.

We then use urlopen to POST with the following parameters to (https://api.clickatell.com/http_batch/quicksend).

And with that, your broadcast message is on its way.

The sample code prints out the responses to each message so you can see what they look like. Feel free to remove or disable the print statements as you wish.

Our sample doesn't track the messages once they are sent, but check whether your messages were successful by examining the response to your quicksend POST.

The response will contain one line for each number you send the message to. Each line will contain an apimsgid and the phone number of the recipient:

       ['ID: cc959204830b71ed27a014c3622356ee0 To: 12223334444\n']

You can then use the querymsg command to get the status of the particular recipient/message combination that the api_id refers to:

http://api.clickatell.com/http/querymsg?user=xxxx&password=xxxx&api_id=xxxx& apimsgid=xxxxx     

NOTE

Clickatell's quicksend command supports a maximum of 100 numbers on the To: line if submitting the request via HTTP GET, or 300 if submitting the request via HTTP POST. Break your request into multiple calls if you are sending to more numbers than these.

7.3.1.6. Web frontend

Our web frontend consists of three pieces. The first is a static HTML page that presents a simple form to the conference administrator. The second is a CGI script that processes the form submission. The third is a CGI script that will be used as a callback by Clickatell when they receive inbound SMSs for your leased phone number.

The interface for the conference administrator is presented by one simple HTML form.

admin.html:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"> <html lang="en">        <head>               <title>                      Conference Announcement System               </title>        </head>        <body>               <h3> Send an Announcement </h3>               <form action="admin_send.py" method="post">                      <p> Message: <input type="text" name="message"/> </p>                      <p> <input type="submit" value="Announce"/> </p>               </form>        </body> </html>

It has one field message that should be filled in with the text of the message that should be sent. The form is submitted via POST to the CGI script admin_send.py.

The second part of our web frontend is a python CGI script that processes the form described in admin.html. It imports the broadcast functionality we wrote earlier and uses it to send a message to everyone.

admin_send.py:

import sys import cgi import cgitb; cgitb.enable() from broadcast import * def result(text):  print "Content-type: text/html\n\n"  print """   <html>   <head><title>Announcement Made</title></head>   <body>%s</body>   </html> """ % text   sys.exit(0) form = cgi.FieldStorage() message = form.getfirst("message") broadcast(message) result("%s sent!" % message)

First the script imports several needed libraries and the broadcast functionality we wrote earlier. The cgitb.enable() command enables tracebacks on the web form, which makes it much easier to debug any potential problems.

We then define a function result() that will return a status page to the user.

The next line after the function definition uses the cgi module to fetch the parameters that were passed to our script.

We grab the message parameter (you'll recall that's the name of the field from admin.html) and then we pass it to broadcast.

Finally, we call our result function which returns a page to the user that confirms that he's sent the message.

NOTE

This short cut assumes you have access to a web hosting service that is running Apache or other server that will let you run python CGI scripts.

The easiest way to get everything working is to put all the files in the same directory. Everything with a .py extension will need to have correct permissions. This is usually 711 (rwx..x..x) on Unix systems, though the correct permissions can vary from host to host. For more advanced applications, you'll want to separate your static pages from your scripts or follow other practices designed to prevent source code compromise.

There are many other Python web frameworks that can be used, but they are not necessarily as straightforward or widely supported as Apache and pure CGI. Read about them at http://wiki.python.org/moin/WebFrameworks.

7.3.1.7. Receiving messages

To receive messages using Clickatell, you will need to set up two-way messaging, which involves leasing a phone number and setting up a callback URL. When an SMS is received to our leased number, Clickatell will invoke our callback URL with parameters containing the message details.

The Clickatell guide for setting up two-way messaging is at https://www.clickatell.com/downloads/Clickatell_Two_Way_Technical_Guide.pdf.

NOTE

As a quick reference, here is Clickatell's pricing for two-way messaging as of May 2007:

Number type Length Once-off set up fee (in euros) Monthly rental (in euros)
Standard number Up to 12 digits 100 25; 75
Tagged number 16 digits 50 15
Tagged number range 1 digit (10 tagged numbers) 100 30
  2 digits (100 tagged numbers) 100 60
  3 digits (1,000 tagged numbers) 100 80
  4 digits (10,000 tagged numbers) 100 90


The URL for this script needs to be accessible to Clickatell (so you'll need a static IP address or domain). Place it in the same directory as the rest of the scripts we've created. Our callback URL will receive a post from Clickatell with two parameters: text (the body of the message) and from (the number the message was received from).

responder.py:

import sys import cgi import cgitb; cgitb.enable() import re from broadcast import * form = cgi.FieldStorage() text = form.getfirst("text") #message is in the 'text' variable from_pn = form.getfirst("from") response_file = file("responses.txt", "a") #Check if message is of the form "!message body" m = re.match("!(.*)", text) if m:        #m.group(1) is the text of the shout        broadcast(m.group(1), from_pn) else: #if we didn't get a 'shout', write the response into a file        response_file.write("%s : %s\n" % (from_pn, text))        response_file.close()

First, we import the standard raft of libraries we'll be using, including our own.

Next, we grab the parameters via the cgi.FieldStorage object. We pick out the text and from parameters

We open a file responses.txt in append mode. Append mode ensures that we will add new lines to the file every time we write to it, instead of overwriting it. This file path should be changed to be outside the web path to prevent unauthorized users from viewing it. This file will be used to store feedback messages (i.e., those not prepended with a '!').

The re module is used to create a regular expression that will match text that has a '!' as the first character and will group everything else for later retrieval. We use the regex to try to match the message we were sent.

For instance, this will match the regex:

!What's Up?

This won't:

This talk is boring

If there was a match, we call broadcast and pass it the text (not including the '!') and the number we received the request from.

If there isn't a match, we write the text out to the file we opened earlier.

NOTE

If you change the script you may need to debug it. An easy way to debug the script is to call it from a web browser and supply your own text and from parameters.

Another way to test and debug the script from the command line, without a web server, is to invoke python with a URL-encoded string of form parameters as the second parameter:

  python responder.py text='!what%20is%20up'\&from=13334445555

The escape character \ before the & is necessary on many Unix shells to prevent the shell from interpreting the ampersand. The same goes for the ticks around the text parameter '!' is a special character in most shells. Windows and some Unix shells will be different.

7.3.1.8. Running the service

Install the files onto your hosting account as described earlier, open the admin page, and send a message.

Make sure you register your callback URL and try sending a shout. Or, try using the debugging methods above to test the shouting functionality if you don't want to lease a phone number.

Good work, you've just built a send and receive broadcast message service using an SMS aggregator! Now let's look at some other methods for implementing an SMS service.

 

 



How to Build an SMS Service
How to Build an SMS Service
ISBN: 789742233
EAN: N/A
Year: 2007
Pages: 52
BUY ON AMAZON

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net