GAMMU-SMSD-RUN(7)

πŸ’… GAMMU-SMSD-RUN(7) β€” the RunOnReceive glow-up guide πŸ’…

okay so this is the <pink>Gammu</pink> manual page for gammu-smsd-run, and it's literally all about the RunOnReceive directive. bestie, if you've ever wanted SMSD to do stuff the second a message lands, this is your page. let's get into it 🫢


✨ NAME ✨

gammu-smsd-run β€” the documentation for the RunOnReceive directive. that's it, that's the name, slay.


🌸 DESCRIPTION 🌸

so <hotpink>Gammu SMSD</hotpink> can be set up with the RunOnReceive directive (peep the SMSD Configuration File for the deets) to run a program you choose after it receives every single message. and like, it can receive one message or a whole bunch of messages that are parts of one multipart message. multipart representation, we love to see it πŸ’…

the command you configure can totally include parameters. SMSD appends the identifiers of the received messages as extra arguments. those identifiers depend on the service backend β€” typically database row IDs, or file names for the files backend. oh and btw, file names do not include the inbox directory. multipart messages can hand you multiple arguments, so your scripts have to handle all the identifiers they get. no skipping, fr fr.

on POSIX systems, the configured command runs through a shell, so any special characters in that command need escaping. message identifiers get passed as separate literal arguments. SMSD waits for the script to terminate, which means slow scripts can delay receiving new messages 😭 and do not β€” i repeat, do NOT β€” rely on a fixed timeout to interrupt a blocked script.

on Windows, SMSD starts the configured executable directly. batch files need an explicit command interpreter, like the example further down ("Running a batch file on Windows"). SMSD does not wait for the process to finish and does not collect its exit status. so hooks can overlap, bestie, and a successful process creation does not mean message forwarding actually succeeded. it's giving "started, not finished" πŸ’€

Note: on POSIX systems, standard input is closed and standard output and standard error get captured in the SMSD log. on Windows, the hook has to arrange its own output and error logging. scripts should not require interactive input. like, ever. πŸ™ˆ

πŸ¦‹ ENVIRONMENT πŸ¦‹

added in version 1.28.0, iconic behavior.

the program runs with an environment that contains a lot of info about the message. you can use it together with the NULL service (see Null Backend) to implement completely your own processing of messages. main character energy tbh πŸ‘‘

⭐ Global variables

  • SMS_MESSAGES β€” number of physical messages received.
  • DECODED_PARTS β€” number of decoded message parts.
  • PHONE_ID β€” added in version 1.38.2. it's the value of PhoneID. super useful when you're running multiple instances (see Multiple modems). this variable is available to all RunOn directives, including calls which don't provide message details. versatile queen πŸ’œ

πŸŽ€ Per message variables

the variables described as SMS_1_... are generated for each physical message, where 1 is replaced by the current number of the message. ok so:

  • SMS_1_CLASS β€” class of message.
  • SMS_1_NUMBER β€” sender number.
  • SMS_1_TEXT β€” message text. heads up: text is not available for 8-bit binary messages.
  • SMS_1_REFERENCE β€” added in version 1.38.5. Message Reference. if a delivery status was received, this variable contains the TPMR of the original message.
  • SMS_1_SENT_ID β€” for a delivery report matched by a database backend, the ID of the corresponding row in the sentitems table. the value is empty for other messages, when no matching sent message was found, and for non-database backends.
  • SMS_1_TIMESTAMP β€” message date and time as seconds since the Unix epoch. for a received message this is the service center timestamp. for a delivery report this is the time when the service center received the original message. the value is empty when the message doesn't contain a valid date and time.
  • SMS_1_DATETIME β€” same value as SMS_1_TIMESTAMP, formatted as ISO 8601 with a timezone offset, for example 2024-01-02T03:04:05+01:30.
  • SMS_1_SMSC_TIMESTAMP β€” for a delivery report, the discharge time as seconds since the Unix epoch. the value is empty for other messages or when the report doesn't contain a valid discharge time.
  • SMS_1_SMSC_DATETIME β€” same value as SMS_1_SMSC_TIMESTAMP, formatted as ISO 8601 with a timezone offset.

🌈 Per part variables

the variables described as DECODED_1_... are generated for each message part, where 1 is replaced by the current number of the part. only the variables whose content is actually present in the message get set. no filler, we respect that πŸ’…

  • DECODED_1_TEXT β€” decoded long message text.
  • DECODED_1_MMS_SENDER β€” sender of MMS indication message.
  • DECODED_1_MMS_TITLE β€” title of MMS indication message.
  • DECODED_1_MMS_ADDRESS β€” address (URL) of MMS from MMS indication message.
See also: Can I use Gammu to receive MMS?
  • DECODED_1_MMS_SIZE β€” size of MMS as specified in MMS indication message.

πŸ”₯ EXAMPLES πŸ”₯

🌸 Activating RunOnReceive

to activate this feature you need to set RunOnReceive in the SMSD Configuration File. literally two lines, you got this:

[smsd]
RunOnReceive = /path/to/script.sh

🧚 Running a batch file on Windows

use cmd.exe to launch a batch file. for example, with the script and inbox in C:\gammu:

[smsd]
RunOnReceive = C:\Windows\System32\cmd.exe /d /c C:\gammu\forward_sms.bat

adjust these absolute paths so they match your installation, and restart SMSD after changing the configuration. also note the example uses paths without spaces. πŸ™ˆ

do not add "%FILE%" β€” that is not a Gammu placeholder. SMSD appends the received file names automatically.

for example, the batch file receives IN20260228_053040_00_+61402111111_00.txt as its first argument. inside the batch file, %1 accesses that argument and %~1 removes surrounding quotes. with the inbox above, the full path is C:\gammu\%~1. and process subsequent arguments too, for example using shift in a loop. don't leave args hanging, bestie 😭

use absolute paths for the inbox, address book, log files, and helper programs. the hook inherits SMSD's working directory, which does not have to be the script or inbox directory. when you move SMSD to a Windows service, make sure the service account can access these files and any credentials the forwarding program needs. πŸ”‘

to test invocation separately from email delivery, save the following as C:\gammu\receive-test.bat and temporarily use that path in RunOnReceive:

@echo off
setlocal DisableDelayedExpansion
>>C:\gammu\receive-hook.log echo Hook started
>>C:\gammu\receive-hook.log set SMS_MESSAGES
>>C:\gammu\receive-hook.log set SMS_1_NUMBER

restart SMSD and send a fresh SMS. a new entry in receive-hook.log confirms the batch file started. if no entry appears, check the SMSD log for Starting run on receive and CreateProcess failed, and check that the account running SMSD can write the diagnostic log. restore the forwarding script path after testing β€” and its own log should record processing and email delivery errors, because Windows SMSD does not collect the script's output or exit status. periodt πŸ’…

πŸŽ€ Forwarding messages with an address book

a forwarding program can match SMS_1_NUMBER against the Number column of a CSV address book and use the corresponding Name in the email subject. store and compare phone numbers in a consistent format, for example international numbers beginning with +, and use the sender's number when no name matches. consistency is key, bestie ✨

for multipart text, use the available DECODED_n_TEXT variables described above, or process all file arguments. do not assume SMS_1_TEXT contains the entire message. read message text as data inside the forwarding program rather than expanding it into batch commands β€” otherwise SMS characters could get interpreted as command syntax, and that's a big yikes πŸ’€

configure SMTP authentication in the forwarding program. that program is also responsible for logging delivery failures and retaining pending messages for retry. starting a hook does not guarantee email delivery, ngl.

πŸ¦‹ Processing messages from the files backend

the following script (if used as a RunOnReceive handler) passes message data to another program. this works only with the Files backend:

#!/bin/sh
INBOX=/path/to/smsd/inbox
PROGRAM=/bin/cat
for ID in "$@" ; do
    $PROGRAM < $INBOX/$ID
done

⭐ Invoking commands based on message text

the following script (if used as a RunOnReceive handler) executes given programs based on message text. cute lil dispatcher, honestly:

#!/bin/sh

# Check for sender number
if [ "$SMS_1_NUMBER" != "+420123456789" ] ; then
    exit
fi

# Handle commands
case "$SMS_1_TEXT" in
    "DMS A")
        /usr/bin/dms-a
        ;;
    "DMS B")
        /usr/bin/dms-b
        ;;
esac

πŸ“ Passing message text to program

the following script (if used as a RunOnReceive handler) passes message text and sender to an external program:

#!/bin/sh
PROGRAM=/bin/echo
for i in `seq $SMS_MESSAGES` ; do
    eval "$PROGRAM \"\${SMS_${i}_NUMBER}\" \"\${SMS_${i}_TEXT}\""
done

πŸ’œ Passing MMS indication parameters to external program

the following script (if used as a RunOnReceive handler) will write information about each received MMS indication to the log file. just replace the echo command with your own program to do custom processing. swap in your fave and go off πŸ‘‘

#!/bin/sh
if [ $DECODED_PARTS -eq 0 ] ; then
    # No decoded parts, nothing to process
    exit
fi
if [ "$DECODED_1_MMS_ADDRESS" ] ; then
    echo "$DECODED_1_MMS_ADDRESS" "$DECODED_1_MMS_SENDER" "$DECODED_1_MMS_TITLE" >> /tmp/smsd-mms.log
fi

🌈 Processing message text in Python

the following script (if used as a RunOnReceive handler) written in Python will concatenate all text from a received message:

#!/usr/bin/env python

import os

numparts = int(os.environ["DECODED_PARTS"])

text = ""
# Are there any decoded parts?
if numparts == 0:
    text = os.environ["SMS_1_TEXT"]
# Get all text parts
else:
    for i in range(1, numparts + 1):
        varname = "DECODED_%d_TEXT" % i
        if varname in os.environ:
            text = text + os.environ[varname]

# Do something with the text
print("Number {} have sent text: {}".format(os.environ["SMS_1_NUMBER"], text))

πŸ‘‘ Author πŸ‘‘

Michal ČihaΕ™ <michal@cihar.com> β€” the legend themselves πŸ’–

2009-2015, Michal ČihaΕ™ <michal@cihar.com>


and that's the page, bestie! 🫢 this whole thing lives in the 1.45.0 era, dated Sep 16, 2026. go forth and let your hooks slay πŸ’…βœ¨πŸŒΈ

πŸ“¦ where this page comes from