Monday, July 13, 2009

Google Voice - Python - SMS

EDIT: Google recently made some behind the scenes changes to the login page, which broke this script. Please see the new and improved script here.

After a long wait, I finally received my Google Voice invitation last weekend. It offers a lot of features, but one that I was really excited about was the free SMS service. I don't have a cell phone, but nearly all my family members, friends and co-workers do. The majority of them are more prone to check their phone than their email, so sending a text is the best way to contact them. For a while, I used Gmail's SMS Lab to get in contact with the leaders and the Scouts of a Boy Scout troop that I participate in, but Gmail shut that down recently.

After I got my account, I began thinking about how neat it would be to be able to set up a script to send reminder text messages for me (preferably scheduled) using my account. I searched all over the internet to find out if there was an API provided by Google to do this -like their excellent gdata API - but no luck. I didn't give up there, there had to be a way.

A while ago, I learned that you can use HTTPCookieProcessor() from the urllib2 module to create an opener that will keep track of Cookie data sent back and forth from a server. So, with the help of Firebug (the best friend of many web-developers) I looked at the headers and POST data being sent when logging in to Google Voice, and when sending a text message. Turns out, it isn't very hard to log into your account, grab some necessary information from the Google Voice Home page (the inbox) and send a text.

This script will do just that one thing - log in your account, load the homepage to get a hidden form field's value, and then send one text message to one number. It will still show up in your outbox, so you aren't losing anything by using this method. This ability opens up a lot of possibilities, especially when coupled with the Gdata Contacts API. I have a few little scripts that I will be creating to send out weekly reminders to other people - and might use Google App Engine to make it even more useful and automated.


# Get URL handling support
import urllib2, urllib
# Get regular expression support
import re

# Google Account login credentials
email = 'YOUR_EMAIL'
password = 'YOUR_PASSWORD'

# Text message details
sendToNumber = 'NUMBER_TO_SEND_A_TEXT_TO'
messageToSend = 'I used Python to send this!'

# Set up an opener with HTTPCookieProcessor
opener = urllib2.build_opener(urllib2.HTTPCookieProcessor())
urllib2.install_opener(opener)

# Set up login credentials for Google Accounts
# The 'continue' param redirects us to the Google Voice
# homepage, and gives us necessary cookie info
loginParams = urllib.urlencode( {
'Email' : email,
'Passwd' : password,
'continue' : 'https://www.google.com/voice/account/signin',
} )

# Perform the login. Cookie info sent back will be saved, so we remain logged in
# for future requests when using the opener
opener.open( 'https://www.google.com/accounts/ServiceLoginAuth', loginParams)

# Need to load the homepage to find user specific data
googleVoiceHomeData = opener.open('https://www.google.com/voice/#inbox').read()

# Go through the home page and grab the value for the hidden
# form field "_rnr_se", which must be included when sending texts
match = re.search('name="_rnr_se".*?value="(.*?)"', googleVoiceHomeData)
_rnr_se = match.group(1)

# Set up parameters for sending text
sendTextParams = urllib.urlencode({
'_rnr_se': _rnr_se,
'phoneNumber': sendToNumber,
'text': messageToSend
})

# Send the text, store the return value
f = opener.open('https://www.google.com/voice/sms/send/', sendTextParams)
data = f.read()
print data
f.close()


Right now, if it succeeds nothing spectacular happens - it simply prints out the response: {"ok":true,"data":{"code":0}}. If it fails, {"ok":false,"data":{"code":20}}. Just look at the "ok" value to see if it worked.

You may notice that I don't have much (any) error checking in the script, nor do I usually when putting together scripts quickly just to test an idea out. When I do create something actually useful using this above script, I will put in the appropriate "checker" code. Just be aware that a text message can be 160 characters long, if you go over the remaining characters will be sent in a separate message.

Have fun, and don't be evil.

6 comments:

  1. You might like this:

    http://posttopic.com/topic/google-voice-add-on-development

    ReplyDelete
  2. Hi Scott,

    That is a very nice thought to use HTTPCookieProcessor like this.

    I am trying to use this script but it blows up exception on this line and couldn't create the match object and use the group method on it...

    match = re.search('name="_rnr_se".*?value="(.*?)"', googleVoiceHomeData)
    _rnr_se = match.group(0)

    Can you help and were you able to do anything further than this experiment with Google Voice?

    Thanks again and keep doing good job!

    ReplyDelete
  3. Pankaj -

    The only reason that I can think of as to why it would not work for you, is that you do not yet have a Google Voice account. If you do, then I don't know what the reason could be as long as your login credentials are correct.

    ReplyDelete
  4. Great idea! Me and a couple others have made our own implementation into a proper python module. The project is located at http://code.google.com/p/pygooglevoice/

    ReplyDelete
  5. I know this is old now, but i keep getting...

    C:\>test.py
    Traceback (most recent call last):
    File "C:\test.py", line 37, in
    _rnr_se = match.group(1)
    AttributeError: 'NoneType' object has no attribute 'group'


    I just need a command line script that will send a single hardcoded SMS message to a single hardcoded phone number through google voice. This looks the most promising.

    ReplyDelete
    Replies
    1. Sorry for the late response. To get this to work, you simply need to get the latest version of the gvoice.py module. You can find it here: https://github.com/hillmanov/gvoice/blob/master/gvoice.py

      Delete

Please comment!