Index ¦ Archives ¦ Atom

Extending ejabberd with SMS via Twilio (Part 1)

One of my favorite features back when I used to use AOL Instant Messanger was the ability to send messages to any cell phone and basically get SMS messages for free (back before most people had fancy “unlimited” plans). Similarly, I really like the equivalent feature in Gmail that lets me send SMS message directly from my email page with Google Voice. It’s especially useful since my phone and gmail contacts are synced.

I decided I’d try to implement this feature for my favorite XMPP server, ejabberd. There is actually a mod_sms for version 1.x of ejabberd, but it uses the SMS over SMTP trick that has a lot of limitations. You need to be able to figure out which carrier each phone number is on, the received message looks ugly (email headers) and there isn’t a way for the receiver to reply back to the jabber user. I’ll be using the Twilio Cloud Communications Platform, so I don’t have to worry about all that garbage. Being able to route incoming message is going to be slightly tricky, but that will be covered in a future post.

Ejabberd and its modules are written in Erlang, a language that really puts the FUN in fun-ctional programming. While Erlang has been gaining popularity due to its powerful message passing and concurrency features, it isn’t quite popular enough to have an officially supported Twilio library. So, my first step was writing a Twilio API wrapper in Erlang. Before this week, my experience in Erlang was limited to: debugging ejabberd, an elevator simulator for a concurrency class in college, and trying to impress ladies with an elegant implementation of quicksort (spoiler: this doesn’t work). Also, I bought Joe Armstrong’s excellant Programming Erlang, but I’ve only read a few chapters. Erlang has some crazy syntax, but it’s a syntax that slowly grows on you. I’m not going to try to explain the language too much, it’s way out of the scope of this post.

Ok, so since my Erlang experience was largely just playing around, I realized I didn’t know how an idiomatic Erlang API should look. I asked for some help on reddit’s /r/erlang and got some helpful feedback. In particular, I struggled with how to represent optional parameters in Twilio’s REST requests. What I ended up doing is having a generic twilio:request/3 method that just takes the method (get or post), a URL, and a list of 2-tuples for GET or POST arguments. Using this method, I implemented some wrappers around some common Twilio API calls with the most common arguments used. So if you’re doing basic stuff, use a convenience method, otherwise just manually list out your URL and arguments. Not too bad, since my request method takes care of the basic auth and encoding parameters for you. For example, here is how I implemented making an outbound call:

outbound_call(To, From, Url) ->
    ApiUrl = "https://api.twilio.com/2010-04-01/Accounts/...myaccountsid.../Calls",
    request(post, ApiUrl, [{"To", To}, {"From", From}, {"Url", Url}]).

Since I can’t simply hardcode my AccountSid into the URL, and since there’s no need to repeat the “https://api.twilio.com/2010-04-01/” everytime, I looked in to how to do string formatting in Erlang. Sadly, string stuff is really awkward in Erlang. User jamiiecb on reddit showed me a simple trick that uses a list of strings and atoms, looks a little bit like Python name based string formatting. So instead, I can replace the above line with this:

ApiUrl = [server, api_version, "/Accounts/", account_sid, "/Calls"],

In order to maintain the state (which is simply your Twilio AccountSid and AuthToken) I use the “gen_server” behavior. This means that there is an Erlang process (not to be confused with an operating system process) that runs and waits to receive commands to send request Twilio URLs. It’s a little counter intuitive that my Twilio client is a server to other processes in my script. This was initially inspired by an Erlang Facebook wrapper, called ErlyFace; but unless I wanted to pass the credentials in every request, it was going to have to be like that anyway.

I’m mostly happy with the code in its current state, so I’ll be posting it to github pretty soon and then subsequently linking it back to this blog post. The next post I have will be about writing and distributing ejabberd modules, and translating Jabber messages into an SMS message.

© Chad Selph. Built using Pelican. Theme by Giulio Fidente on github.