Perlscript für log-Auswertung, qMail Notify

der-merlin

New Member
Hallo,
ich habe mir ein Script gebastelt, das eine Benachrichtuigung an den Absender generiert, wenn die Mail an den entfernten Absender nach mehreren Stunden nicht versandt wurde. Das läuft auch zufriedenstellend per stündlichen Cronjob und ich hab das hier unten angefügt.

Ich möchte nun auch die Fehlerursache mit angeben und habe ein Problem mit dem ich nicht weiter komme und auch Google hat mich mehr verwirrt als geholfen, deshalb, mit Bitte um "Input":

Bei der Auswertung des Log qmail/send habe ich die richtigen Meldungen zur Mail extrahiert. Ich bekomme pro "offener" Mail in der
"starting-Schleife" die entfernte Mailadresse und die Tasknummer ausgelesen und in der "delivery-Schleife" die Tasknummer und die Server-Fehlermeldung

Code:
starting delivery 7665: msg 2326553 to remote sumsi@t-onlie.de

delivery 7665: deferral: Sorry,_I_wasn't_able_to_establish_an_SMTP_connection._(#4.4.1)/
...
starting delivery 7669: msg 2326553 to remote sumsi@t-onlie.de

delivery 7669: deferral: Sorry,_I_wasn't_able_to_establish_an_SMTP_connection._(#4.4.1)/

Ich komme nun nicht weiter, wie ich mit Listen-Arrays/Hash (ohne SQL, nur perl) das so aufbauen kann, dass ich bei starting:
den Mailempfänger und dazu den Task ablege
und dann bei delivery:
anhand des Task die Fehlermeldung dem Empfänger zuordne
(Die Werte habe ich in Variablen, aber wohin damit :)

Problem dabei ist:
Da Qmail mehrfach versucht die Mails zu senden, habe ich mehrere Task für einen Empfänger (mit immer der gleichen Fehlermeldung)
UND
Wenn mehrere Empfänger angegeben sind, muss ich das für mehrere Adressen zuordnen.
Code:
( aus der $mtext{$rmsg} ) 
starting delivery 7436: msg 2326550 to remote test@t-onlie.de
starting delivery 7437: msg 2326550 to remote test2@t-onlie.de
starting delivery 7438: msg 2326550 to remote test@onlie.de
delivery 7438: failure: 83.243.43.224_does_not_like_recipient./Remote_host_said:_554_5.7.1_<test@onlie.de>:_Relay_access_denied/Giving_up_on_83.243.43.224./
delivery 7436: deferral: Sorry,_I_wasn't_able_to_establish_an_SMTP_connection._(#4.4.1)/
delivery 7437: deferral: Sorry,_I_wasn't_able_to_establish_an_SMTP_connection._(#4.4.1)/

Die Ausgabe soll dann so in eine Variable erfolgen, dass jeder Mailempfänger mit einer (der letzen) Fehlermeldung 1 mal angezeigt wird.
...

Hier erstmal das "fast-fertige" (funktionierende) Script
Code:
#!/usr/bin/perl
#
# catch remote adress and mail from qmail-queue for info to sender 
# works with qmail and netqmail
# use crontab to start it 
#
# Jürgen Augustinat 11/2008 "ja at regionalnetz de" 
# thanks to Michele Beltrame "mb at italpro net" for qmHandle
#
# Install:
# copy the script to path, set premission 4755
# edit cronfile e.g.: 55 * * * * /path/queuemail2
# have fun
#
# you can use it for test only, if you change the T0: in "Print Mail..." at the end of the script

use strict;
use warnings;
use diagnostics;

my $version = '2.20'; # can run in cronjob every hour, write delaytime to mail

# ... start userconfig ...
my ($queue) = '/var/qmail/queue/';
my $lastfile = '/var/run/queuetime'; 

# set mailprogram      
my $Sendmail_Prog = "/usr/sbin/sendmail";
# your service-mailadress
my $mailfrom = 'service@yourdomain.tld';

# please set delay hours (h*60min*60sec) 4-12-24-48-72
# last can set greater as queuelifetime :-)
my $delhr1 = 4;
my $delhr2 = 12;
my $delhr3 = 24;
my $delhr4 = 48;
my $delhr5 = 72;

# ... end userconfig ...
my $summary = 0;
my @array = ();
my $lastrun = 0;
my $mytime = time();

## START build lastfile !could uncomment after the first go-off !
if (-e $lastfile){}
  else{
    open(LAST, ">$lastfile") || die "error write lastrun\n"; 
    print LAST $mytime-3600;
    close (LAST);
    }
## END
 
my $deltime1 = $delhr1*3600;
my $deltime2 = $delhr2*3600;
my $deltime3 = $delhr3*3600;
my $deltime4 = $delhr4*3600;
my $deltime5 = $delhr5*3600;

# read lifetime
my $day = 0;
my $lifetime = '/var/qmail/control/queuelifetime';
if (-e $lifetime){
    open(DAYS, $lifetime);
    $day = <DAYS>/86400;
    close(DAYS);
    }
    else{
    $day = 7;
    }

# lastrun = read file and write time!
open(LAST, $lastfile) || die "error read lastrun\n"; 
$lastrun = <LAST>;
close (LAST);

open(LAST, ">$lastfile") || die "error write lastrun\n"; 
print LAST $mytime;
close (LAST);

# START #
# Create a message list for remote queues
my (@msglist) = ();
my (%delhr) = ();

foreach my $currentqueue ("remote") {
    opendir(DIR,"${queue}$currentqueue");
    my (@dirlist) = grep !/\./, readdir DIR;
    closedir DIR;
    foreach my $dir (@dirlist) {
	opendir (SUBDIR,"${queue}${currentqueue}/$dir");	
	my (@files) = grep !/\./, map "$dir/$_", readdir SUBDIR;
	foreach my $file (@files) {
	my $Datei = "${queue}${currentqueue}/$file";	
	my $letsgo = '';
	my @info = stat($Datei);
	my $expiry = $info[9];

# set the notify delay
    my $expiry1 = $expiry+$deltime1; 
    my $expiry2 = $expiry+$deltime2; 
    my $expiry3 = $expiry+$deltime3; 
    my $expiry4 = $expiry+$deltime4; 
    my $expiry5 = $expiry+$deltime5; 

    if ($expiry1 > $mytime) {
    next;
    }

    if ($expiry1 > $lastrun && $expiry1 <= $mytime) {
    push @msglist, "$file";
    $delhr{"$file"} = $delhr1;
    next;
    }	    
    if ($expiry2 > $lastrun && $expiry2 <= $mytime) {
    push @msglist, "$file";
    $delhr{"$file"} = $delhr2;
    next;
    }	    
    if ($expiry3 > $lastrun && $expiry3 <= $mytime) {
    push @msglist, "$file";
    $delhr{"$file"} = $delhr3;
    next;
    }	    
    if ($expiry4 > $lastrun && $expiry4 <= $mytime ) {
    push @msglist, "$file";
    $delhr{"$file"} = $delhr4;
    next;
    }	    
    if ($expiry5 > $lastrun && $expiry5 <= $mytime ) {
    push @msglist, "$file";
    $delhr{"$file"} = $delhr5;
    next;
    }	    
    }
	closedir SUBDIR;
    }
}
 
# read for remote message list 
    my ($q) = shift;
    my (%ret, %date, %from, %subj, %to, %allto);
    
    if ($summary == 0) {
	foreach my $msg(@msglist) {
	    # Read return path 
	    open (MSG, "${queue}info/$msg");
	    $ret{$msg} = <MSG>;
	    substr($ret{$msg}, 0, 1) = '';
	    chop ($ret{$msg});
	    close (MSG);
	    # Read all remote (D=Done,T=Todo)
	    open (MSG, "${queue}remote/$msg");
	    $allto{$msg} = <MSG>;
	    chop ($allto{$msg});
	    close (MSG);

# Read something from message header (sender, receiver, subject, date)
	    open (MSG, "${queue}mess/$msg");
	    while (<MSG>) {
		if ($_ =~ /^Date: /) {
		    $date{$msg} = $';
		    chop ($date{$msg});
		} 
		elsif ( $_ =~ /^From: /) {
		$from{$msg} = $';
		    chop ($from{$msg});
		} 
		elsif ( $_ =~ /^Subject: /) {
		    $subj{$msg} = $';
		    chop ($subj{$msg});
		} 
		elsif ( $_ =~ /^To: /) {
		    $to{$msg} = $';
		    chop ($to{$msg});
		} 
		elsif ( $_ eq "\n") {
		    last;
		}
	    }
	    close (MSG);
	}
    }

# lets go to send the mails 
{
# first read the todo recipients only
	foreach my $msg(@msglist) {
		my $Stop = 0;
		my @Reci = ();
		my $to = "";
		my $todo = "";
		my ($dir, $rmsg) = split (/\//, $msg);
		if ($summary == 0) {
		    @array=split(/\0/,$allto{$msg});
		    foreach (@array){
		    $todo = $_ ;
		     if ($todo =~ /^T/) {
			substr($todo, 0, 1) = '';	    
			push (@Reci,"$todo\n");	
	    		}
	    	    }

# use $Stop because no $ret im mail from postmaster/mailer, use for no info e.g. .local 
$Stop = index ($ret{$msg},"@");

#if ($from{$msg}=~ /\.local/){
#    $Stop= 0;
#    }

if ($Stop > 0){ 
$to=$from{$msg};
    if ($from{$msg}=~ /.*<(.*)>/){
    $to=$1;
    }
    open(MAIL,"|$Sendmail_Prog -t") || print STDERR "Mailprogramm error, not started \n";
    print MAIL "From: $mailfrom\n";
    print MAIL "To: $to\n"; # use "To: $mailfrom\n"; for test only
    print MAIL "Subject: eMail $subj{$msg} \n\n";
## in german:
    print MAIL "Die Mail von $ret{$msg}\n"; # set to RETURNPATH for info the sender e.g. if from wwwrun
    print MAIL "gesendet am $date{$msg}, mit dem \n"; 
    print MAIL "Betreff: $subj{$msg}  \n";
    print MAIL "konnte seit über $delhr{$msg} Stunden nicht an folgende Empfänger zugestellt werden: \n\n";
    print MAIL "@Reci \n" ; 	     
    print MAIL "Diese Infomail erhalten Sie max. $day Tage lang!\n";
    print MAIL "Mehr Infos unter http://seite_auf_server.tld/xyz.html !\n";
## english version follows:
#    print MAIL "The mail from $ret{$msg} sending on $date{$msg} with the \n"; 
#    print MAIL "Subject: $subj{$msg}  \n";
#    print MAIL "could not carried forward since $delhr{$msg} hours to the recipient: \n\n";
#    print MAIL "@Reci \n\n" ;
#    print MAIL "We will send this info $day days long\n";
#    print MAIL "For more informations visit http://whatyouthink.yourdomain.com/xyz.html \n";
##
    close(MAIL);
 		}
		}
	}
}
 
Last edited by a moderator:
ich habe erstmal die "umständliche" Lösung fertig :)
Code:
#print $mtext{$rmsg}, "\n"; # test only, enthält die Fehler zur Mail-Nummer
my (%Recip) = ();
my @Trak = split(/\n/,$mtext{$rmsg},);
for(@Trak)
    {
    my $line = $_;
    my @w = split ( /\s/ ,$line, ) ;
        if ( $w[1] eq "starting" )
        {
                $w[3] =~ s/\:// ; # Task
                $dmesg{$w[3]} = $w[8] ;
        }
        elsif ( $w[1] eq "delivery")
        {
                $w[2] =~ s/\:// ;  # Task
                my $m = ( $dmesg{$w[2]} || "" ) ;
                $Recip{$m} = $w[4] ;
        }

while (my ($Name, $Wert) = each %Recip) {
    $todo = join("\n",@Reci) ;
    if ($todo =~ /.*$Name.*/){
        }
    else{
    push (@Reci, "$Name\n $Wert\n\n");
    }
}
}

So kann ich jetzt in der Zustellinfomail auch die Fehlerursache einbauen bzw. kann damit durch den Aufruf von "queuetell" innerhalb von Sekunden prüfen, warum qmail die Mails nicht zustellt. Und das noch im alten Jahr :cool:
Code:
~# queuetell
 queue: 13/2345678
 Date : Tue, 30 Dec 2008 13:44:17 +0100
 From : info@meinedomain.de - Return: info@meinedomain.de
 Subj.: Guten Rutsch ins neue Jahr....
 Todo + Error:
 tolleadresse@web.de
 Connected_to_217.72.192.149_but_greeting_failed./Remote_host_said:_421_mx36 .web.de:_Too_many_concurrent_SMTP_connections_from_one_IP_address;_please_try_again_later./

 nocheiner@tschibo.de
 194.115.167.71_does_not_like_recipient./Remote_host_said:_554
 _Recipient_address_rejected:_tschibo.de_is_not_used_for_mail_purposes,_please_use_tchibo.de/Giving_up_on_
 194.115.167.71./

 test@t-onlie.de
 Sorry,_I_wasn't_able_to_establish_an_SMTP_connection._(#4.4.1)/

~#

Ach ja, die $mtext{$rmsg} wird im extra SUB erstellt ;)
 
Last edited by a moderator:
Back
Top