Let’s get ‘pataphysical

Rube PipeSend an email to mrspeaker@gmail.com with a subject line that begins with sms (and a space), and the remainder of the subject line will be delivered to my mobile phone as a text message. Go on... give it a try... Yep, it worked. Pretty nifty hey? Ok, Ok, just one message is fine, thanks. Jeeez.

Want this service for yourself? Read on!

Ok, perhaps more than just "read on" is involved - the mechanics of the system could probably be considered "novel", so it wont be for you all. On the plus side, the complexity of it being "novel" is balanced by the freeness of it being free.

The intricacies of this model can best be described via this software architecture diagram:
Mr Speaker as Rube Goldberg

  1. A message is sent to my email account with its subject line beginning with sms.
  2. The message sits on some Google server.
  3. In an unrelated event, a user of the World Wide Web lands upon my web site.
  4. My blog stats package - ShortStat - logs a record of that visit to the database. I intercept this event, and take the opportunity to send an HTTP request to a separate page on my development server.
  5. The dev server runs a script which logs in to my Gmail account, and searches for unread messages that begin with sms.
  6. If one or more is available, then each message is posted to an auxiliary Twitter account. The message is then marked read, so as not to be processed again.
  7. My main Twitter account is subscribed to receive updates from this account, and therefore, receives them.
  8. I am set up to get Twitter updates to my phone. The message arrives, and my phone emits an annoying "beeeep beeeep" sound.

It's just that simple.

Notes on the "design"

  • Step "d" is just functioning as a dodgy cron job - All I want to do is check the status of my Gmail account every few minutes. After analysing my logs I noted that, on average, a unique visitor using the Firefox browser will hit my blog every 3-5 minutes.

    So in the stats script I detect this event, and fire the HTTP call.

  • Step "f" is just one idea... what we've really done is set up a generic SMS service - for example, I've also written a version that sends me todoist updates. You can check for pretty much anything here.
  • Step "i" is really step "h". Don't tell anyone.

The code

There are two pieces of PHP code involved in this: The HTTP trigger for the cron job which resides on this blog's server, and the main processing code which is on my dev server (of course, these can be the same server).

The HTTP trigger is a straight-forward CURL HTTP GET, buried in the middle of my short-stat code:

$url = 'http://www.mrspeaker.net/scripts/cronupdate.php';
$curl_handle = curl_init();
curl_setopt($curl_handle, CURLOPT_URL, '$url');
curl_setopt($curl_handle, CURLOPT_CONNECTTIMEOUT, 2);
curl_setopt($curl_handle, CURLOPT_TIMEOUT, 1);
curl_setopt($curl_handle, CURLOPT_HEADER, 0);
curl_setopt($curl_handle, CURLOPT_RETURNTRANSFER, 1);
$buffer = curl_exec($curl_handle);

(hmmm, this should probably be done asynchronously... better look that up...) This call will execute the main script, which can be broken into two parts: checking GMail, and posting to Twitter.

GMail Checking

To check GMail, I'm using a funky lil' PHP library called libgmailer. This allows you to log in, check your mail, send mails... the lot.

We use this library to log in to our account, and grab unread emails that start with SMS. Then we iterate through the results and send 'em to Twitter.

The code looks a lot like this:


// Gmail details
$GMAIL_USER = 'mrspeaker';
$GMAIL_PASS = 'password';
$GMAIL_TZ = '+10';

$CHECK_SUBJECT = 'sms'; // Will twitter any subject that starts with this...

// Get started
$gmailer = new GMailer();
if (!$gmailer->created)
	// Log something
	die('Failed to create GMailer because: '.$gmailer->lastActionStatus());

$gmailer->setLoginInfo($GMAIL_USER, $GMAIL_PASS, $GMAIL_TZ);

if (!$gmailer->connect())
	// Log Something
	die('Fail to connect because: '.$gmailer->lastActionStatus());

// GMailer connected to Gmail successfully.
$gmailer->fetchBox(GM_QUERY, 'subject:$CHECK_SUBJECT AND is:unread', 0);
$snapshot = $gmailer->getSnapshot(GM_STANDARD);

foreach( $snapshot->box as $mailItem )
	$subj = strip_tags($mailItem['subj']);
	// If starts with sms, twitter it.
	if( strncasecmp( $subj, $CHECK_SUBJECT, strlen( $CHECK_SUBJECT ) ) == 0 )
		$subj = substr($subj, strlen($CHECK_SUBJECT), strlen($subj));
		if( twit( strip_tags($mailItem['sender']) . ':' . $subj ) )
			// Mark as read...

The bit that is doing the hard yakka is $gmailer->fetchBox( GM_QUERY, 'subject:$CHECK_SUBJECT AND is:unread', 0 ), which fetches any new SMS messages we want to send. All that's left to do is pass the details to the twit() function...

Twitter Updating

The twit() function uses the Twitter API to post a message to our Twitter account, via another simple CURL POST:

// Twitter details
$TWIT_USER = 'mrspeaker_sms';
$TWIT_PASS = 'password';

function twit( $msg )

	// Set up and execute the curl process
	$curl_handle = curl_init();
	curl_setopt($curl_handle, CURLOPT_URL, 'http://twitter.com/statuses/update.xml');
	curl_setopt($curl_handle, CURLOPT_CONNECTTIMEOUT, 2);
	curl_setopt($curl_handle, CURLOPT_RETURNTRANSFER, 1);
	curl_setopt($curl_handle, CURLOPT_POST, 1);
	curl_setopt($curl_handle, CURLOPT_POSTFIELDS, 'status=$msg');
	curl_setopt($curl_handle, CURLOPT_USERPWD, '$TWIT_USER:$TWIT_PASS');
	$buffer = curl_exec($curl_handle);
		return false;
	return true;

After posting to the Twitter account, Twitter kindly sends me an email about it. Voila!

I could have just sent a Twitter Direct Message to my original twitter account, but by starting up multiple accounts I can now subscribe to various services: for example, if I decide that I don't want to get my Todoist updates I just turn of notifications from my mrspeaker_todoist account.

This all probably violates many terms-of-service, but hey... terms were meant to broken.