A low-tech SMS gateway with Twilio and OpenBSD

By Sijmen J. Mulder

After setting up outbound email on my server and being delighted how nice it is to pipe things to mail, like this bit in my daily.local

fortune cats | mail -s "Daily cat fact" wife@example.com

...I thought it would be fun to do the same for SMS (I have a dumbphone so no WhatsApp or XMPP).

Sending SMS

This is my sms script, using the Twilio API:

#!/bin/sh

if [ $# -ne 1 ]; then
  echo 'usage: sms <number>'
  exit 1
fi

url=https://api.twilio.com/2010-04-01
sid=REDACTED
token=REDACTED

to=$1
from=+31xxxxxxxxxx

curl -s "$url/Accounts/$sid/Messages.json" \
     -u $sid:$token \
     --data-urlencode "From=$from" \
     --data-urlencode "To=$to" \
     --data-urlencode "Body@-" \
     -o /dev/null \
 || echo 'error'

The "Body@-" bit means to use standard input (the text) as the form-encoded value for the Body key. I'm not using bash syntax because I use OpenBSD with ksh.

Now I can text cat facts!

$ fortune cats | sms +316xxxxxxxx

Email to SMS gateway

I even hooked it up to an incoming mail alias so I can email my server to text me!

$ fortune cats | mail -s "Cat fact" sms@example.com

This is how that's set up with an alias in /var/mail/aliases

sms: | sed '1,/^$/d' | sms +316xxxxxxxx

The sed invocation deletes the mail headers. (This uses the deletion command with syntax <from>,<to>d where from is line number 1, and to is a regex for an empty line.)

SMS to email gateway

The missing piece now is receiving SMS. I set up Twilio to POST incoming texts to this CGI script:

#!/bin/sh

echo 'Content-type: text/plain'

if [ "$REQUEST_METHOD" != "POST" ]; then
  echo 'Status: 405'
  echo
  echo 'Method Not Allowed'
  exit
fi

payload=`cat`
from=`echo "$payload" | formq From`
body=`echo "$payload" | formq Body`

echo "$body" | mail -s "SMS from $from" me@example.com
echo

First I cat the payload, which is a form encoded message, from stdin into a variable because I need to use it twice. First to extract the sender with formq, then to extract the body. The final echo is to finish the CGI response.

The script is hosted on OpenBSD's httpd with slowcgi, the latter which is a FastCGI to CGI adapter. I wrote formq because doing that with the shell was a mess.

Cat facts

What this is all about, of course, are the cat facts! I used the Cat Facts API and some sed to make fortune files. Download.

Conclusion

Now I can text from my server, text via email, and receive texts via email all with some shell scripts. Sure, I have used something like IFTTT but it was fun doing this myself, especially using just the base system, a handful of shell script and a sprinkling of C.

Back to top