check_email_loop script modified

Emmanuel Kedaj emmanuel.kedaj at gmail.com
Mon Jun 19 16:18:43 CEST 2006


I was just experiencing some strange problems, fixed it and wanted to submit
it to the community.
nagios 2.2 (now 2.3)
nagios-plugins 1.4.2


the script is actually trying to do doing this:
- send mail number 1
- queue mail 1 for delivery on mailserver
- retrive mails from mailbox looking for mail number 0 (previously sent)
- delete old unrecognised mails.
- retain in mind (stat file) mail 1 was sent for next check

problem:
if your mailserver is quick enough, here is what will happen:
- send mail 1
- deliver mail 1 to mailbox directly without queuing
- retrieve mails looking for mail 0 (including mail 1)
- delete mail 1 as if it is not yet recognised as sent
- retain mail 1 was sent (and never find it)

so the solution was that simple:
- retrieve mail 0
- send mail 1
- retain mail 1 was sent for future retrieval

I ve seen in the mailing some other people are experiencing the same, but
did not find someone who posted an updated version of the script.
So here is the updated version that is running well for me.

cheers,

Manu


------------------------------ start of check_email_loop-pl
-------------------------------------------

#!/usr/bin/perl -w
#
# (c)2000 Benjamin Schmid, blueshift at gmx.net
# Copyleft by GNU GPL
#
#
# check_email_loop Nagios Plugin
#
# This script sends a mail with a specific id in the subject via
# an given smtp-server to a given email-adress. When the script
# is run again, it checks for this Email (with its unique id) on
# a given pop3 account and send another mail.
#
#
# Example: check_email_loop.pl -poph=mypop -popu=user -pa=password
#        -smtph=mailer -from=returnadress at yoursite.com
#       -to=remaileradress at friend.com -pendc=2 -lostc=0
#
# This example will send each time this check is executed a new
# mail to remaileradress at friend.com using the SMTP-Host mailer.
# Then it looks for any back-forwarded mails in the POP3 host
# mypop. In this Configuration CRITICAL state will be reached if
# more than 2 Mails are pending (meaning that they did not came
# back till now) or if a mails got lost (meaning a mail, that was
# send later came back prior to another mail).
#
# Michael Markstaller, mm at elabnet.de various changes/additions
# MM 021003: fixed some unquoted strings
# MM 021116: fixed/added pendwarn/lostwarn
# MM 030515: added deleting of orphaned check-emails
# changed to use "top" instead of get to minimize traffic (required changing
match-string from "Subject: Email-ping [" to "Email-Ping ["
#
# Emmanuel Kedaj (Emmanuel.kedaj at gmail.com)
# Added some debug messages
# retrieving POP3 mails before sending actual test mail
# as mentionned by Dave Ewall <dave_at_email.domain.hidden> on 19 Jul 2005
on Nagios-users mailing list
# https://lists.sourceforge.net/lists/listinfo/nagios-users
#

use Net::POP3;
use Net::SMTP;
use strict;
use Getopt::Long;
&Getopt::Long::config('auto_abbrev');

# ----------------------------------------

my $TIMEOUT = 120;
my %ERRORS = ('UNKNOWN' , '-1',
              'OK' , '0',
              'WARNING', '1',
              'CRITICAL', '2');

my $state = "UNKNOWN";
my ($sender,$receiver, $pophost, $popuser, $poppasswd,
$smtphost,$keeporphaned);
my ($poptimeout,$smtptimeout,$pinginterval,$maxmsg)=(60,60,5,50);
my ($lostwarn, $lostcrit,$pendwarn, $pendcrit,$debug);

$debug=0;

# Internal Vars
my ($pop,$msgcount, at msglines,$statinfo, at messageids,$newestid);
my (%other_smtp_opts);
my ($matchcount,$statfile) = (0,"check_email_loop.stat");

# Subs declaration
sub usage;
sub messagematchs;
sub nsexit;

# Just in case of problems, let's not hang Nagios
$SIG{'ALRM'} = sub {
     print ("ERROR: $0 Time-Out $TIMEOUT s \n");
     exit $ERRORS{"UNKNOWN"};
};
alarm($TIMEOUT);


# Evaluate Command Line Parameters
my $status = GetOptions(
                "from=s",\$sender,
            "to=s",\$receiver,
                        "debug", \$debug,
                        "pophost=s",\$pophost,
                        "popuser=s",\$popuser,
            "passwd=s",\$poppasswd,
            "poptimeout=i",\$poptimeout,
            "smtphost=s",\$smtphost,
            "smtptimeout=i",\$smtptimeout,
            "statfile=s",\$statfile,
            "interval=i",\$pinginterval,
            "lostwarn=i",\$lostwarn,
            "lostcrit=i",\$lostcrit,
            "pendwarn=i",\$pendwarn,
            "pendcrit=i",\$pendcrit,
            "maxmsg=i",\$maxmsg,
            "keeporphaned=s",\$keeporphaned,
            );
usage() if ($status == 0 || ! ($pophost && $popuser && $poppasswd &&
    $smtphost && $receiver && $sender ));

# Try to read the ids of the last send emails out of statfile
if (open STATF, "$statfile") {
  @messageids = <STATF>;
  chomp @messageids;
  close STATF;
}

# Try to open statfile for writing
if (!open STATF, ">$statfile") {
  nsexit("Failed to open mail-ID database $statfile for
writing",'CRITICAL');
}

if ( $debug == 1  ) {
     print
("----------------------------------------------------------------------\n");
     print
("----------------------------------------------------------------------\n");
     print ("-------------------- Checking POP3 Mails
-----------------------------\n");
     print
("----------------------------------------------------------------------\n");
     print
("----------------------------------------------------------------------\n");
     print ("Retrieving POP mails from $pophost using user: $popuser and
password $poppasswd\n");
}

# the interessting part: let's see if mails are receiving ;-)

$pop = Net::POP3->new( $pophost,
         Timeout=>$poptimeout)
       || nsexit("POP3 connect timeout (>$poptimeout s, host:
$pophost)",'CRITICAL');

$msgcount=$pop->login($popuser,$poppasswd);

$statinfo="$msgcount mails on POP3";
if ( $debug == 1  ) {
     print ("Found $statinfo\n");
}

nsexit("POP3 login failed (user:$popuser)",'CRITICAL') if
(!defined($msgcount));

# Check if more than maxmsg mails in pop3-box
nsexit(">$maxmsg Mails ($msgcount Mails on POP3); Please delete
!",'WARNING') if ($msgcount > $maxmsg);

# Count messages, that we are looking 4:
while ($msgcount > 0) {
  @msglines = @{$pop->top($msgcount,1)};
  for (my $i=0; $i < scalar @messageids; $i++) {
    if (messagematchsid(\@msglines,$messageids[$i])) {
      $matchcount++;
    if ( $debug == 1  ) {
             print ("Messages are matching\n");
    }
      # newest received mail than the others, ok remember id.
      if(!defined $newestid) {
        $newestid = $messageids[$i]
      } elsif ($messageids[$i] > $newestid) {
        $newestid = $messageids[$i];
      }
    my @msgsubject = grep /^Subject/, @msglines;
    if ( $debug == 1  ) {
             print ("Deleted retrieved mail $msgcount with subject
$msgsubject[0]\n");
    }
      $pop->delete($msgcount);  # remove E-Mail from POP3 server
      splice @messageids, $i, 1;# remove id from List
      last;                     # stop looking in list
    }
  }
    # Delete orphaned Email-ping msg
    my @msgsubject = grep /^Subject/, @msglines;
    chomp @msgsubject;
    # Scan Subject if email is an Email-Ping. In fact we match and delete
also successfully retrieved messages here again.
    if (!defined $keeporphaned && $msgsubject[0] =~ /E-Mail Ping \[/) {
        $pop->delete($msgcount);  # remove E-Mail from POP3 server
        if ( $debug == 1  ) {
                 print ("Deleted orphaned mail $msgcount with subject
$msgsubject[0]\n");
        }
    }

    $msgcount--;
}

$pop->quit();  # necessary for pop3 deletion!

# traverse through the message list and mark the lost mails
# that mean mails that are older than the last received mail.
if (defined $newestid) {
  $newestid =~ /\#(\d+)\#/;
  $newestid = $1;
  for (my $i=0; $i < scalar @messageids; $i++) {
    $messageids[$i] =~ /\#(\d+)\#/;
    my $akid = $1;
    if ($akid < $newestid) {
      $messageids[$i] =~ s/^ID/LI/; # mark lost
        if ( $debug == 1  ) {
                 print ("MAIL $messageids[$i] MARKED AS LOST\n");
        }
    }
  }
}

# Write list to id-Database
foreach my $id (@messageids) {
  print STATF  "$id\n";
}

# creating new serial id
my $serial = time();
$serial = "ID#" . $serial . "#$$";

if ( $debug == 1  ) {
     print
("----------------------------------------------------------------------\n");
     print
("----------------------------------------------------------------------\n");
     print ("-------------------- SENDING MAIL: $serial
-----------------\n");
     print
("----------------------------------------------------------------------\n");
     print
("----------------------------------------------------------------------\n");
}

# sending new ping email
#%other_smtp_opts={};
if ( $debug == 1  ) {
    $other_smtp_opts{'Debug'} = 1;
}
my $smtp = Net::SMTP->new($smtphost,Timeout=>$smtptimeout, %other_smtp_opts)

  || nsexit("SMTP connect timeout ($smtptimeout s)",'CRITICAL');
($smtp->mail($sender) &&
 $smtp->to($receiver) &&
 $smtp->data() &&
 $smtp->datasend("To: $receiver\nSubject: E-Mail Ping [$serial]\n\n".
         "This is a automatically sended E-Mail.\n".
         "It ist not intended for human reader.\n\n".
         "Serial No: $serial\n") &&
 $smtp->dataend() &&
 $smtp->quit
 ) || nsexit("Error delivering message",'CRITICAL');

print STATF "$serial\n";     # remember send mail of this session
close STATF;

# ok - count lost and pending mails;
my @tmp = grep /^ID/, @messageids;
my $pendingm = scalar @tmp;
@tmp = grep /^LI/, @messageids;
my $lostm = scalar @tmp;

# Evaluate the Warnin/Crit-Levels
if (defined $pendwarn && $pendingm > $pendwarn) { $state = 'WARNING'; }
if (defined $lostwarn && $lostm > $lostwarn) { $state = 'WARNING'; }
if (defined $pendcrit && $pendingm > $pendcrit) { $state = 'CRITICAL'; }
if (defined $lostcrit && $lostm > $lostcrit) { $state = 'CRITICAL'; }

if ((defined $pendwarn || defined $pendcrit || defined $lostwarn
     || defined $lostcrit) && ($state eq 'UNKNOWN')) {$state='OK';}



  if ( $debug == 1  ) {
    print ("STATUS:\n");
    print ("Found    : $statinfo\n");
    print ("Matching : $matchcount\n");
    print ("Pending  : $pendingm\n");
    print ("Lost     : $lostm\n");
    print ("Mail $serial remembered as sent\n");
     print
("----------------------------------------------------------------------\n");
     print
("----------------------------------------------------------------------\n");
     print ("-------------------------- END DEBUG INFO
----------------------------\n");
     print
("----------------------------------------------------------------------\n");
     print
("----------------------------------------------------------------------\n");
  }

# Append Status info
$statinfo = $statinfo . ", $matchcount mail(s) came back,".
            " $pendingm pending, $lostm lost.";

# Exit in a Nagios-compliant way
nsexit($statinfo);

# ----------------------------------------------------------------------

sub usage {
  print "check_email_loop 1.1 Nagios Plugin - Real check of a E-Mail
system\n";
  print "=" x 75,"\nERROR: Missing or wrong arguments!\n","=" x 75,"\n";
  print "This script sends a mail with a specific id in the subject via an
given\n";
  print "smtp-server to a given email-adress. When the script is run again,
it checks\n";
  print "for this Email (with its unique id) on a given pop3 account and
sends \n";
  print "another mail.\n";
  print "\nThe following options are available:\n";
  print    "   -from=text         email adress of send (for mail returnr on
errors)\n";
  print    "   -to=text           email adress to which the mails should
send to\n";
  print "   -pophost=text      IP or name of the POP3-host to be checked\n";
  print "   -popuser=text      Username of the POP3-account\n";
  print    "   -passwd=text       Password for the POP3-user\n";
  print    "   -poptimeout=num    Timeout in seconds for the POP3-server\n";
  print "   -smtphost=text     IP oder name of the SMTP host\n";
  print "   -smtptimeout=num   Timeout in seconds for the SMTP-server\n";
  print "   -statfile=text     File to save ids of messages ($statfile)\n";
  print "   -interval=num      Time (in minutes) that must pass by before
sending\n";
  print "                      another Ping-mail (gibe a new try);\n";
  print "   -lostwarn=num      WARNING-state if more than num lost
emails\n";
  print "   -lostcrit=num      CRITICAL \n";
  print "   -pendwarn=num      WARNING-state if more than num pending
emails\n";
  print "   -pendcrit=num      CRITICAL \n";
  print "   -maxmsg=num        WARNING if more than num emails on POP3
(default 50)\n";
  print "   -keeporphaned      Set this to NOT delete orphaned E-Mail Ping
msg from POP3\n";
  print "   -debug             send SMTP tranaction info to stderr\n\n";
  print " Options may abbreviated!\n";
  print " LOST mails are mails, being sent before the last mail arrived
back.\n";
  print " PENDING mails are those, which are not. (supposed to be on the
way)\n";
  print "\nExample: \n";
  print " $0 -poph=host -pa=pw -popu=popts -smtph=host -from=root\@me.com\n
";
  print "      -to=remailer\@testxy.com -lostc=0 -pendc=2\n";
  print "\nCopyleft 19.10.2000, Benjamin Schmid / 2003 Michael Markstaller,
mm\@elabnet.de\n";
  print "This script comes with ABSOLUTELY NO WARRANTY\n";
  print "This programm is licensed under the terms of the ";
  print "GNU General Public License\n\n";
  exit $ERRORS{"UNKNOWN"};
}

# ---------------------------------------------------------------------

sub nsexit {
  my ($msg,$code) = @_;
  $code=$state if (!defined $code);
  print "$code: $msg\n" if (defined $msg);
  exit $ERRORS{$code};
}

# ---------------------------------------------------------------------

sub messagematchsid {
  my ($mailref,$id) = (@_);
  my (@tmp);
  my $match = 0;

  # ID
  $id =~ s/^LI/ID/;    # evtl. remove lost mail mark
  @tmp = grep /E-Mail Ping \[/, @$mailref;
  chomp @tmp;
  if ( $debug == 1  ) {
    print ("Comparing Mail content $tmp[0] with Mail ID $id:\n");
  }
  if (($tmp[0] =~ /$id/))
    { $match = 1; }

  # Sender:
#  @tmp = grep /^From:\s+/, @$mailref;
#  if (@tmp && $sender ne "")
#    { $match = $match && ($tmp[0]=~/$sender/); }

  # Receiver:
#  @tmp = grep /^To: /, @$mailref;
#  if (@tmp && $receiver ne "")
#    { $match = $match && ($tmp[0]=~/$receiver/); }

  return $match;
}

# ---------------------------------------------------------------------


------------------------------ end of check_email_loop-pl
-------------------------------------------
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://www.monitoring-lists.org/archive/users/attachments/20060619/3cf00f34/attachment.html>
-------------- next part --------------
_______________________________________________
Nagios-users mailing list
Nagios-users at lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/nagios-users
::: Please include Nagios version, plugin version (-v) and OS when reporting any issue. 
::: Messages without supporting info will risk being sent to /dev/null


More information about the Users mailing list