Skip to content

Instantly share code, notes, and snippets.

@rcoup rcoup/.gammurc
Last active Sep 30, 2018

What would you like to do?
Gammu config and script for receiving SMS via a USB modem attached to an OSX computer and forwarding it into iMessage, where it will appear on all your devices.
port = /dev/tty.HUAWEIMobile-Modem
connection = at19200
model = at
synchronizetime = yes
logfile = /Users/me/.gammu/log
logformat = errorsdate
gammucoding = utf8
Service = files
CheckSecurity = 0
LogFile = /Users/me/Library/logs/gammu.log
InboxPath = /Users/me/.gammu/inbox/
OutboxPath = /Users/me/.gammu/outbox/
SentSMSPath = /Users/me/.gammu/sent/
ErrorSMSPath = /Users/me/.gammu/error/
DebugLevel = 1
RunOnReceive = python /Users/me/.gammu/ +447700900000 NZ
CheckBattery = 0

Idea (swap out the countries & numbers):

  • You live in the UK, with a UK mobile number and an iPhone (eg. +447700900000)
  • And have a New Zealand sim card and number (eg. +6421000000), in a USB modem attached to your Mac (permanently roaming)
  • When somebody SMSs your New Zealand number, make it appear in iMessage on your UK phone
  1. Get a USB modem that works on OSX. I use an ancient Huawei E220 I found on eBay. Check it's unlocked for your SIM and can send/receive texts using the vendor's Mac software.
  2. Install Gammu via git or homebrew.
  3. Put into ~/.gammu, and the .gammurc file into ~. Edit the paths in the files.
  4. Manually start the daemon with gammu-smsd -c .gammurc --pid .gammu/pid, then look at ~Library/logs/gammu.log and ~/Library/logs/gammu-forwardToIMessage.log for debugging help. Send yourself some SMS messages to test.
  5. Once it's working, to start it on boot (so it will pick up messages whenever you connect/disconnect the USB dongle), update the paths in the .plist file and drop it into ~/Library/LaunchAgents, then:
    launchctl load -w ~/Library/LaunchAgents/gammu.IMessageForwarder.plist`
    launchctl start gammu.IMessageForwarder


  • SMSing an iMessage number via iMessage won't actually send an SMS. Using Skype if you need to test SMS is pretty cheap and easy.
  • If you get AppleScript errors, have a go at sending to your iMessage email address rather than your iMessage number. (change RunOnReceive in ~/.gammurc)
  • Has been working under Sierra, El Capitan, and Mavericks.
#!/usr/bin/env python
from __future__ import print_function
import logging
import os
import re
import subprocess
import sys
TEMPLATE = u"%(country)s%(number)s: %(message)s"
on run {targetBuddyPhone, targetMessage}
tell application "Messages"
set targetService to 1st service whose service type = iMessage
set targetBuddy to buddy targetBuddyPhone of targetService
send targetMessage to targetBuddy
end tell
end run
LOG = os.path.expanduser('~/Library/logs/gammu-forwardToIMessage.log')
L = logging.getLogger("forwardToIMessage")
class SMSError(Exception):
class IMessageError(Exception):
def flag(code):
OFFSET = 127397
if not code:
return u''
points = [ord(x) + OFFSET for x in code.upper()]
return chr(points[0]) + chr(points[1])
except ValueError:
return ('\\U%08x\\U%08x' % tuple(points)).decode('unicode-escape')
def get_message(files):
if not files:
# get from environment
number = os.environ['SMS_1_NUMBER']
# Are there any decoded parts?
numparts = int(os.environ['DECODED_PARTS'])
if numparts:
# Get all text parts
text = ''
for i in range(0, numparts):
varname = 'DECODED_%d_TEXT' % i
if varname in os.environ:
text = text + os.environ[varname]
text = os.environ['SMS_1_TEXT']
files.sort() # make sure we get the parts in the right order
number = re.match(r'^IN\d+_\d+_\d+_(\+?\d+)_\d+\.txt', os.path.split(files[0])[1]).group(1)
L.debug('Files: parsed sending number as: %s', number)
text = ''
for f in files:
L.debug('Files: parsing: %s', f)
text += open(f, 'r').read()
text = text.decode('UTF-8', 'strict')
except UnicodeDecodeError:
L.exception("Error decoding message as utf-8, falling back to '?' replacement: [%s]", repr(text))
text = text.decode('UTF-8', 'replace')
return number, text
def send_imessage(recipient, text):
args = ['osascript', '-', recipient, text.encode('utf-8')]
L.debug("Invoking AppleScript: %s", args)
p = subprocess.Popen(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
stdout, _ = p.communicate(APPLESCRIPT)
L.debug("AppleScript results: %d: %s", p.returncode, stdout)
if p.returncode:
raise IMessageError("Error %d sending (%r %r): %s" % (p.returncode, recipient, text, stdout))
return stdout
def main():
filename=os.path.join(os.path.split(__file__)[0], LOG),
format='%(asctime)-15s %(levelname)s %(funcName)s:%(lineno)d %(message)s',
)"Starting: args=%s", sys.argv[1:])
L.debug("Relevant environment=%s", repr(dict([(k, v) for k, v in os.environ.iteritems() if k.startswith(("SMS_", "DECODED_"))])))
if len(sys.argv) < 3:
print >>sys.stderr, USAGE % sys.argv[0]
if 'SMS_1_NUMBER' in os.environ:
# parse from environment (default)"Getting message info from environment...")
msg_files = None
# parse from message files"No data found in environment, parsing from message files...")
msg_files = [os.path.join(os.path.split(__file__)[0], 'inbox', m) for m in sys.argv[3:]]
if not len(msg_files):
print >>sys.stderr, "No message found in environment, and no message paths specified"
print >>sys.stderr, USAGE % sys.argv[0]
sys.exit(2)"Message file paths: %s", msg_files)
recipient = sys.argv[1]
country = flag(sys.argv[2]) or sys.argv[2].upper()
number, text = get_message(msg_files)"From %s: %s", number, repr(text))
message = TEMPLATE % {'number': number, 'message': text, 'country': country}
send_imessage(recipient, message)
L.exception("Error processing message")
raise"Done :)")
if __name__ == "__main__":
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC -//Apple Computer//DTD PLIST 1.0//EN >
<plist version="1.0">
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.