FUN WITH LINUX

Hack A Day: Lets make a Mail2SMS-Gateway using the Raspberry Pi

6 February 2015

If you are monitoring services, you also might want to get informed about critical states via sms. Almost everyone has an old mobile phone at home. Why not using one of those old mobile-phones? In this article I will describe how to transform your raspberry into a mail2sms-gateway. This gateway will be able to:

  • receive emails and forward them via sms
  • receive sms and forward them via email
  • provide a webinterface for sending sms manually

##

##

What is Mail2SMS?

Mail2SMS is a service which receives emails and forwards them via sms. In that way we are able to send sms via email. The “Email Body” is the “sms message”, but where do we place the phone-number? Until now i used a commercial mail2sms-service. They placed the phone-number at the first part of the “Email TO Header”, like: <phonenumber>@mail2sms-service.com. I will handle it the same, because in that way i haven’t to change the notification-scripts for my monitoring-system.

We used a commercial mail2sms-gateway until now but it was very expensive. Now we have our own sim-card with 1000 free sms/month.

How do we realize it?

  1. Postfix(SMTP-Daemon) at our raspberry is waiting for emails
  2. Postfix passes the emails to my smsgw.pl-script
  3. smsgw.pl reads phone-number and message-text and calls “gammu-smsd-inject”
  4. gammu-smsd is a daemon which communicates with our phone(which is connected via USB) and sends our sms

Other features?

Beside forwarding emails via sms we will provide the following features:

  • receiving sms and forwarding them via email( gammu->sms2mail.pl->postfix )
  • sending sms manually via webgui ( lighttpd -> sms.pl(cgi) -> gammud )

##
Lets start with the postfix-config

Our domain for sms will be: sms.example.com

Let’s install postfix and set our mailname first:

apt-get install postfix

/etc/mailname:

sms.example.com

This is our /etc/postfix/main.cf:

# See /usr/share/postfix/main.cf.dist for a commented, more complete version

# Debian specific: Specifying a file name will cause the first
# line of that file to be used as the name. The Debian default
# is /etc/mailname.
#myorigin = /etc/mailname

smtpd_banner = $myhostname ESMTP $mail_name (Debian/GNU)
biff = no

# appending .domain is the MUA's job.
append_dot_mydomain = no

# Uncomment the next line to generate "delayed mail" warnings
#delay_warning_time = 4h

readme_directory = no

# TLS parameters
smtpd_tls_cert_file=/etc/ssl/certs/ssl-cert-snakeoil.pem
smtpd_tls_key_file=/etc/ssl/private/ssl-cert-snakeoil.key
smtpd_use_tls=yes
smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache

# See /usr/share/doc/postfix/TLS_README.gz in the postfix-doc package for
# information on enabling SSL in the smtp client.

transport_maps = hash:/etc/postfix/transport

myhostname = sms.example.com
alias_maps = hash:/etc/aliases
alias_database = hash:/etc/aliases
myorigin = /etc/mailname
mydestination = sms.example.com, localhost.localdomain, localhost
relayhost =
mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128
mailbox_size_limit = 0
recipient_delimiter = +
inet_interfaces = all

local_recipient_maps =

This we have to append to our /etc/postfix/master.cf:

sms unix - n n - - pipe
  flags=Rq user=pi argv=/usr/local/bin/smsgw.pl -f ${sender} -r ${recipient}

And finally we just need this in our /etc/postfix/transport:

sms.example.com sms

(Be aware that you have to do a “postmap /etc/postfix/transport” after you changed or created this file)

After all just restart postfix: /etc/init.d/postfix restart

smsgw.pl

/usr/local/bin/smsgw.pl is our small little script which recieves emails from postfix, parses all the necessary informations and calls “gammu gammu-smsd-inject”. We need to install log4perl and touch the logfile:

apt-get install liblog-log4perl-perl


root@sms:~# touch /var/log/smsgw.log
root@sms:~# chown pi /var/log/smsgw.log
root@sms:~# ls -l /var/log/smsgw.log
-rw-r--r-- 1 pi root 29150592 Feb 6 13:20 /var/log/smsgw.log

/usr/local/bin/smsgw.pl:

#!/usr/bin/perl

# Copyright (C) 2017 Wolfgang Hotwagner <code@feedyourhead.at>       
#                                                                
# This file is part of mail2sms                                
# 
# This program is free software; you can redistribute it and/or 
# modify it under the terms of the GNU General Public License 
# as published by the Free Software Foundation; either version 2 
# of the License, or (at your option) any later version.
# 
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License          
# along with this program; if not, write to the 
# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, 
# Boston, MA  02110-1301  USA 


use Log::Log4perl;
use Getopt::Std;

my %options=();
getopts("r:f:h", \%options);

my $logconf = q(
log4perl.rootLogger                = DEBUG,Logfile
log4perl.appender.Logfile          = Log::Log4perl::Appender::File
log4perl.appender.Logfile.filename = /var/log/smsgw.log
log4perl.appender.Logfile.layout   = Log::Log4perl::Layout::PatternLayout
log4perl.appender.Logfile.layout.ConversionPattern = [%r] %F %L %m%n
log4perl.appender.Screen         = Log::Log4perl::Appender::Screen
log4perl.appender.Screen.stderr  = 0
log4perl.appender.Screen.layout = Log::Log4perl::Layout::SimpleLayout
);

my $line = undef;
my $mailstring = undef;
my $from = undef;
my $to = undef;
my $subject = undef;
my $out = 0;

Log::Log4perl::init( \$logconf);
my $log = Log::Log4perl::get_logger("smsgw");

if($options{h})
{
        $log->logdie("usage: smsgw.pl -f  -r ");
}

$log->logdie("-f option is missing use -h for help") if not defined($options{f});
$log->logdie("-r option is missing use -h for help") if not defined($options{r});

$from = $options{f};
$to = $options{r};

$log->info("Mail kommt rein..");

while(defined($line = <STDIN> ))
{
	$log->debug("LINE: \"$line\"");

        if($line =~ m/^subject: (.*)\n/i) { $subject = $1; }

	if( ($line eq "\n") && ($out != 1) )
        {
                $log->info("NOW IT MESSAGE-PART");
                $log->info("BECAUSE: ..$line..");
                $out = 1;
        }
        else
        {
                $mailstring .= $line if($out == 1);
        }
}

$log->info("FROM: $from");
$log->info("TO: $to");
$log->info("SUBJECT: $subject");
$log->info("MAIL: $mailstring");

my $telnumber = 0;
if($to =~ m/^(\d+)@/)
{
        $telnumber = $1;
}

if($telnumber == 0)
{
        $log->logdie("not a number-format!");
}

$log->info("NUMBER: $telnumber");

my $smsstring = "sudo -u gammu gammu-smsd-inject TEXT $telnumber -text \"$mailstring\"";
$log->info("$smsstring");

my $output = `$smsstring`;
$log->warn("$output");
root@smsgateway:~# chmod o+rx /usr/local/bin/smsgw.pl

Gammu

For communications with our USB-connected mobile-phone, we use the gammu-smsd. This daemon is able to send and receive sms using a queue. So sms don’t get lost even if we power off the raspberry during a transfer. This our gammurc:

# Configuration file for Gammu SMS Daemon

# Gammu library configuration, see gammurc(5)
[gammu]
port=/dev/ttyACM0
connection=at
name=Sony Ericsson S500i/S500c
logformat = textall
# Please configure this!
#port = /dev/null
#connection = at
# Debugging
#logformat = textall

# SMSD configuration, see gammu-smsdrc(5)
[smsd]
service = files
logfile = /var/log/gammu-smsd
# Increase for debugging information
debuglevel = 0
ReceiveFrequency = 300

# Paths where messages are stored
inboxpath = /var/spool/gammu/inbox/
outboxpath = /var/spool/gammu/outbox/
sentsmspath = /var/spool/gammu/sent/
errorsmspath = /var/spool/gammu/error/

Restart the daemon after you connected the phone with /etc/init.d/gammu-smsd restart

Connecting the phone

At this point our mail2sms-service should work. We can connect our phone now with our raspberry. On some phones it is important to use it in “phone modus”.

Now we can test via telnet:

dr@tardis:/# telnet sms.example.com 25
Trying 172.30.50.31...
Connected to sms.example.com.
Escape character is '^]'.
220 sms.example.com ESMTP Postfix (Debian/GNU)
helo sms.example.com
250 sms.example.com
mail from: dr@tardis
250 2.1.0 Ok
rcpt to: 0190222222@sms.example.com
250 2.1.5 Ok
data
354 End data with .
allons-y allonso
.
250 2.0.0 Ok: queued as 58F7C146B1
quit
221 2.0.0 Bye
Connection closed by foreign host.

Sms2mail

We also want to forward all received sms via email to a specific email-address. For this we will simply start a cron-job which calls a script called sms2mail.pl. This script simply checks the inbox-queue of gammu-smsd and forwards all sms via email to a pre-defined email-address.

/usr/local/bin/sms2mail.pl:

#!/usr/bin/perl

# IN20130307_171617_00_+43190222222_00.txt

my $spooldir = '/var/spool/gammu/inbox/';
my $file = undef;
my $date = undef;
my $tel = undef;
my $subject = undef;

# CHANGE THIS EMAIL-ADDRESS
my $recipient = 'dr@tardis';

opendir(D,$spooldir) || die "Can't open dir: $!\n";

while($file = readdir(D))
{

        if($file =~ m/IN(\d\d\d\d)(\d\d)(\d\d)_(\d\d)(\d\d)\d\d_\d{1,2}_(.*)_\d{1,2}.txt/g)
        {
                $date = "$1-$2-$3 $4:$5";
                $tel = $6;
                $subject = "SMS from $tel at $date";

                `cat $spooldir/$file | mutt -s "$subject" -- $recipient`;
                unlink "$spooldir/$file";
        }
}

closedir(D);
root@sms:~# chmod 700 /usr/local/bin/sms2mail.pl
root@sms:~# apt-get install cron
root@sms:~# echo "*/2 * * * * /usr/local/bin/sms2mail.pl" >> /var/spool/cron/crontabs/root

Webservice

Last but not least we also want to create a website for sending sms manually. We will install lighttpd which calls a simple cgi-script.

root@smsgateway:~# apt-get install lighttpd spawn-fcgi sudo

/etc/lighttpd/lighttpd.conf:

server.modules = (
        "mod_access",
        "mod_alias",
        "mod_compress",
        "mod_redirect",
# "mod_rewrite",
)

server.document-root = "/var/www"
server.upload-dirs = ( "/var/cache/lighttpd/uploads" )
server.errorlog = "/var/log/lighttpd/error.log"
server.pid-file = "/var/run/lighttpd.pid"
server.username = "www-data"
server.groupname = "www-data"
server.port = 80


index-file.names = ( "index.php", "index.html", "index.lighttpd.html" )
url.access-deny = ( "~", ".inc" )
static-file.exclude-extensions = ( ".php", ".pl", ".fcgi" )

compress.cache-dir = "/var/cache/lighttpd/compress/"
compress.filetype = ( "application/javascript", "text/css", "text/html", "text/plain" )

# default listening port for IPv6 falls back to the IPv4 port
include_shell "/usr/share/lighttpd/use-ipv6.pl " + server.port
include_shell "/usr/share/lighttpd/create-mime.assign.pl"
include_shell "/usr/share/lighttpd/include-conf-enabled.pl"

/etc/lighttpd/conf-available/10-cgi.conf:

# /usr/share/doc/lighttpd/cgi.txt

server.modules += ( "mod_cgi" )

$HTTP["url"] =~ "^/cgi-bin/" {
        cgi.assign = ( "" => "" )
}

## Warning this represents a security risk, as it allow to execute any file
## with a .pl/.py even outside of /usr/lib/cgi-bin.
#
cgi.assign = (
        ".pl" => "/usr/bin/perl",
# ".py" => "/usr/bin/python",
)
root@sms:/etc/lighttpd# ln -s /etc/lighttpd/conf-available/10-cgi.conf /etc/lighttpd/conf-enabled/10-cgi.conf
root@sms:/etc/lighttpd# /etc/init.d/lighttpd restart

Add the following line to /etc/sudoers:

www-data ALL=(ALL) NOPASSWD:/usr/bin/gammu-smsd-inject

Place this script to /var/www/sms.pl:

#!/usr/bin/perl

print "Content-type: text/html\n\n";
print '', "\n";
print '

'; exit 0;

..and change the permissions:

root@sms:/var/www# chmod 755 /var/www/sms.pl

Where to go from here?

Our index.html is still missing. You can all sources and configs in the download-area https://github.com/whotwagner/mail2sms. Beside this, I would recommend to make some monitoring so that you can be sure that the gateway is working. I created some nagios-scripts for this, but that’s another story…

[ Linux  Sysadmin  HackADay  Raspberry  ]
Except where otherwise noted, content on this site is licensed under a Creative Commons Attribution 3.0 Unported License.

Copyright 2015-present Hoti