Sunday, December 10, 2006

e-mail to SMS (email2SMS )

We talked about how to set up a simple SMS based service before using free and open software. Next we'd look how we can use this in to more practical use. In this example I will try to demonstrate how to develop a simple e-mail to SMS solution. It is assumed that the mail server is an internal server on the local LAN (example the intranet server).

Here again we will use Linux but this can even be applied on FreeBSD and alike. We will use Kannel as the SMS gateway, postfix as the MTA. As for a MDA (mail deliver agent) we will use procmail. You need to install all of this on your system before we start. Also we will be again using Perl as the scripting language. The diagram below illustrates the simple over view of how the system works.

The system is designed to send sms using the internal mail system. The sender needs to be a predefined user of the mail system to use this system. A set number of sms recipients is set. Example send to 10 people (customers) with a single mail. Logs of emails sent will be kept on the system. System will also sent the sms to a given list of numbers; for each email (system usage).

To start off we first setup postfix. The default configuration of postfix is used. Please insert the following line to the postfix configuration file fount at /etc/postfix/. Append the line below to the file main.cf, to edit this file login as root and use a text editor like vim.

mailbox_command = /usr/bin/procmail

Explanation:
The mailbox_command parameter specifies the optional external command to use instead of mailbox delivery. The command is run as the recipient with proper HOME, SHELL and LOGNAME environment settings. Exception: delivery for root is done as $default_user. Other environment variables of interest: USER (recipient username), EXTENSION (address extension), DOMAIN (domain part of address), and LOCAL (the address localpart). Unlike other Postfix configuration parameters, the mailbox_command parameter is not subjected to $parameter substitutions.
- from the man pages -

IF YOU USE THIS TO DELIVER MAIL SYSTEM-WIDE, YOU MUST SET UP AN ALIAS THAT FORWARDS MAIL FOR ROOT TO A REAL USER.

To overcome the above issue please edit the fie aliases in /etc. Append the following line to the bottom of the page.

root: sms

also add the following line to file virtual at /etc/postfix.

@intranet.ourcompany.com sms

This will make the system to catch all mails to the sms user account.

Also add(modify) the following 2 line to the main.cf file.

myhostname = intranet.ourcompany.com
mydomain = ourcompany.com

Procmail configuration

create a file named .procmailrc in the /home/sms folder. Add the following line to the file and save the file.

TO=`formail -xTo:`
SUBJECT=`formail -xSubject: \
| expand | sed -e 's/^[ ]*//g' -e 's/[ ]*$//g'`
SENDER=`formail -xFrom: \
| expand | sed -e 's/^[ ]*//g' -e 's/[ ]*$//g'`
BODY= `formail -I "" \
| expand | sed -e '1,/^$/ d' -e '1,/^$/ d'`
BODY=`formail -I "" `
SENDER=`formail -rtzxTo:`
:0
| perl /home/sms/massms/newsms.pl $SENDER $TO $SUBJECT $BODY >> /home/sms/massms/maillog.txt

The above configuration sets up variables for each required filed and then passes these as parameters to a scrip called newsms.pl located at /home/sms/massms/

The script (newsms.pl)
use POSIX qw(strtod);
use LWP::Simple;

#if ($#ARGV !=1) {
# print "usage :sendsms \n";
# exit;
#}

$from = $ARGV[0];
$number = $ARGV[1];
$subject = $ARGV[2];
$text = $ARGV[3];
$maxsend = 10;

print 'params: ' .$from . ' ' . $number . ' ' . $subject . ' '. $text . "\n";

sub getnum {
my $str = shift;
$str =~ s/^\s+//;
$str =~ s/\s+$//;
$! = 0;
my($num, $unparsed) = strtod($str);
if (($str eq '') || ($unparsed != 0) || $!) {
return;
} else {
return $num;
}
}

sub trim($)
{
my $string = shift;
$string =~ s/^\s+//;
$string =~ s/\s+$//;
return $string;
}

my @orinum = split('@', $number);
print 'orinum: '. $orinum[0] . "\n";
$orinum[0] =~ s/^;
$orinum[0] = trim($orinum[0]);

$words = @ARGV;

$text= "";
for ($r=3;$r<=$words;$r++){
$text = $text . " " . $ARGV[$r];
}
$text = trim($text);
print 'text: '. $text . "\n";
#$text =~ s/<(.*?)>//gi;
# $orinum[0]=~ s/\D//gi;
#print $text;

@months = qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec);
@weekDays = qw(Sun Mon Tue Wed Thu Fri Sat Sun);
($second, $minute, $hour, $dayOfMonth, $month, $yearOffset, $dayOfWeek, $dayOfYear, $daylightSavings) = localtime();
$year = 1900 + $yearOffset;
$theTime = "$hour:$minute:$second, $weekDays[$dayOfWeek] $months[$month] $dayOfMonth, $year";
print 'time: ' . $theTime;

sub authuser {
my ($fromuser) = @_;
print 'in function ' . $fromuser . "\n";
$okuser = 0;
my @user = split('@', $fromuser);
print 'passed to authuser as @: ' . @_ . "\n";
print 'the user:'. $user[0] ."\n";
open (CHECKBOOK, "/home/sms/massms/access.list") || die "couldn't open the access list file!";
print "file open \n";
while ($record = ) {
if (lc(trim($record)) eq lc(trim($user[0]))) {
$okuser = 1;
}
print lc(trim($record)) . " <> " . lc(trim($user[0])) . "\n";
}

close(CHECKBOOK);

return $okuser;
}

sub sendEmail
{
my ($eto, $efrom, $esubject, $emessage) = @_;
my $sendmail = '/usr/lib/sendmail';
open(MAIL, "|$sendmail -oi -t");
print MAIL "From: $efrom\n";
print MAIL "To: $eto\n";
print MAIL "Subject: $esubject\n\n";
print MAIL "$emessage\n";
close(MAIL);
}

$orimail = 'smsdemon@intranet.ourcompany.com';
print 'da user is: '. $from . "\n";
$isitoktosend = authuser($from);
my $sent = 0;
if ($isitoktosend eq 1) {
#if user is authorised to send sms
print "auth ok \n";
my @sendlist = split (',',$subject);
my $listcount = @sendlist;
print $listcount . ' > ' . $maxsend . "\n";
if ($listcount <= $maxsend) {
#send list cannot exceed more then maxsend if only less
print "in if list and max\n";
my $longnumbers = 'sms sent to ';
foreach (@sendlist) {
$ournumber = $_ ;
if ($ournumber =~ /^9609/i) { # all numbers should have 9609
my $url = 'http://127.0.0.1:5034/cgi-bin/sendsms?username=usr&password=password&from=' . $orinum[0] .'&to=' . $_ . '&text='. $text ;
$html = getprint ($url); # ok shoot to kannel to send sms
$lognumbers = $lognumbers . ',' . $_ ;
$sent = 1;
}
}
if ($sent eq 1) {
$lognumbers = $lognumbers . ' with the message : ' . $text;
sendEmail ($from, $orimail , 'sent sms status' , 'sms sent to ' . $lognumbers);
open(FILE,">>/home/sms/massms/log/sent.log") or die "cannot create file";
print FILE $theTime . ' ' . 'from:' . $from . ' ' . ' sent through: '. $number . ' >' . $lognumbers . "\n";
close(FILE);

# enable to send every time to follwing numbers the sms for control
my $alwayssendlist ='9609620001,9609620002'; #change as needed
my @loopsend = split(',',$alwayssendlist);
foreach (@loopsend) {
my $url = 'http://127.0.0.1:5034/cgi-bin/sendsms?username=user&password=password&from=' . $orinum[0] .'&to=' . $_ . '&text='. $text ;
$html = getprint ($url); # ok shoot to kannel to send sms
}

print "sent";
}
} else {
sendEmail ($from, $orimail , 'sent sms status' , 'error : cannot send to more then ' . $maxsend . ' numbers');
print "send list exceed err:";
}
} else {
# sendEmail ($from, $orimail , 'sent sms status' , 'error: sorry you do not have authorization to use this service');
print "cannot send";
}

A close look at the code. I've designed it to have some security levels. You can modify as you need. The control measures are that there is an access list. You need to have your email address in the access file for you to send the SMS. Next I have implemented a control to copy all SMS to a given list of numbers. These can be taken off the script as you wish. But the basic thing is there.

This demonstrates how simple and easy it is to get these sort of things done. Maybe next time I'd try to post about how to do the reverse. SMS2email. With little effort the script can be changed together with the system to bring better improvements.

2 comments:

kim said...

Hi,

I just want to ask how this works?I follow what you did here but it's not working for me.. is this all what you did? where can I find the email send to mail server? hope you can answer me thanks...

hawodi said...

Hello,
Thanks for the tutorial. Any lead on how I can reverse i.e sms2email?

Thanks again