Re: format and output all received: lines in an e-mail message
Andy Bradford wrote in <20191121072709.1303.qm...@angmar.bradfordfamily.org>: |Thus said Greg Minshall on Wed, 20 Nov 2019 10:41:34 +0530: |> then, i'd like to use something like fmttest(1) to print out all the |> "Received:" lines in an e-mail message. ideally, each "Received:" line |> would come out on a separate line; less ideally, but i'm sure very |> practical, a very long line would come out, with some odd ascii code |> separating the individual lines. | |I usually use 822field (from mess822 [1]) for this kind of thing which |takes all received lines and reformats them one per line (odd ascii code |separating them is a newline). | |For example, your message looks like: | |$ 822field received < `mhpath cur` | tail -6 | from eggs.gnu.org ([2001:470:142:3::10]:33280) by lists.gnu.org with \ ... Well, yes, it is a bit restricted, but you could also use S-nail v14.9.11 or later: $ printf 'dig c 25 -;dig 25 h s received;digmsg r 25' |\ s-nail -#Rf +download 212 Received from lists.gnu.org (lists.gnu.org [209.51.188.17]) by sdaoden.eu (Postfix) with ESMTPS id 977431604A for ; Thu, 21 Nov 2019 15:28:01 +0100 (CET) from localhost ([::1]:41250 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iXnR9-000318-IA for stef...@sdaoden.eu; Thu, 21 Nov 2019 09:27:59 -0500 from eggs.gnu.org ([2001:470:142:3::10]:39911) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iXnQr-0002zm-Am for nmh-workers@nongnu.org; Thu, 21 Nov 2019 09:27:42 -0500 from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1iXnQq-0007yp-1j for nmh-workers@nongnu.org; Thu, 21 Nov 2019 09:27:41 -0500 from pellegrino.bradfordfamily.org ([208.53.44.231]:50897) by eggs.gnu.org with smtp (Exim 4.71) (envelope-from ) id 1iXnQp-0007uL-NM for nmh-workers@nongnu.org; Thu, 21 Nov 2019 09:27:39 -0500 (qmail 73392 invoked from network); 21 Nov 2019 14:27:26 - from localhost (HELO arnor.bradfordfamily.org) (127.0.0.1) by localhost with SMTP; 21 Nov 2019 14:27:26 - (qmail 71469 invoked from network); 21 Nov 2019 14:27:10 - from localhost (HELO edoras.bradfordfamily.org) (127.0.0.1) by localhost with SMTP; 21 Nov 2019 14:27:10 - (qmail 50445 invoked from network); 21 Nov 2019 14:27:10 - from angmar.bradfordfamily.org (50.77.44.21) by edoras.bradfordfamily.org with SMTP; 21 Nov 2019 14:27:10 - (qmail 27684 invoked by uid 1000); 21 Nov 2019 14:27:10 - Where dig is actually digmsg, c is create, h is header, s is show, and r is remove. String matching etc. via the csop and vexpr commands. I have heared someone revived qmail and wants to include some patches for builtin TLS etc. That sounded very much interesting, especially if its mailing-list manager would be maintained again! |Andy | |[1] https://cr.yp.to/mess822.html ... --steffen | |Der Kragenbaer,The moon bear, |der holt sich munter he cheerfully and one by one |einen nach dem anderen runter wa.ks himself off |(By Robert Gernhardt)
Re: format and output all received: lines in an e-mail message
Thus said Greg Minshall on Wed, 20 Nov 2019 10:41:34 +0530: > then, i'd like to use something like fmttest(1) to print out all the > "Received:" lines in an e-mail message. ideally, each "Received:" line > would come out on a separate line; less ideally, but i'm sure very > practical, a very long line would come out, with some odd ascii code > separating the individual lines. I usually use 822field (from mess822 [1]) for this kind of thing which takes all received lines and reformats them one per line (odd ascii code separating them is a newline). For example, your message looks like: $ 822field received < `mhpath cur` | tail -6 from eggs.gnu.org ([2001:470:142:3::10]:33280) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iXIOr-0005CP-UD for nmh-workers@nongnu.org; Wed, 20 Nov 2019 00:19:34 -0500 from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1iXIOq-00089z-NS for nmh-workers@nongnu.org; Wed, 20 Nov 2019 00:19:33 -0500 from hiwela.pair.com ([209.68.5.201]:21038) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1iXIOq-00088d-K6 for nmh-workers@nongnu.org; Wed, 20 Nov 2019 00:19:32 -0500 from hiwela.pair.com (localhost [127.0.0.1]) by hiwela.pair.com (Postfix) with ESMTP id 001419805E3 for ; Wed, 20 Nov 2019 00:11:43 -0500 (EST) from minshall-entroware-apollo.cliq.com (unknown [59.95.74.169]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by hiwela.pair.com (Postfix) with ESMTPSA id 89AEF8F084C for ; Wed, 20 Nov 2019 00:11:43 -0500 (EST) from apollo2.minshall.org (localhost [IPv6:::1]) by minshall-entroware-apollo.cliq.com (Postfix) with ESMTP id E305D6089A for ; Wed, 20 Nov 2019 10:41:34 +0530 (IST) Andy [1] https://cr.yp.to/mess822.html -- TAI64 timestamp: 40005dd69ee2
Re: format and output all received: lines in an e-mail message
greg wrote: > ps -- the goal is a little "blame" script for e-mail that tells you how > long a given message spent moving from A to B. (this relies, of course, > on globally synchronized clocks, but that seems much more likely to be > true today than it did when Received: lines were first introduced.) Oh, why didn't you say so. :-) Don't know if he's still on the list, but I cribbed this from Chris Garrigues many many years ago. Takes a raw message on stdin. paul #!/usr/bin/perl -w # # mailroute by Chris Garrigues # # Reads an email message on stdin and pretty prints the contents of the # recieved headers. # # When given an email message as it's argument will parse out the received # headers and display the route it took to get to you and the times it # arrived at each of the locations in your local timezone. # # It also tries to be clever in how it displays things: (1) It only shows # what changed in the date/time rather than the entire date/time each time. # (2) It breaks the line before the keywords "from", "by", and "with" # unless they appear in comments. # Changes by Mikko H�nninen # # - match non-numeric timezones, as well as more liberal number checking # - allow for two digit years as well as four digits (actually, any number # of digits) # - also display Delivered-To: lines amidst Received: information # - timezone conversion works even with timezones like +0745 # - somewhat prettier output (split at by/with/from) for non-recognised # date lines # - print time difference from first entry # - print time different always, even if it's the same as previous time # (so you can see where each hop is) # - added "id" and "for" to keywords before which a linebreak is added # - print date information on a separate line, so there's no need to reserve # columns for it on every line # - print malformed received lines (cannot parse date) "as-is" with no # offset use Time::Local; # Global variable for date parsing %mon = ('jan' => 0, 'feb' => 1, 'mar' => 2, 'apr' => 3, 'may' => 4, 'jun' => 5, 'jul' => 6, 'aug' => 7, 'sep' => 8, 'oct' => 9, 'nov' => 10, 'dec' => 11); # Initialize some variables to keep -w quiet ($owd, $om, $od, $ot, $oy) = ("", "", "", "", ""); # Perl trim function to remove whitespace from the start and end of the string sub trim($) { my $string = shift; $string =~ s/^\s+//; $string =~ s/\s+$//; return $string; } # Read the headers into $_ ($_ = "\n" . join("", <>)) =~ s/\n\n.*$//sg; # Parse the contents of the received headers into an array @rec = (); while (/\n(received|delivered-to):(.*?)(\n\S)/gis) { unshift(@rec, "$1:$2"); #print "Adding $1: $2\n"; $_ = "$3$'"; } #while (/\nreceived:(.*?)(\n\S)/gis) { #unshift(@rec, $1); #print "Adding Received: $1\n"; #$_ = "$2$'"; #} for (@rec) { if (/^delivered-to:/i) { s/^delivered-to://i; # strip Delivered-To: s/\s+/ /gs; s/^\s+//; print " Delivered-To: $_\n"; } else { s/^received://i; # strip Received: s/\s+/ /gs; # Format is "information; date" ($line, $date) = /^\s*(.*?)\s*;\s*(.*?)$/; if (!$date) { # no date, must be malformed? simscan will produce these # just print it out and go to next print " ", trim($_), "\n"; next; } $date =~ s/\(.*\)//g; $date =~ s/\s+/ /gs; # Parse the sucker if ($date =~ /(\d+) (jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec) (\d+) (\d+):(\d\d):(\d\d) ([+-]?\d+|\w+)/i) { # Coerce the date into something we can give to timegm $d = $1; ($m = $2) =~ tr/A-Z/a-z/; $y = $3; $h = $4; $mi = $5; $s = $6; $tz = $7; if ($tz =~ /[+-]?\d+/) { ($zs, $zh, $zm) = $tz =~ /^([-+])(\d\d)(\d\d)$/; } else { $zs = "+"; $zh = $zm = 0; } # word tz def, assume GMT $m = $mon{$m}; if ($y > 1900) { $y -= 1900; } elsif ($y < 70) { $y += 100; } # Y2K fix if ($zs eq "+") { $zs = 1; } else { $zs = -1; } $ts = timegm($s, $mi, $h, $d, $m, $y) - $zs * ($zh*60*60 + $zm*60); $begints = $ts unless ($begints); ($wd, $m, $d, $t, $y) = split(' ', localtime($ts)); $d = " $d" if ($d < 10); # Insert line breaks $line =~ s/\b(by|with|from|id|for)\b/\n $1/g; # But take them back out if they're in a comment while ($line =~ s/\(([^()]*?)\s\s+?(.*?)\)/\($1 $2\)/gs) {}; $line =~ s/\( /\(/g; $line =~ s/^\s*//s; # Figure out what parts of the date we want to display ($pwd, $pm, $pd, $pt, $py) = ($wd, $m, $d, $t, $y); $pwd = "" if ($wd eq $owd); $pm = "" if ($d eq $od); #$pm = "" if ($m eq $om); $pd = "" if ($d eq $od); $pt = "" if ($t eq