]> git.ipfire.org Git - thirdparty/AWStats.git/commitdiff
Fixed wrong parsing for qmail log files.
authoreldy <>
Wed, 17 Sep 2003 16:08:11 +0000 (16:08 +0000)
committereldy <>
Wed, 17 Sep 2003 16:08:11 +0000 (16:08 +0000)
Support mail errors in qmail log files.
Return code for postfix log were all reported in error for mails sent to several recipients when one recipient was in error.

tools/maillogconvert.pl

index 89dd21f0326f9119c9ca816ab3fc90858c5dee9e..ce39f2fa4939d3ee45f58453ac2fe7178f00ea56 100644 (file)
@@ -25,12 +25,15 @@ $VERSION="1.1 (build $REVISION)";
 use vars qw/
 $DIR $PROG $Extension
 $Debug
-%entry $help
+%mail %qmaildelivery
+$help
 $mode $year $Debug
-$NBOFLINESFORFLUSH
+$NBOFENTRYFOFLUSH
+$MailType
 /;
 
-$NBOFLINESFORFLUSH=8192;               # Nb or records for flush of %entry (Must be a power of 2)
+$NBOFENTRYFOFLUSH=8192;                # Nb or records for flush of %entry (Must be a power of 2)
+$MailType='';                          # Mail server family (postfix, sendmail, qmail)
 
 
 #-------------------------------------------------------
@@ -93,51 +96,63 @@ sub trim { $_=shift;
        return $_;
 }
 
+# Write a record
+#
 sub OutputRecord {
-       my $id=shift;
+       my $year=shift;
+       my $month=shift;
+       my $day=shift;
+       my $time=shift;
+       my $from=shift;
+       my $to=shift;
+       my $relay_s=shift;
+       my $relay_r=shift;
+       my $code=shift;
+       my $size=shift||0;
+       my $forwardto=shift;
 
        # Clean day and month
-       $entry{$id}{'day'}=sprintf("%02d",$entry{$id}{'day'});
-       if ($entry{$id}{mon} eq 'Jan') { $entry{$id}{mon} = "01"; }
-       if ($entry{$id}{mon} eq 'Feb') { $entry{$id}{mon} = "02"; }
-       if ($entry{$id}{mon} eq 'Mar') { $entry{$id}{mon} = "03"; }
-       if ($entry{$id}{mon} eq 'Apr') { $entry{$id}{mon} = "04"; }
-       if ($entry{$id}{mon} eq 'May') { $entry{$id}{mon} = "05"; }
-       if ($entry{$id}{mon} eq 'Jun') { $entry{$id}{mon} = "06"; }
-       if ($entry{$id}{mon} eq 'Jul') { $entry{$id}{mon} = "07"; }
-       if ($entry{$id}{mon} eq 'Aug') { $entry{$id}{mon} = "08"; }
-       if ($entry{$id}{mon} eq 'Sep') { $entry{$id}{mon} = "09"; }
-       if ($entry{$id}{mon} eq 'Oct') { $entry{$id}{mon} = "10"; }
-       if ($entry{$id}{mon} eq 'Nov') { $entry{$id}{mon} = "11"; }
-       if ($entry{$id}{mon} eq 'Dec') { $entry{$id}{mon} = "12"; }
+       $day=sprintf("%02d",$day);
+       if ($month eq 'Jan') { $month = "01"; }
+       if ($month eq 'Feb') { $month = "02"; }
+       if ($month eq 'Mar') { $month = "03"; }
+       if ($month eq 'Apr') { $month = "04"; }
+       if ($month eq 'May') { $month = "05"; }
+       if ($month eq 'Jun') { $month = "06"; }
+       if ($month eq 'Jul') { $month = "07"; }
+       if ($month eq 'Aug') { $month = "08"; }
+       if ($month eq 'Sep') { $month = "09"; }
+       if ($month eq 'Oct') { $month = "10"; }
+       if ($month eq 'Nov') { $month = "11"; }
+       if ($month eq 'Dec') { $month = "12"; }
 
        # Clean from
-       $entry{$id}{'from'}=&CleanEmail($entry{$id}{'from'});
-       $entry{$id}{'from'}||='<>';
+       $from=&CleanEmail($from);
+       $from||='<>';
        
        # Clean to
-       if ($mode eq 'vadmin') { $entry{$id}{'to'}=&CleanVadminUser($entry{$id}{'to'}); }
-       else { $entry{$id}{'to'}=&CleanEmail($entry{$id}{'to'}); }
-       $entry{$id}{'to'}||='<>';
+       if ($mode eq 'vadmin') { $to=&CleanVadminUser($to); }
+       else { $to=&CleanEmail($to); }
+       $to||='<>';
 
        # Clean relay_s
-       $entry{$id}{'relay_s'}=&CleanHost($entry{$id}{'relay_s'});
-       $entry{$id}{'relay_s'}||=&CleanDomain($entry{$id}{'from'});
-       $entry{$id}{'relay_s'}=~s/\.$//;
-       if ($entry{$id}{'relay_s'} eq 'local' || $entry{$id}{'relay_s'} eq 'localhost.localdomain') { $entry{$id}{'relay_s'}='localhost'; }
+       $relay_s=&CleanHost($relay_s);
+       $relay_s||=&CleanDomain($from);
+       $relay_s=~s/\.$//;
+       if ($relay_s eq 'local' || $relay_s eq 'localhost.localdomain') { $relay_s='localhost'; }
 
        # Clean relay_r
-       $entry{$id}{'relay_r'}=&CleanHost($entry{$id}{'relay_r'});
-       $entry{$id}{'relay_r'}||="-";
-       $entry{$id}{'relay_r'}=~s/\.$//;
-       if ($entry{$id}{'relay_r'} eq 'local' || $entry{$id}{'relay_r'} eq 'localhost.localdomain') { $entry{$id}{'relay_r'}='localhost'; }
+       $relay_r=&CleanHost($relay_r);
+       $relay_r||="-";
+       $relay_r=~s/\.$//;
+       if ($relay_r eq 'local' || $relay_r eq 'localhost.localdomain') { $relay_r='localhost'; }
        #if we don't have info for relay_s, we keep it unknown, awstats might then guess it
        
        # Write line
-       print "$year-$entry{$id}{mon}-$entry{$id}{day} $entry{$id}{time} $entry{$id}{from} $entry{$id}{to} $entry{$id}{relay_s} $entry{$id}{relay_r} SMTP - $entry{$id}{code} ".($entry{$id}{size}||0)."\n";
+       print "$year-$month-$day $time $from $to $relay_s $relay_r SMTP - $code $size\n";
        
        # If there was a redirect
-       if ($entry{$id}{'frowardto'}) {
+       if ($forwardto) {
                # Redirect to local address
                # TODO
                # Redirect to external address
@@ -196,88 +211,100 @@ HELPTEXT
 #
 # Start Processing Input Logfile
 #
-$NBOFLINESFORFLUSH--;
 my $numrecord=0;
+my $numrecordforflush=0;
 while (<>) {
        chomp $_; s/\r//;
        $numrecord++;
-       
-       my $rowid=0;
+       $numrecordforflush++;
+
+       my $mailid=0;
+
+       if (/^__BREAKPOINT__/) { last; }        # For debug only
 
+       if (/^#/) {
+               debug("Comment record");
+               next;
+       }
+       
        #
        # Get sender host for postfix
        #
-       if (/: client=/ ne undef) {
+       elsif (/: client=/ ne undef) {
+               $MailType||='postfix';
                my ($id,$relay_s)=m/\w+\s+\d+\s+\d+:\d+:\d+\s+[\w\-]+\s+(?:sendmail|postfix\/smtpd|postfix\/smtp)\[\d+\]:\s+(.*?):\s+client=(.*)/;
-               $rowid=$id;
-               $entry{$id}{'relay_s'}=$relay_s;
-               debug("For id=$id, found host sender on a 'client' line: $entry{$id}{'relay_s'}");
+               $mailid=$id;
+               $mail{$id}{'relay_s'}=$relay_s;
+               debug("For id=$id, found host sender on a 'client' line: $mail{$id}{'relay_s'}");
        }
 
        #
        # See if we received postfix email reject error
        #
        elsif (/: reject/ ne undef) {
+               $MailType||='postfix';
                # Example: 
                # postfix:  Jan 01 04:19:04 apollon postfix/smtpd[26553]: 1954F3B8A4: reject: RCPT from unknown[80.245.33.2]: 450 <partenaires@chiensderace.com>: User unknown in local recipient table; from=<httpd@fozzy2.dpi-europe.fr> to=<partenaires@chiensderace.com> proto=ESMTP helo=<fozzy2.dpi-europe.fr>
                # postfix:  Jan 01 04:26:39 halley postfix/smtpd[9245]: reject: RCPT from unknown[203.156.32.33]: 554 <charitha99@yahoo.com>: Recipient address rejected: Relay access denied; from=<1126448365@aol.com> to=<charitha99@yahoo.com>\r
                my ($mon,$day,$time,$id,$code,$from,$to)=m/(\w+)\s+(\d+)\s+(\d+:\d+:\d+)\s+[\w\-]+\s+(?:postfix\/smtpd|postfix\/smtp)\[\d+\]:\s+(.*?):\s+(.*)\s+from=([^\s,]*)\s+to=([^\s,]*)/;
-               $rowid=($id eq 'reject'?999:$id);       # id not provided in log, we take 999
+               $mailid=($id eq 'reject'?999:$id);      # id not provided in log, we take 999
                # $code='reject: RCPT from c66.191.66.89.dul.mn.charter.com[66.191.66.89]: 450 <partenaires@chiensderace.com>: User unknown in local recipient table;'
                #    or 'reject: RCPT from unknown[203.156.32.33]: 554 <charitha99@yahoo.com>: Recipient address rejected: Relay access denied;'
-               if ($rowid) {
-                       if ($code =~ /\s+(\d\d\d)\s+/) { $entry{$rowid}{'code'}=$1; }
-                       else { $entry{$rowid}{'code'}=999; }    # Unkown error
-                       if (! $entry{$rowid}{'relay_s'} &&  $code =~ /from\s+([^\s]+)\s+/) {
-                               $entry{$rowid}{'relay_s'}=&trim($1);
+               if ($mailid) {
+                       if ($code =~ /\s+(\d\d\d)\s+/) { $mail{$mailid}{'code'}=$1; }
+                       else { $mail{$mailid}{'code'}=999; }    # Unkown error
+                       if (! $mail{$mailid}{'relay_s'} &&  $code =~ /from\s+([^\s]+)\s+/) {
+                               $mail{$mailid}{'relay_s'}=&trim($1);
                        }
-                       $entry{$rowid}{'from'}=&trim($from);
-                       $entry{$rowid}{'to'}=&trim($to);
-                       $entry{$rowid}{'mon'}=$mon;
-                       $entry{$rowid}{'day'}=$day;
-                       $entry{$rowid}{'time'}=$time;
-                       debug("For id=$rowid, found a postfix error incoming message: code=$entry{$rowid}{'code'} from=$entry{$rowid}{'from'} to=$entry{$rowid}{'to'}");
+                       $mail{$mailid}{'from'}=&trim($from);
+                       $mail{$mailid}{'to'}=&trim($to);
+                       $mail{$mailid}{'mon'}=$mon;
+                       $mail{$mailid}{'day'}=$day;
+                       $mail{$mailid}{'time'}=$time;
+                       debug("For id=$mailid, found a postfix error incoming message: code=$mail{$mailid}{'code'} from=$mail{$mailid}{'from'} to=$mail{$mailid}{'to'}");
                }
        }
        #
        # See if we received sendmail reject error
        #
        elsif (/, reject/ ne undef) {
+               $MailType||='sendmail';
                # Example: 
                # sm-mta:   Jul 27 04:06:05 androneda sm-mta[6641]: h6RB44tg006641: ruleset=check_mail, arg1=<7ms93d4ms@topprodsource.com>, relay=crelay1.easydns.com [216.220.57.222], reject=451 4.1.8 Domain of sender address 7ms93d4ms@topprodsource.com does not resolve
                # sm-mta:       Jul 27 06:21:24 androneda sm-mta[11461]: h6RDLNtg011461: ruleset=check_rcpt, arg1=<nobody@nova.dice.net>, relay=freedom.myhostdns.com [66.246.77.42], reject=550 5.7.1 <nobody@nova.dice.net>... Relaying denied
                # sendmail: Sep 30 04:21:32 halley sendmail[3161]: g8U2LVi03161: ruleset=check_rcpt, arg1=<amber3624@netzero.net>, relay=moon.partenor.fr [10.0.0.254], reject=550 5.7.1 <amber3624@netzero.net>... Relaying denied
                my ($mon,$day,$time,$id,$ruleset,$arg,$relay_s,$code)=m/(\w+)\s+(\d+)\s+(\d+:\d+:\d+)\s+[\w\-]+\s+(?:sendmail|sm-mta)\[\d+\]:\s+(.*?):\sruleset=(\w+),\s+arg1=(.*),\s+relay=(.*),\s+(reject=.*)/;
-               $rowid=$id;
-               if ($rowid) {
-                       if ($ruleset eq 'check_mail') { $entry{$id}{'from'}=$arg; }
-                       if ($ruleset eq 'check_rcpt') { $entry{$id}{'to'}=$arg; }
-                       $entry{$id}{'relay_s'}=$relay_s;
+               $mailid=$id;
+               if ($mailid) {
+                       if ($ruleset eq 'check_mail') { $mail{$id}{'from'}=$arg; }
+                       if ($ruleset eq 'check_rcpt') { $mail{$id}{'to'}=$arg; }
+                       $mail{$id}{'relay_s'}=$relay_s;
                        # $code='reject=550 5.7.1 <amber3624@netzero.net>... Relaying denied'
-                       if ($code =~ /=(\d\d\d)\s+/) { $entry{$id}{'code'}=$1; }
-                       else { $entry{$id}{'code'}=999; }       # Unkown error
-                       $entry{$id}{'mon'}=$mon;
-                       $entry{$id}{'day'}=$day;
-                       $entry{$id}{'time'}=$time;
-                       debug("For id=$id, found a sendmail error incoming message: code=$entry{$id}{'code'} from=$entry{$id}{'from'} to=$entry{$id}{'to'} relay_s=$entry{$id}{'relay_s'}");
+                       if ($code =~ /=(\d\d\d)\s+/) { $mail{$id}{'code'}=$1; }
+                       else { $mail{$id}{'code'}=999; }        # Unkown error
+                       $mail{$id}{'mon'}=$mon;
+                       $mail{$id}{'day'}=$day;
+                       $mail{$id}{'time'}=$time;
+                       debug("For id=$id, found a sendmail error incoming message: code=$mail{$id}{'code'} from=$mail{$id}{'from'} to=$mail{$id}{'to'} relay_s=$mail{$id}{'relay_s'}");
                }
        }
        #
        # See if we received postfix email bounced error
        #
        elsif (/stat(us)?=bounced/ ne undef) {
+               $MailType||='postfix';
                # Example: 
                # postfix:  Sep  9 18:24:23 halley postfix/local[22003]: 12C6413EC9: to=<etavidian@partenor.com>, relay=local, delay=0, status=bounced (unknown user: "etavidian")
                my ($mon,$day,$time,$id,$to,$relay_r)=m/(\w+)\s+(\d+)\s+(\d+:\d+:\d+)\s+[\w\-]+\s+(?:postfix\/(?:local|smtpd|smtp))\[\d+\]:\s+(.*?):\s+to=([^\s,]*)[\s,]+relay=([^\s,]*)/;
-               $rowid=($id eq 'reject'?999:$id);       # id not provided in log, we take 999
-               if ($rowid) {
-                       $entry{$rowid}{'code'}="999";   # Unkown error (bounced)
-                       $entry{$rowid}{'to'}=&trim($to);
-                       $entry{$rowid}{'relay_r'}=&trim($relay_r);
-                       $entry{$rowid}{'mon'}=$mon;
-                       $entry{$rowid}{'day'}=$day;
-                       $entry{$rowid}{'time'}=$time;
-                       debug("For id=$rowid, found a postfix bounced incoming message: code=$entry{$rowid}{'code'} to=$entry{$rowid}{'to'} relay_r=$entry{$rowid}{'relay_r'}");
+               $mailid=($id eq 'reject'?999:$id);      # id not provided in log, we take 999
+               if ($mailid) {
+                       $mail{$mailid}{'code'}="999";   # Unkown error (bounced)
+                       $mail{$mailid}{'to'}=&trim($to);
+                       $mail{$mailid}{'relay_r'}=&trim($relay_r);
+                       $mail{$mailid}{'mon'}=$mon;
+                       $mail{$mailid}{'day'}=$day;
+                       $mail{$mailid}{'time'}=$time;
+                       debug("For id=$mailid, found a postfix bounced incoming message: code=$mail{$mailid}{'code'} to=$mail{$mailid}{'to'} relay_r=$mail{$mailid}{'relay_r'}");
                }
        }
 
@@ -285,38 +312,42 @@ while (<>) {
        # See if we send a sendmail (with ctladdr tag) email
        #
        elsif(/, ctladdr=/ ne undef) {
-                       #
-                       # Matched outgoing sendmail/postfix message
-                       #
-                       my ($mon,$day,$time,$id,$to,$from)=m/(\w+)\s+(\d+)\s+(\d+:\d+:\d+)\s+[\w\-]+\s+(?:sm-mta|sendmail(?:-out|)|postfix\/(?:local|smtpd|smtp))\[.*?\]:\s+([^:]*):\s+to=(.*?)[,\s]+ctladdr=([^\,\s]*)/;
-                       $rowid=$id;
-                       if (m/\s+relay=([^\s,]*)[\s,]/) { $entry{$id}{'relay_r'}=$1; }
-                       elsif (m/\s+mailer=local/) { $entry{$id}{'relay_r'}='localhost'; }
-                       if (/, stat\=Sent/) { $entry{$id}{'code'}=1; }
-                       elsif (/, stat\=User\s+unknown/) { $entry{$id}{'code'}=550; }
-                       elsif (/, stat\=Local\s+configuration/) { $entry{$id}{'code'}=451; }
-                       elsif (/, stat\=Deferred:\s+(\d*)/) { $entry{$id}{'code'}=$1; }
-                       else { $entry{$id}{'code'}=999; }
-                       $entry{$id}{'mon'}=$mon;
-                       $entry{$id}{'day'}=$day;
-                       $entry{$id}{'time'}=$time;
-                       $entry{$id}{'to'}=&trim($to);
-                       $entry{$id}{'from'}=&trim($from);
-                       $entry{$id}{'size'}='?';
-                       debug("For id=$id, found a sendmail outgoing message: to=$entry{$id}{'to'} from=$entry{$id}{'from'} size=$entry{$id}{'size'} relay_s=$entry{$id}{'relay_s'}");
+               $MailType||='sendmail';
+               #
+               # Matched outgoing sendmail/postfix message
+               #
+               my ($mon,$day,$time,$id,$to,$from)=m/(\w+)\s+(\d+)\s+(\d+:\d+:\d+)\s+[\w\-]+\s+(?:sm-mta|sendmail(?:-out|)|postfix\/(?:local|smtpd|smtp))\[.*?\]:\s+([^:]*):\s+to=(.*?)[,\s]+ctladdr=([^\,\s]*)/;
+               $mailid=$id;
+               if (m/\s+relay=([^\s,]*)[\s,]/) { $mail{$id}{'relay_r'}=$1; }
+               elsif (m/\s+mailer=local/) { $mail{$id}{'relay_r'}='localhost'; }
+               if (/, stat\=Sent/) { $mail{$id}{'code'}=1; }
+               elsif (/, stat\=User\s+unknown/) { $mail{$id}{'code'}=550; }
+               elsif (/, stat\=Local\s+configuration/) { $mail{$id}{'code'}=451; }
+               elsif (/, stat\=Deferred:\s+(\d*)/) { $mail{$id}{'code'}=$1; }
+               else { $mail{$id}{'code'}=999; }
+               $mail{$id}{'mon'}=$mon;
+               $mail{$id}{'day'}=$day;
+               $mail{$id}{'time'}=$time;
+               $mail{$id}{'to'}=&trim($to);
+               $mail{$id}{'from'}=&trim($from);
+               $mail{$id}{'size'}='?';
+               debug("For id=$id, found a sendmail outgoing message: to=$mail{$id}{'to'} from=$mail{$id}{'from'} size=$mail{$id}{'size'} relay_s=$mail{$id}{'relay_s'}");
        }
 
        #
        # Matched incoming qmail message
        #
        elsif (/info msg .* from/ ne undef) {
-               my ($id,$size,$from)=m/(\d+)(?:\.\d+)? info msg \d+: bytes (\d+) from <(.*)>/;
-               $rowid=$id;
-               if (! $entry{$id}{'code'}) { $entry{$id}{'code'}=1; }   # If not already defined, we define it
-               if ($entry{$id}{'from'} ne '<>') { $entry{$id}{'from'}=$from; }
-               $entry{$id}{'size'}=$size;
-               if (m/\s+relay=([^\,]+)[\s\,]/ || m/\s+relay=([^\s\,]+)$/) { $entry{$id}{'relay_s'}=$1; }
-               debug("For id=$id, found a qmail incoming message: from=$entry{$id}{'from'} size=$entry{$id}{'size'} relay_s=$entry{$id}{'relay_s'}");
+               # Example: Sep 14 09:58:09 gandalf qmail: 1063526289.292776 info msg 270182: bytes 10712 from <john@john.do> qp 54945 uid 82
+               $MailType||='qmail';
+               #my ($id,$size,$from)=m/(\d+)(?:\.\d+)? info msg \d+: bytes (\d+) from <(.*)>/;
+               my ($id,$size,$from)=m/\d+(?:\.\d+)? info msg (\d+): bytes (\d+) from <(.*)>/;
+               $mailid=$id;
+               delete $mail{$mailid};  # If 'info msg' found, we start a new mail. This is to protect from wrong file
+               if ($mail{$id}{'from'} ne '<>') { $mail{$id}{'from'}=$from; }   # TODO ???
+               $mail{$id}{'size'}=$size;
+               if (m/\s+relay=([^\,]+)[\s\,]/ || m/\s+relay=([^\s\,]+)$/) { $mail{$id}{'relay_s'}=$1; }
+               debug("For id=$id, found a qmail 'info msg' message: from=$mail{$id}{'from'} size=$mail{$id}{'size'} relay_s=$mail{$id}{'relay_s'}");
        }
 
        #
@@ -326,12 +357,12 @@ while (<>) {
                # sm-mta:  Jul 28 06:55:13 androneda sm-mta[28877]: h6SDtCtg028877: from=<4cmkh79eob@webtv.net>, size=2556, class=0, nrcpts=1, msgid=<w1$kqj-9-o2m45@0h2i38.4.m0.5u>, proto=ESMTP, daemon=MTA, relay=smtp.easydns.com [205.210.42.50]
                # postfix: Jul  3 15:32:26 apollon postfix/qmgr[13860]: 08FB63B8A4: from=<nobody@ns3744.ovh.net>, size=3302, nrcpt=1 (queue active)
                my ($id,$from,$size)=m/\w+\s+\d+\s+\d+:\d+:\d+\s+[\w\-]+\s+(?:sm-mta|sendmail(?:-in|)|postfix\/qmgr|postfix\/nqmgr)\[\d+\]:\s+(.*?):\s+from=(.*?),\s+size=(.*?),/;
-               $rowid=$id;
-               if (! $entry{$id}{'code'}) { $entry{$id}{'code'}=1; }   # If not already defined, we define it
-               if ($entry{$id}{'from'} ne '<>') { $entry{$id}{'from'}=$from; }
-               $entry{$id}{'size'}=$size;
-               if (m/\s+relay=([^\,]+)[\s\,]/ || m/\s+relay=([^\s\,]+)$/) { $entry{$id}{'relay_s'}=$1; }
-               debug("For id=$id, found a sendmail/postfix incoming message: from=$entry{$id}{'from'} size=$entry{$id}{'size'} relay_s=$entry{$id}{'relay_s'}");
+               $mailid=$id;
+               if (! $mail{$id}{'code'}) { $mail{$id}{'code'}=1; }     # If not already defined, we define it
+               if ($mail{$id}{'from'} ne '<>') { $mail{$id}{'from'}=$from; }
+               $mail{$id}{'size'}=$size;
+               if (m/\s+relay=([^\,]+)[\s\,]/ || m/\s+relay=([^\s\,]+)$/) { $mail{$id}{'relay_s'}=$1; }
+               debug("For id=$id, found a sendmail/postfix incoming message: from=$mail{$id}{'from'} size=$mail{$id}{'size'} relay_s=$mail{$id}{'relay_s'}");
        }
 
        #
@@ -339,82 +370,143 @@ while (<>) {
        #
        elsif (/: to=.*stat(us)?=sent/i ne undef) {
                my ($mon,$day,$time,$id,$to)=m/(\w+)\s+(\d+)\s+(\d+:\d+:\d+)\s+[\w\-]+\s+(?:sm-mta|sendmail(?:-out|)|postfix\/(?:local|smtpd|smtp))\[.*?\]:\s+(.*?):\s+to=(.*?),/;
-               $rowid=$id;
-               if (m/\s+relay=([^\s,]*)[\s,]/) { $entry{$id}{'relay_r'}=$1; }
-               elsif (m/\s+mailer=local/) { $entry{$id}{'relay_r'}='localhost'; }
+               $mailid=$id;
+               $mail{$id}{'code'}='1';
+               if (m/\s+relay=([^\s,]*)[\s,]/) { $mail{$id}{'relay_r'}=$1; }
+               elsif (m/\s+mailer=local/) { $mail{$id}{'relay_r'}='localhost'; }
                if (m/forwarded as/) {
                        # If 'forwarded as idnewmail' is found, we discard this mail to avoid counting it twice
                        debug("For id=$id, mail was forwarded to other id, we discard it");
-                       undef $entry{$id};
+                       delete $mail{$id};
                }
                else {
                        if (m/\s+orig_to=([^\s,]*)[\s,]/) {
                                # If we have a orig_to, we used it as receiver
-                               $entry{$id}{'to'}=&trim($1);
-                               $entry{$id}{'forwardedto'}=&trim($to);
+                               $mail{$id}{'to'}=&trim($1);
+                               $mail{$id}{'forwardedto'}=&trim($to);
                        }
                        else {
-                               $entry{$id}{'to'}=&trim($to);
+                               $mail{$id}{'to'}=&trim($to);
                        }
-                       $entry{$id}{'mon'}=$mon;
-                       $entry{$id}{'day'}=$day;
-                       $entry{$id}{'time'}=$time;
-                       debug("For id=$id, found a sendmail/postfix record: mon=$entry{$id}{'mon'} day=$entry{$id}{'day'} time=$entry{$id}{'time'} to=$entry{$id}{'to'} relay_r=$entry{$id}{'relay_r'}");
+                       $mail{$id}{'mon'}=$mon;
+                       $mail{$id}{'day'}=$day;
+                       $mail{$id}{'time'}=$time;
+                       debug("For id=$id, found a sendmail/postfix record: mon=$mail{$id}{'mon'} day=$mail{$id}{'day'} time=$mail{$id}{'time'} to=$mail{$id}{'to'} relay_r=$mail{$id}{'relay_r'}");
                }
        }
 
        #
-       # Matched qmail "to" message
+       # Matched qmail "to" record
        #
        elsif (/starting delivery/ ne undef) {
-               my ($mon,$day,$time,$id,$to)=m/^(\w+)\s+(\d+)\s+(\d+:\d+:\d+)\s+.*\s+(\d+)(?:\.\d+)?\s+starting delivery \d+:\s+msg\s+\d+\s+to\s+.*?\s+(.*)$/;
-               $rowid=$id;
-               if (m/\s+relay=([^\s,]*)[\s,]/) { $entry{$id}{'relay_r'}=$1; }
-               elsif (m/\s+mailer=local/) { $entry{$id}{'relay_r'}='localhost'; }
-               $entry{$id}{'mon'}=$mon;
-               $entry{$id}{'day'}=$day;
-               $entry{$id}{'time'}=$time;
-               $entry{$id}{'to'}=&trim($to);
-               debug("For id=$id, found a qmail record: mon=$entry{$id}{'mon'} day=$entry{$id}{'day'} time=$entry{$id}{'time'} to=$entry{$id}{'to'} relay_r=$entry{$id}{'relay_r'}");
+               # Example: Sep 14 09:58:09 gandalf qmail: 1063526289.574100 starting delivery 251: msg 270182 to local spamreport@john.do
+               $MailType||='qmail';
+               #my ($mon,$day,$time,$id,$to)=m/^(\w+)\s+(\d+)\s+(\d+:\d+:\d+)\s+.*\s+(\d+)(?:\.\d+)?\s+starting delivery \d+:\s+msg\s+\d+\s+to\s+.*?\s+(.*)$/;
+               my ($mon,$day,$time,$delivery,$id,$to)=m/^(\w+)\s+(\d+)\s+(\d+:\d+:\d+)\s+.*\s+\d+(?:\.\d+)?\s+starting delivery (\d+):\s+msg\s+(\d+)\s+to\s+.*?\s+(.*)$/;
+               $mailid=$id;
+               if (m/\s+relay=([^\s,]*)[\s,]/) { $mail{$id}{'relay_r'}=$1; }
+               elsif (m/\s+mailer=local/) { $mail{$id}{'relay_r'}='localhost'; }
+               $qmaildelivery{$delivery}=$id;          # Save mail id for this delivery to be able to get error code
+               $mail{$id}{'mon'}=$mon;
+               $mail{$id}{'day'}=$day;
+               $mail{$id}{'time'}=$time;
+               $mail{$id}{'to'}{$delivery}=&trim($to);
+               debug("For id=$id, found a qmail 'start delivery' record: mon=$mail{$id}{'mon'} day=$mail{$id}{'day'} time=$mail{$id}{'time'} to=$mail{$id}{'to'}{$delivery} relay_r=$mail{$id}{'relay_r'} delivery=$delivery");
        }
 
        #
-       # Write record if full
+       # Matched qmail status code record
        #
-       if ($rowid) {
-               debug("ID:$rowid RELAY_S:$entry{$rowid}{'relay_s'} RELAY_R:$entry{$rowid}{'relay_r'} FROM:$entry{$rowid}{'from'} TO:$entry{$rowid}{'to'} CODE:$entry{$rowid}{'code'}");
-               if (
-                  ($entry{$rowid}{'from'} && $entry{$rowid}{'to'})
-               || ($entry{$rowid}{'from'} && $entry{$rowid}{'code'} > 1)
-               ) {
-                       &OutputRecord($rowid);
-                       # Delete generic unknown record
-                       if ($rowid == 999) {
-                               undef $entry{999};
-                       }
-               }
+       elsif (/delivery (\d+): (\w+):/ ne undef) {
+               # Example: Sep 14 09:58:09 gandalf qmail: 1063526289.744259 delivery 251: success: did_0+0+1/
+               $MailType||='qmail';
+               my ($delivery,$code)=($1,$2);
+               my $id=$qmaildelivery{$delivery};
+               $mailid=$id;
+               if ($code =~ /success/i) { $mail{$id}{'code'}{$delivery}=1; }
+               elsif ($code =~ /deferral/i) { $mail{$id}{'code'}{$delivery}=999; }
+               else { $mail{$id}{'code'}{$delivery}=999; }
+               debug("For id=$qmaildelivery{$delivery}, found a qmail 'delivery' record: delivery=$delivery code=$mail{$id}{'code'}{$delivery}");
        }
-       else {
-               debug("Not interesting row");
+       #
+       # Matched qmail end of mail record
+       #
+       elsif (/end msg (\d+)/ && scalar %{$mail{$1}{'to'}}) {  # If records for mail id are finished and still mails with no delivery status
+               # Example: Sep 14 09:58:12 gandalf qmail: 1063526292.782444 end msg 270182
+               $MailType||='qmail';
+               my ($id)=($1);
+               $mailid=$id;
+               foreach my $delivery (keys %{$mail{$mailid}{'to'}}) { $mail{$id}{'code'}{$delivery}||=1; }
+               debug("For id=$id, found a qmail 'end msg' record. This replace 'delivery' record for delivery=".join(',',keys %{$mail{$id}{'code'}}));
        }
 
+       #
+       # Write record if all required data were found
+       #
+       if ($mailid) {
+               my $code; my $to;
+               my $delivery=0;
+               my $canoutput=0;
+               
+               debug("ID:$mailid RELAY_S:$mail{$mailid}{'relay_s'} RELAY_R:$mail{$mailid}{'relay_r'} FROM:$mail{$mailid}{'from'} TO:$mail{$mailid}{'to'} CODE:$mail{$mailid}{'code'}");
+
+               # Check if we can output a mail line
+               if ($MailType eq 'qmail') {
+                       if (scalar %{$mail{$mailid}{'code'}}) {
+                               # This is a hash variable
+                               foreach my $key (keys %{$mail{$mailid}{'code'}}) {
+                                       $delivery=$key;
+                                       $code=$mail{$mailid}{'code'}{$key};
+                                       $to=$mail{$mailid}{'to'}{$key};
+                               }
+                               $canoutput=1;
+                       }
+               }
+               if ($MailType ne 'qmail') {
+                       $code=$mail{$mailid}{'code'};
+                       $to=$mail{$mailid}{'to'};
+                       if ($mail{$mailid}{'from'} && $mail{$mailid}{'to'}) { $canoutput=1; }
+                       if ($mail{$mailid}{'from'} && $mail{$mailid}{'code'} > 1) { $canoutput=1; }
+               }
+
+               # If we can
+               if ($canoutput) {
+                       &OutputRecord($year,$mail{$mailid}{'mon'},$mail{$mailid}{'day'},$mail{$mailid}{'time'},$mail{$mailid}{'from'},$to,$mail{$mailid}{'relay_s'},$mail{$mailid}{'relay_r'},$code,$mail{$mailid}{'size'},$mail{$mailid}{'forwardto'});
+                       # Delete mail with generic unknown id (This id can by used by another mail)
+                       if ($mailid == 999) {
+                               debug(" Delete mail for id=$mailid",3);
+                               delete $mail{$mailid};
+                       }
+                       # Delete delivery instance for id if qmail (qmail can use same id for several mails with multiple delivery)
+                       elsif ($MailType eq 'qmail') {
+                               debug(" Delete delivery instances for mail id=$mailid and delivery id=$delivery",3);
+                               if ($delivery) {
+                                       delete $mail{$mailid}{'to'}{$delivery};
+                                       delete $mail{$mailid}{'code'}{$delivery};
+                               }
+                       }
+
+                       # We flush %mail if too large
+                       if (scalar keys %mail > $NBOFENTRYFOFLUSH) {
+                               debug("We reach $NBOFENTRYFOFLUSH records in %mail, so we flush mail hash array");
+                               #foreach my $id (keys %mail) {
+                               #       debug(" Delete mail for id=$id",3);
+                               #       delete $mail{$id};
+                               #}
+                               %mail=();
+                               %qmaildelivery=();
+                       }
 
-       if ((++$numrecord & $NBOFLINESFORFLUSH) == 0) {
-               # We clean $entry
-               debug("We reach $numrecord records, so we flush entry hash array");
-               foreach my $id (keys %entry) {
-                       debug(" Delete entry for id=$id",3);
-                       undef $entry{$id};
                }
        }
+       else {
+               debug("Not interesting row");
+       }
 
 }
 
-0;
-
+#foreach my $key (keys %mail) {
+#      print ".$key.$mail{$key}{'to'}.\n";
+#}
 
-# SMTP Postfix errors:
-# 450 Sender or domain address not qualified (or Unkown recipient user with incomplete postfix setup)
-# 451 Domain of sender address
-# 550 Relaying denied or Unkown recipient user
-# 554 Relay denied
+0;