SMS from the command line with Google Voice

I needed a script send an SMS today, and I found a very handy post at sudocode to send one via Google Voice, using PHP. I wanted to make it a little more command-line-friendly, so I rewrote it (ham-handedly) in Ruby and added some options parsing to it. It’s designed for — and only tested on — OS X, but may work fine elsewhere.

The code

To use it, copy the code below into a text file, save it as voicesms.rb (or download it directly using the link at the top of the code), and run chmod a+x voicesms.rb from the command line to make it executable.

#!/usr/bin/env ruby -Ku

require 'net/http'
require 'net/https'
require 'open-uri'
require 'cgi'
require 'optparse'

ACCOUNT = '' # Set to Google Voice account email for default account
PASSWORD = '' # Set to Google Voice account password for default account
NUMBERS = ['+1555444333','+1555444222'] # Set one or more numbers for default destination(s)

options = {}
optparse = do|opts|
  opts.banner = "Usage: voicesms.rb -n +15554443333[,+15554442222] -m \"Message to send\" [-u Username:Password]"

  options[:numbers] = NUMBERS
  opts.on( '-n', '--numbers NUM[,NUM]', 'Phone numbers to SMS (separate multiples with comma)' ) do|numbers|
    options[:numbers] = numbers.split(',')

  options[:message] = false
  opts.on( '-m', '--message MESSAGE', 'Message to send' ) do|msg|
    options[:message] = msg

   options[:username] = ACCOUNT
   options[:password] = PASSWORD
   opts.on( '-u', '--user USERNAME:PASSWORD', 'Google Voice username and password' ) do|creds|
     parts = creds.split(':')
     options[:username] = parts[0]
     options[:password] = parts[1]

  opts.on( '-h', '--help', 'Display this screen' ) do
    puts opts


unless options[:message]
  puts "Message required. Use -m \"MESSAGE\"."
  puts "Enter `voicesms.rb -h` for help."

def postit(uri_str, data, header = nil, limit = 3)
    raise ArgumentError, 'HTTP redirect too deep' if limit == 0
    url = URI.parse(uri_str)
    http =,443)
    http.use_ssl = true
    http.verify_mode = OpenSSL::SSL::VERIFY_NONE
    response,content =,data,header)
    case response
      when Net::HTTPSuccess     then content
      when Net::HTTPRedirection then postit(response['location'],data,header, limit - 1)
        puts response.inspect

def getit(uri_str, header, limit = 3)
    raise ArgumentError, 'HTTP redirect too deep' if limit == 0
    url = URI.parse(uri_str)
    http =,url.port)
    http.use_ssl = true
    http.verify_mode = OpenSSL::SSL::VERIFY_NONE
    response,content = http.get(url.path,header)
    case response
      when Net::HTTPSuccess     then content
      when Net::HTTPRedirection then getit(response['location'],header, limit - 1)

data = "accountType=GOOGLE&Email=#{options[:username]}&Passwd=#{options[:password]}&service=grandcentral&source=brettterpstra-CLISMS-2.0"
res = postit('',data)
if res
  authcode = res.match(/Auth=(.+)/)[1]
  header = {'Authorization' => "GoogleLogin auth=#{authcode.strip}",'Content-Length' => '0'}
  newres = getit('',header)
  if newres
    rnrse = newres.match(/'_rnr_se': '([^']+)'/)[1]
    options[:numbers].each {|num|
      data = "_rnr_se=#{rnrse}&phoneNumber=#{num.strip}&text=#{CGI.escape(options[:message])}&id="
      finalres = postit('',data,header)
      if finalres["ok"]
        puts "Message sent to #{num}"
        puts "Error sending to #{num}"


You can set default account name, password and send-to numbers at the top of the script. These can be overridden by command line options at runtime. The standard syntax is:

voicesms.rb -n +15552525543,+15554342221 -m “The message to send” -u GVoiceUsername:GVoicePassword

Parameters can be in any order. The -n parameter takes one or more phone numbers in international format (+XX country code at the beginning, +1 for US numbers), separated by commas (no spaces).

The -m option (message) is required and can’t be set by default in the script. Just use -m “and a quoted message” and it will handle the rest.

-u defines a username/password combination for Google Voice. It’s probably most convenient to set these at the top of the script and ignore this parameter, but the option is there.

-h will provide the help information.


The point of the script is to let me automate SMS messages from my system, so its primary invocation will be from other scripts. However, it will function just fine as a command line texting utility, in which case you’d probably want to alias the core functions in your .bash_profile. Set your default username and password in the script, and maybe a default destination number. If you want to send to a different numbers, you might want to make several aliases which include different -n # parameters, one for each destination. The alias will look something like:

alias sms=”~/scripts/voicesms.rb -m”

Or, maybe:

alias smsjohn=”~/scripts/voicesms.rb -n +15554443333 -m”

Get it? Then you can just type smsjohn "And your message" to send the message straight to John. Whoever that is.

What it does

It’s pretty simple, just a series of POST and GET requests to the Google API. It uses Google’s client authentication to get an initial auth code. Then it uses the auth code to get an auth token. Then, it posts your information to the API with the proper headers (the auth token) to complete the call. All of your data is sent securely over SSL (https) connections.

Have fun!

Brett Terpstra

Brett is a writer and developer living in Minnesota, USA. You can follow him as ttscoff on Twitter, GitHub, and Mastodon. Keep up with this blog by subscribing in your favorite news reader.

This content is supported by readers like you.

Join the conversation