, issue one or many e-mails per row based on the contents of the SQL row.
I have attempted to document the script in the pod section as best as I can.
As always, I welcome feedback and criticisms. Code follows below the readmore :
#!perl.exe -w
=pod
TITLE : omnipage.pl
AUTHOR : boo_radley (theeaterofsocks@hotmail.com)
DESCRIPTION : This script is designed to take the output of one or
+ more SQL
query and processes it through a series of filters,
+allowing
it to issue template-based e-mail based on the conte
+nt of that
query.
This script relies on the existence of a configurati
+on file
and several different directories. These items have
+default
values, but may be renamed in the constants section
+of the
script. The default name for the configuration file
+is named
'config.txt', and the default directories are "logs"
+,
"incoming", "templates","completed" and "emailtempla
+tes". All
examples and suggestion will use these default names
+.
Descriptions of these items follow, with notes and e
+xamples
following the descriptions.
The directory named 'incoming' contains the output o
+f any SQL
queries which the script should act upon. This file
+needs to
be a delimited file with no headers. The default del
+imiter is
a comma, but this may be changed by altering the val
+ue of
IncomingDivider in the constants section.
The 'templates' directory contains the template file
+s that the
script uses to create e-mail messages. These templat
+e files
are plain text files that make use of special tags t
+o indicate
field positions. These tags look like "[% field.0 %]
+", and
correspond to fields within the SQL report.
The 'emailtemplates' directory contains templates fo
+r creating
e-mail addresses for the recipients of the script's
+output.
In most cases, the e-mail address should
The "completed' directory contains SQL reports which
+ have been
processed successfully.
"config.txt" is a simple text file that lists groupi
+ngs of
associated files -- the contents of this file should
+ correlate
to the names of the of the SQL report files.
Finally, the "logs" directory contains a logfile for
+ each
group listed in config.txt. Each time the script is
+run, the
log file will either be created or appended to.
EXAMPLE : A config.txt which contains one line, "example" indi
+cates that
there will be a file called "example" in each of the
+ sub-
directories :
/templates/example
/incoming/example
/logs/example
/completed/example
/emailtemplates/example
The incoming file might look like this :
user@company.com,Joe,user, 2,1,TELECOM,123456,"Cus
+tomer has problem with phone line"
Since the recipient's e-mail address is in the SQL r
+eport, the
email template is very simple :
[% fields.0 %]
The corresponding template file might look like the
+following.
Notice that even though the email address has been a
+dded as
one of the headers in the message due to requirement
+s in SMTP's
requirements. Any number of arbitrary headers may be
+ added in
this fashion.
To: [% fields.0 %]
From: MailAgent@helpdesk.com
Subject: Your [% fields.5 %] ticket
Dear [% fields.1 %] [% fields.2 %],
Your [% fields.5 %] ticket number [% fields.6
+%] regarding
[% fields.7 %] has been closed. If you'd like
+to reopen
it, call the helpdesk at 555-1212.
Once finished processing, the result would an email
+that looks
like :
To: user@company.com
From: MailAgent@helpdesk.com
Subject: Your Telecom ticket
Dear Joe User,
Your TELECOM ticket number 123456 regarding
"Customer has problem with phone line" has bee
+n closed. If you'd like to reopen
it, call the helpdesk at 555-1212.
=cut
######################################################################
+########
# modules
#
use strict;
use Template;
use Net::SMTP;
use File::Copy;
use Date::Manip;
######################################################################
+########
# constant delcarations
#
use constant LogPath => "logs/";
use constant IncomingPath => "incoming/";
use constant EmailMsgTemplatePath => "templates/";
use constant CompletedPath => "completed/";
use constant EmailAddressTemplatePath => "emailtemplates/";
use constant ConfigFile => "config.txt";
use constant IncomingDivider => ',';
use constant SMTPServer => "your server here";
######################################################################
+########
# main
#
&Date_Init("TZ=MDT");
my $template = Template->new() or die ("Can't create template : $!
+");
my $paginggroups = load_paging_groups(ConfigFile);
foreach my $thisgroup (@$paginggroups) {
my $errorout = 0;
print_log ($thisgroup, "checking $thisgroup\n for data");
my $incoming = get_incoming ($thisgroup);
my $completed = CompletedPath . $thisgroup;
my $emailmsgtemplate = EmailMsgTemplatePath . $thisgroup;
my $emailaddresstemplate = EmailAddressTemplatePath . $thisgro
+up;
foreach my $thisline(@$incoming) {
# set up the vars for the templates.
my $vars = {fields=>$thisline};
# complete email address
my $emailaddress;
unless ($template->process ($emailaddresstemplate,$vars,\$
+emailaddress)) {
$errorout .="bad email address template |";
print_log ($thisgroup, "Unable to create email address
+ from template. Template reports $!. Skipping entry\n");
#die "no process! $!";
};
# complete email message
my $emailmessage;
unless ($template->process ($emailmsgtemplate,$vars,\$emai
+lmessage)) {
$errorout .="bad email message template |";
print_log ($thisgroup, "Unable to create email message
+ from template. Template reports $!. Skipping entry\n");
#die "no process! $!";
};
#debug email address
$emailaddress = "debug@domain.com";
# issue email unless the address or message creation faile
+d.
unless ($errorout){
print_log ($thisgroup, "issuing mail for ", join (
+",",@$thisline),"\n");
my $smtp= Net::SMTP->new(SMTPServer ) or die ("Ca
+n't create smtp object - $!");
$smtp->mail($ENV{USER});
$smtp->recipient ($emailaddress);
$smtp->data();
$smtp->datasend($emailmessage);
$smtp->dataend();
$smtp->quit;
# log.
}
}
if ($errorout) {
print_log ($thisgroup, "Unable to complete $thisgroup\n");
}else{
archive_incoming ($thisgroup);
}
$errorout ||
print_log ($thisgroup, "finished with $thisgroup\n");
}
######################################################################
+########
# support routines
#
######################################################################
+########
sub load_paging_groups {
print "here is $_[0]\n";
open FH, $_[0] or die "can't open groups : $!";
my @lines = <FH>;
chomp $_ foreach @lines;
close FH;
print "in load paging @lines\n";
return \@lines;
}
######################################################################
+########
sub get_incoming {
die "nothing to get_incoming" unless @_;
my @lines;
open INCOMING, IncomingPath . $_[0] or die "can't open incoming fi
+le $_[0]!";
#
# read past 2 lines for sql report headers.
#
<INCOMING>; <INCOMING>;
while (<INCOMING>) {
# all the extra syntax in the regex enables the use of a const
+ant
# $string =~ m /@{[ CONST ]}/;
my @line = split /@{[IncomingDivider]}/, $_;
push @lines, \@line;
foreach (@line) {s/^\s+//; s/\s+$//}; # trim leading and trail
+ing whitespace
}
close INCOMING;
return \@lines;
}
######################################################################
+########
sub archive_incoming {
my $filename = shift or die "no file name passed to archive_incomi
+ng!";
my $ts = UnixDate("now","%q"); # %q format : %Y%m%d%H%M%S : 19961
+025174058
my $backup = CompletedPath.$ts.$filename;
print "\n--$backup--\n";
copy (IncomingPath.$filename, $backup) or die "can't copy! $!";
}
######################################################################
+########
sub print_log {
my $thisgroup = shift or die "no group name to print_log!";
open LOGFILE, ">>",LogPath . $thisgroup;
print LOGFILE UnixDate("now","%q"),"\t@_";
close LOGFILE;
}