qpsmtpd_report.pl

NAME

qpsmtpd_report.pl [-v]

DESCRIPTION

Report daily (summary|extended info) about (Accepted|Greylisted|Refused) mails by Qpsmtpd service.

USAGE

without argument : print summary.

with -v : print extended info + summary.

COPYRIGHT

Copyright 2015 Etienne LEMEE <etilem AT cpan DOT org>

This piece of code is free software; you can redistribute it and/or modify it under the same terms as Perl itself.


#!/usr/bin/perl -w

use strict;
use Sys::Hostname;
use Digest::MD5 qw(md5_hex);     

my $hostname = hostname;
my $log = "/var/log/qpsmtpd/qpsmtpd.log";
my %seen;
my %final;
my %stats;
my $sn;
my $hash;
my %code  = (
    25 => "Accepted",
    45 => "Greylisted",
    55 => "Refused",
);
my @lines;

@ARGV > 0 and my $verb = 1;

open my $IN, "<", $log or die "Can't open $log : $!";
while (my $l = <$IN>) {
    chomp $l;
    $l =~ s/^.*(\d{2}:\d{2}:\d{2}).*$hostname\[(\d+)\]: (.*)$/$2%$1%$3/;
    my ($pid, $date, $line) = split '%', $l;
    push @{$seen{$pid}}, [$date, $line];
}
close $IN;

for my $pid (keys %seen) {
    for my $ref (@{$seen{$pid}}) {
        my ($date, $line) = ($ref->[0], $ref->[1]);
        next unless ($line =~ /^\d{3}/);
        $sn = 1 if ($line =~ /^220/);
        $sn = 0 if ($line =~ /^221/);    
        if ($sn > 0 and $line =~ /^250-.*?Hi.*?\[.*?\]/) {
            $sn = 2;
            $hash = md5_hex ($pid . $date . $line);
            $line =~ s/^250.*?Hi (.*?) \[(.*?)\].*?$/$1 $2/;
            my ($host, $ip) = split " ", $line;
            $final{$hash} = [$date, $host, $ip];
        } elsif ($sn > 1) {
            push @{$final{$hash}}, $line unless ($line =~ /^50\d/);
        }
    }
}

for my $k (keys %final) {
    my $line = sprintf "At %s, mail from %s with IP %s was: ", $final{$k}->[0], $final{$k}->[1], $final{$k}->[2];
    for (my $c = 3; my $v = $final{$k}->[$c]; $c++) {
        next unless ($v =~ /^[4|5]5/ or $v =~ /^250 Queued/);
        $line .= sprintf "%s ", $v;
        push @lines, $line;
        $v =~ s/^(\d{2}).*/$1/;
        $stats{$v}++;
    }
}

exit unless (@lines);

for my $l (sort @lines) {
    printf "%s\n", $l if ($verb);
}

print "\n|============ SUMMARY ============|\n|\n";
for my $c (sort keys %stats) {
    printf "| %sx: %s = %d\n", $c, $code{$c}, $stats{$c};
}
print "|\n|=================================|\n";