Perl email SMS alert

Before getting a new smartphone, I had a razor phone, which could get SMS messages, but not web. This script checks an email account via POP3, and checks the most recent 10 messages. These messages are compared to the messages noted in the MySQL database, if there are any new messages, a small notification is emailed to my phone using an “SMS gateway”, which is an email address such as: 8005551212@tmomail.net. Most cell carriers have some sort of gateway address for forwarding from email to SMS.

Upon a new email, I would be presented with a text telling me which account to check who it’s from, and the subject. It was run from CRON every 10 minutes, like so:

1
./checkem.pl  address@toCheck.com myEmailPassword pop.gmail.com 9255551212@tmomail.net

Here’s the Perl:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
#!/usr/bin/perl

if ($ARGV[0]&&$ARGV[1]&&$ARGV[2]){
}else{
print "\n\tusage: ./checkem.pl [email address] [password] [email server] [email to alert]\n";
exit;
}

$config->{'systemsender'} = 'CoreForge Alerter <misc@coreforge.com>';
$config->{'sqlserv'} = 'localhost';
$config->{'sqluser'} = 'user';
$config->{'sqlpass'} = 'password';
$config->{'sqlbase'} = 'database';
$config->{'sqltabl'} = 'sysguard_table';

$verbose = 0;
$really_db = 1;
use warnings;

use lib "/home/sceneki/perl-libs";
use Mail::Sendmail; # outgoing
use DBI; # MySql connections
use Mail::POP3Client; # for establishing connection to mailserver
use Data::Dumper; # like print_r in php
$Data::Dumper::Indent = 3; # --pretty print with array indices

#
# Strips whitespace from variables
# usage: trim($string)
# returns: $cleanstring
sub trim($){
my $string = shift;
$string =~ s/^\s+//;
$string =~ s/\s+$//;
return $string;
}

#
# Safe keys replaces or removes bad or illegal characters based on my list
# usage: safekeys($string_in)
# returns: $string_out
sub safekeys {
$_ = $_[0];
s/“/"/g;
s/”/"/g;
s/´/'/g;
s/’/'/g;
s/‘/'/g;
s/`/'/g;
s/[^[:alnum:].:!@#\$%^&*()_+-=\[\]<>'"\/\\{}|?\n]/ /go;
return $_;
}

sub makepophash{
my $i = shift;
my $pop = shift;
my $oust;
print "Running on #".$i."\n" if ($verbose);
my ($msghead,$header,$uidl,$from,$subject) = ""; # clear vars

#get UIDL
my @uidl = split(' ',$pop->Uidl($i), 2);
$uidl = trim($uidl[1]);
if (!$uidl){print "Message had no uidl\n"; exit;}

# Combine header into one variable
foreach ($pop->Head($i)){$header .= $_."\n";}
if (!$header){print "No header found, strange error."; exit;}
# get Sender and Subject
my @from = $header =~ /^From: (.*)/mi;
if (!@from) {@from = $header =~ /^From:(.*)/mi;}
my @subj = $header =~ /^Subject: (.*)/mi;
if (!@subj) {@subj = $header =~ /^Subject:(.*)/mi;}

$oust->{'mesg'} = $i;
$oust->{'uidl'} = $uidl;
#$oust->{'head'} = $header;
$oust->{'from'} = $from[0];
$oust->{'subj'} = $subj[0];
return ($oust);
}

#
# Email Function using plain smtp
# usage: send_mail_MIMEd($server,$smtpuser,$smtppass,$smtpshow,$to,$subject,$body)
# returns true/false depending on server connection, not on sending failures(this didn't work)
sub send_mail_MIMEd {
my($server, $smtpuser, $smtppass, $smtpshow, $to, $subject, $body, $attachfile, $attachtype) = @_;
### Create a new multipart message:
$msg = MIME::Lite->new(
From => $smtpshow,
To => $to,
Subject => $subject,
Type => 'multipart/mixed'
);
### Add parts (each "attach" has same arguments as "new"):
$msg->attach(
Type => 'TEXT',
Data => $body
);
### use Net:SMTP to do the sending
# Sometimes we need to auth, sometimes this breaks sendmail
$msg->send('smtp',"$server", Debug=>1, AuthUser=>$smtpuser, AuthPass=>$smtppass );
# $msg->send('smtp',"$server", Debug=>1 );
return 1;
}

# Establish connection to server, and verify. Check for messages.
$pop = new Mail::POP3Client(
USER => "$ARGV[0]",
PASSWORD => "$ARGV[1]",
HOST => "$ARGV[2]",
DEBUG => 0,
USESSL => "true"
);
$pop->Connect();
print "Connected\n" if ($verbose);
my @messages;
#print "counted:\n";
#print Dumper($pop->Count());

# for every email...
for( my $i = ($pop->Count() - 4); $i <= $pop->Count(); $i++ ) {
my $currentmsg = makepophash($i,$pop);
push @messages, $currentmsg;
print "Reading a message...\n" if ($verbose);
}
$pop->Close();
# done with mail server

#print Dumper(@messages);

print "Connecting to Database...\n" if ($verbose);
my $dbh = DBI->connect("dbi:mysql:$config->{'sqlbase'}:$config->{'sqlserv'}:3306", "$config->{'sqluser'}", "$config->{'sqlpass'}"); # connect to db

foreach $message(@messages){
my $sth_uidl = $dbh->prepare("
SELECT * FROM $config->{'sqltabl'}
WHERE uidl = '".$message->{'uidl'}."' AND account = '".$ARGV[0]."'
LIMIT 0,1");
$sth_uidl->execute();
#my ($uid) = $sth_uid->fetchrow_array();
if ($sth_uidl->fetchrow_array()) {
print "Already in DB\n" if ($verbose);
}else{
print "New entry found\n" if ($verbose);
push @messages2, $message;
}
}

foreach $message(@messages2){
$uidl = $message->{'uidl'};
$to = $ARGV[0];
print " New:\t$uidl \n" if ($verbose);
print " New:\t$to \n" if ($verbose);
print " New:\t".$message->{'from'}." \n" if ($verbose);
$body = "Accout \"$to\" got an email from \"$message->{'from'}\", subject: \"$message->{'subj'}\"";
sendmail(
From => "$config->{'systemsender'}",
To => "$ARGV[3]",
# Subject => 'New email for '.$to,
Message => "$body") or die $Mail::Sendmail::error;
print "OK. Log says:\n", $Mail::Sendmail::log if ($verbose);
# inserts perfectly
$dbh->do("INSERT INTO $config->{'sqltabl'} (`uidl`,`account`) VALUES('$uidl', '$to');") if $really_db;
}