A lot of services today either require or really want you to provide a cellphone number when signing up. I prefer not sharing my private number with these services and I also prefer not having these texts clog up my inbox.

First I thought I could do this with Twilio but apparently they don't allow receiving texts from short codes like Twitter and Facebook uses. So I decided to build an SMS gateway! You don't really need much to do this

  • A 3G/4G modem
  • A sim card, preferably prepaid
  • A computer :)

There are a few frameworks if you want more advanced features, for example playSMS or smsgateway. I haven't tried any of these myself but they look great! Since I only really wanted to receive texts I went with gammu. I found this guide which explained most of what I had to do.

I had an old Huawei E398 laying around at home. I got it working with the instructions below but after a few hours it would disconnect and I had to reinsert it. I'm not sure if this was due to a faulty modem or something else.. So YMMV!

Now I'm using a Huawei E122 and it worked OOTB. lsusb for that modem gives

ID 12d1:1001 Huawei Technologies Co., Ltd. E169/E620/E800 HSDPA Modem

If you have another modem it might be worth checking out the device reference for usb_modeswitch if it's supported. There's also a parameter reference for those who don't like man-pages.

Switching usb mode

Most modems will present themselves as a USB storage when you insert them, mostly for Windows users to they can install drivers. So you need to tell it to switch to modem mode and for this we use usb-modeswitch.

Instructions for Huawei E398

sudo apt-get install gammu usb-modeswitch

Check what mode we're in, for my modem storage mode looked like this

lsusb
=> Bus 002 Device 019: ID 12d1:1505 Huawei Technologies Co., Ltd. E398 LTE/UMTS/GSM Modem/Networkcard

12d1 above is the vendor ID and 1505 the product ID.

Now you need to find the product ID of the modem mode. Some guides recommended restarting the computer with the modem plugged in but that didn't help for me so I had to google a bit. There are tons of forum posts for different modems and in my case I found the correct ID to be 1506.
You also need to find the "message-content" to send the modem with the -M flag.

Switch the modem mode

# -v is current vendor ID
# -p is current product ID
# -V is target vendor ID (usually the same)
# -P is target product ID
# -M is the message
sudo usb_modeswitch -v 12d1 -p 1505 -V 12d1 -P 1506 -M 
"55534243123456780000000000000011062000000100000000000000000000"

Check that the modem has switched mode

lsusb
=> Bus 002 Device 005: ID 12d1:1506 Huawei Technologies Co., Ltd. Modem/Networkcard

There should now be one or more devices to use

dmesg | grep tty
# Should give something like
GSM modem (1-port) converter now attached to ttyUSB0
GSM modem (1-port) converter now attached to ttyUSB1
GSM modem (1-port) converter now attached to ttyUSB2

Run the gammu config and set port to /dev/ttyUSB0

sudo gammu-config

Check if gammu can identify the modem

sudo gammu --identify
Device               : /dev/ttyUSB0
Manufacturer         : Huawei
Model                : unknown (E398)
Firmware             : xxx
IMEI                 : yyy
SIM IMSI             : zzz

All good! Now you should be able to send an sms like so

sudo gammu sendsms TEXT [phonenumber] -text "Ohhai"

Automatically switch mode when inserted or after reboot

After a reboot or unplug and reinsert the modem usually switches mode again. To make sure we always are in modem mode you need to create a config for usb_modeswitch matching the vendor ID and product ID.

sudo nano /etc/usb_modeswitch.d/12d1:1505
DefaultVendor=0x12d1
DefaultProduct=0x1505
TargetVendor=0x12d1
TargetProduct=0x1506
MessageContent="55534243123456780000000000000011062000000100000000000000000000"

Symlink to /dev/sms for consistency

It might be a good idea to create a symlink for your device so your settings for gammu always works, otherwise sometimes after reboot it might switch to /dev/ttyUSB1 or whatever.

sudo nano /etc/udev/rules.d/999-sms-gateway.rules
# Add this line 
SUBSYSTEM=="tty", ATTRS{idVendor}=="12d1", ATTRS{idProduct}=="1506", SYMLINK+="sms"
# Then
sudo udevadm control --reload

Forward texts with WebHook

I wanted to send all received texts to my Huginn instance and from there to Pushover. Huginn supports a bunch of services so if you prefer Slack or even Twitter that's no problem!

I'm using a modified version of this script.

Install gammu-smsd and configure it.

sudo apt-get install gammu-smsd
sudo pip install requests

sudo nano /etc/gammu-smsdrc
# Change the port in the [gammu] section to your device
# Add the RunOnReceive in the [smsd] section.
# RunOnReceive = python /opt/gammu/receivesms.py

sudo service gammu-smsd restart

Feel free to change the path of the script, I put in it /opt/gammu and chown:ed the dir to gammu.

Modified version of the script

#!/usr/bin/env python

from __future__ import print_function
import os, sys, re, requests

def get_message():
    files = [os.path.join('/var/spool/gammu/inbox/', m) for m in sys.argv[1:]]
    files.sort() # make sure we get the parts in the right order
    number = re.match(r'^IN\d+_\d+_\d+_(.*)_\d+\.txt', os.path.split(files[0])[1]).group(1)
    text = ''
    for f in files:
        text += open(f, 'r').read()
    try:
        text = text.decode('UTF-8', 'strict')
    except UnicodeDecodeError:
        text = text.decode('UTF-8', 'replace')
    return number, text

number, text = get_message()

request = requests.post('YOUR_HUGINN_URL', data={
    'from': number,
    'message': text
})

To get the url for Huginn, all you need to do is to create a Webhook Agent. Now try sending a text to your phonenumber and it should show up in Huginn! From there you can forward it to whatever service you prefer, either with one of the built-in Agents or a regular WebHook with Post Agent.

If you have any questions drop me an email or tweet me.