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: 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:

./ myEmailPassword

Here’s the Perl:


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

$config->{'systemsender'} = 'CoreForge Alerter <>';
$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/[^[: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"):
		Type    =>'TEXT',
		Data    =>$body
	### use Net:SMTP to do the sending
	if (0){# 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]",
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);
# 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");
	#my ($uid) = $sth_uid->fetchrow_array();
	if ($sth_uidl->fetchrow_array()) {
		print "Already in DB\n" if ($verbose);
		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'}\"";
		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;