#!/usr/bin/perl ############################################### ## Mail Latency - Check Email ## ## v1.0 - 10/15/2007 - Walt Howd ## ## This script is designed to monitor ## email servers and report e-mail latency. ## ## This script works in conjunction with another ## that connects to an external mail server ## and sends a test message containing the UNIX ## timestamp in the message body. ## ## This script checks the local mail server ## via POP and then can report for each mail ## server in the message headers how long it ## took in seconds for the message to arrive. ## ## Usage: ## ./checkEmail.pl SERVERNAME --measure=METHOD ## ## ./checkEmail mail --measure=absolute ## ## ./checkEmail mail.domain.com --measure=relative ## ## This will give you the average time in ## seconds for mail server supplied on the ## command line. This could be the end server ## you are accessing via POP or any intermediary ## mail servers along the path. ## ## The second option lets you specify if you want ## the time delay from the last non local mail server ## as distinguished by $dnsDomain (servers matching your ## dns suffix). If not specified the script will report ## the absolute time from when the message was sent ## to when the message arrived. ## ## After checking and reporting the average time ## the messages with the matching subject line ## are deleted. ## ## Copyright Walt Howd ## ## 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 ## 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 ## ############################################### ############################################### ## Configuration Variables ############################################### $dnsDomain = "domain.com"; $mailServer = "mail.domain.com"; $mailPort = "995"; $mailUser = "username"; $mailPassword = "password"; $mailSubject = "MailLatency"; $mailSSL = "true"; $noMatchTime = 0; ############################################### ## Load Modules ############################################### use Mail::POP3Client; use Date::Parse; use Getopt::Long; ############################################### ## Usage options ############################################### GetOptions("measure:s" => \$measure, "debug:s" => \$debug); $serverToCheck = $ARGV[0]; if(!$serverToCheck || !$measure && (!($measure =~ /absolute/gi) || !($measure =~ /relative/gi)) ) { die("\nUsage:\n./checkEmail SERVERNAME --measure=absolute\n\n./checkEmail SERVERNAME --measure=relative\n\n"); } ############################################### ## Connect to POP Server ############################################### $pop = new Mail::POP3Client( USER => $mailUser, PASSWORD => $mailPassword, HOST => $mailServer, USESSL => $mailSSL, ); ############################################### ## Examine each message ############################################### for ($i = 1; $i <= $pop->Count(); $i++) { foreach ( $pop->Head( $i ) ) { ############################################### ## Only examine messages with this matching ## subject ############################################### if($_ =~ /^Subject:\s+$mailSubject - $serverToCheck - $measure/i) { ############################################### ## Loop through each line of the mail header ############################################### foreach ( $pop->Head( $i ) ) { chomp(); ################################################### ## Look for the text "Received: by mail.server.net ## to see what mail server the next time stamp we ## see belongs to ################################################### if($_ =~ /(by\s)(\S+\.\S+\.\w{3}|\d{1,2,3}\.\d{1,2,3}\.\d{1,2,3}\.\d{1,2,3})/gi) { $smtpServer = $_; $smtpServer =~ s/(^.*?)(by\s)(\S+\.\S+\.\w{3}|\d{1,2,3}\.\d{1,2,3}\.\d{1,2,3}\.\d{1,2,3})(.*$)/$3/gi } ################################################### ## See if this line contains a recognized date ## if so, then convert that date to a timestamp and ## see what the difference is from the time the ## message was orignally sent. The original time ## is a UNIX timestamp in the message body. ## ## Sorry for the ridiculous regexs. ################################################### if($_ =~ /(Sun|Mon|Tue|Wed|Thu|Fri|Sat)(,\s+\d+\s+?)(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)(\s+\d+?)(\s+\d+:\d+:\d+)(\s+[A-Z]{3}|\s+.\d+)/gi) { $bodyTS = $pop->Body( $i ); chomp($bodyTS); $recTime = $_; $recTime =~ s/(^.*?)(Sun|Mon|Tue|Wed|Thu|Fri|Sat)(,\s+\d+\s+?)(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)(\s+\d+?)(\s+\d+:\d+:\d+)(\s+[A-Z]{3}|\s+.\d+)(.*$)/$2$3$4$5$6$7/gi; $recTS = Date::Parse::str2time($recTime, 'GMT'); $diff = $recTS - $bodyTS; ################################################### ## If this time belongs to the mail server supplied ## on the command line then store the time so we can ## later return an average ################################################### if($smtpServer =~ /$serverToCheck/gi) { if($debug) { print "Processing server $smtpServer - $serverToCheck\n\n"; } $match = 1; $foundFinalMailServer = 1; $totTime = $totTime + $diff; $totMatch++; } ################################################### ## Record the delay on the last non local mail ## server as determined by non matching dns suffix. ################################################### if(!($smtpServer =~ /$dnsDomain/gi) && !$foundLastNonLocalMailServer) { $foundLastNonLocalMailServer = 1; $totLastNonLocalTime = $totLastNonLocalTime + $diff; $totLastNonLocalMatch++; } if($debug) { print "Server:\t\t$smtpServer\nDate:\t\t$_\nRegEx:\t\t$recTime\nTimestamp:\t$recTS\nBodyStamp:\t$bodyTS\nAbsDiff:\t$diff\n\n"; } } } ################################################### ## Delete any messages in this account that matched ## our subject line and clear our message flags ################################################### $pop->Delete( $i ); $foundLastNonLocalMailServer = 0; $foundFinalMailServer = 0; if($debug) { print "Resetting final found server\n\n"; } } } } ############################################### ## If no matches are found then return ZERO ## ## If matches are found, average them out for ## mail server supplied on the command line ############################################### if(!($match)) { print "$noMatchTime\n"; } else { $absAvg = int($totTime / $totMatch); $lastNonLocalAvg = int($totLastNonLocalTime / $totLastNonLocalMatch); $relAvg = $absAvg - $lastNonLocalAvg; if($debug) { print "AbsAvg:\t\t\t$absAvg\nLastNonLocalAvg:\t$lastNonLocalAvg\nRelAvg:\t\t\t$relAvg\n\n"; } ################################################### ## Return the requested delay of time in seconds ## Return 1 if the delay was less then 1 second ################################################### if($measure =~ /relative/gi) { if($relAvg == 0) { print "1\n"; } else { print "$relAvg\n"; } } else { if($absAvg == 0) { print "1\n"; } else { print "$absAvg\n"; } } } $pop->Close();