#!/usr/bin/env perl # # $Id$ # Script to parse /var/log/maillog from postfix # and send information to a .csv file. # Information is sender, recipient, time, # size and status of message. # # Source: http://linuxhacks.in/2013/10/maillog-parser-in-perl.html # Author: me@antonlindstrom.com # Updater: Suyash Jain # Rewritten and extended by: Reinier Post use strict; use warnings; # Define some global variables. my ( %from, %size, %time ); my $headered = 0; while (<>) { # Next if the row does not contain a mail address. #next if !/[\w\-\_\.]+\@[\w\-\_\.]+\.[a-z]+/; # Don't: from and to may be local! # example line: # Apr 18 06:30:02 nessus postfix/smtp[4147]: DC7385FA5E: to=, orig_to=, relay=smtp.tue.nl[131.155.15.38]:25, delay=0.17, delays=0.02/0.01/0.02/0.13, dsn=2.6.0, status=sent (250 2.6.0 <20210418043001.DC7385FA5E@nessus.infra.tue.nl> [InternalId=18751827214664, Hostname=EXCH19MBX-OP01.campus.tue.nl] 2028 bytes in 0.118, 16.682 KB/sec Queued mail for delivery) # First extract the timestamp, ID, and name=value, name=value parts: my ( $time, $rid, $attrs ) = m/(\w+\s+\d+\s\d+\:\d+\:\d+)\s.+\[\d+\]\:\s(\w+)\:\s(\w.*\S)/; $attrs or next; # suspect, but let it pass # Parse the name=value pairs in $attrs, # which consists of name=value pairs separated by ', ', # while, as shown above, the values may also contain ', '; # let's assume all such occurrences are enclosed by () brackets # and that within a value, only one such pair of brackets occurs: my %attr = map { my ( $name, $value ) = /^(\w+)=(.*)/ } $attrs =~ /\w+=[^,(]*(?:\([^)]*\)|)[^,]*/g; # Remove brackets around any mail addresses: s#^<(.*)>#$1# for values %attr; # Assign variables, $mailid is identifier for mail, therefore it can be used as key in hash. # All posts are assigned to a hash with the $mailid as key. if ( defined( $attr{from} ) && $attr{size} && $time ) { ( $from{$rid}, $size{$rid}, $time{$rid} ) = ( $attr{from}, $attr{size}, $time ); } if ( $attr{to} && $attr{status} ) { if ( exists( $from{$rid} ) && exists( $size{$rid} ) && exists( $time{$rid} ) ) { # print message transfer details as CSV if ( !$headered ) { printf( "%s,%s,%s,%s,%s,%s,%s,%s\n", qw(INTIME OUTTIME QID FROM TO DELAY SIZE STATUS) ); $headered = 1; } printf( "%s,%s,%s,%s,%s,%s,%s,%s\n", $time{$rid}, $time, $rid, $from{$rid}, $attr{to}, $attr{delay} // '', $size{$rid}, $attr{status} ); } else { warn "incomplete message details on message $rid in line: $_"; } } }