From 6b14f174d6a0addf8d1dcd0ca8c4a2ceeb48a989 Mon Sep 17 00:00:00 2001 From: azumakuniyuki Date: Mon, 11 Mar 2024 11:59:47 +0900 Subject: [PATCH 01/25] #508 Sisimai::RFC5322->received now returns a list including all the elements found in the Received header --- lib/Sisimai/RFC5322.pm | 200 ++++++++++++++++++++++++++--------------- t/031-rfc5322.t | 19 ++-- 2 files changed, 143 insertions(+), 76 deletions(-) diff --git a/lib/Sisimai/RFC5322.pm b/lib/Sisimai/RFC5322.pm index 0e800469..921700c2 100644 --- a/lib/Sisimai/RFC5322.pm +++ b/lib/Sisimai/RFC5322.pm @@ -3,6 +3,7 @@ use feature ':5.10'; use strict; use warnings; use Sisimai::String; +use Sisimai::Address; use constant HEADERTABLE => { 'messageid' => ['message-id'], 'subject' => ['subject'], @@ -49,84 +50,136 @@ sub LONGFIELDS { sub received { # Convert Received headers to a structured data # @param [String] argv1 Received header - # @return [Array] Received header as a structured data + # @return [Array] Each item in the Received header order by the following: + # 0: (from) "hostname" + # 1: (by) "hostname" + # 2: (via) "protocol/tcp" + # 3: (with) "protocol/smtp" + # 4: (id) "queue-id" + # 5: (for) "envelope-to address" my $class = shift; my $argv1 = shift || return []; - my $hosts = []; - my $value = { 'from' => '', 'by' => '' }; # Received: (qmail 10000 invoked by uid 999); 24 Apr 2013 00:00:00 +0900 - return [] if index($argv1, '(qmail ') > 0 && index($argv1, ' invoked ') > 0; - - my $p1 = index($argv1, 'from '); - my $p2 = index($argv1, 'by '); - my $p3 = index($argv1, ' ', $p2 + 3); - - if( $p1 == 0 && $p2 > 1 && $p2 < $p3 ) { - # Received: from localhost (localhost) by nijo.example.jp (V8/cf) id s1QB5ma0018057; - # Wed, 26 Feb 2014 06:05:48 -0500 - $value->{'from'} = Sisimai::String->sweep(substr($argv1, $p1 + 5, $p2 - $p1 - 5)); - $value->{'by'} = Sisimai::String->sweep(substr($argv1, $p2 + 3, $p3 - $p2 - 3)); - - } elsif( $p1 != 0 && $p2 > -1 ) { - # Received: by 10.70.22.98 with SMTP id c2mr1838265pdf.3; Fri, 18 Jul 2014 - # 00:31:02 -0700 (PDT) - $value->{'from'} = Sisimai::String->sweep(substr($argv1, $p2 + 3,)); - $value->{'by'} = Sisimai::String->sweep(substr($argv1, $p2 + 3, $p3 - $p2 - 3)); - } - - if( index($value->{'from'}, ' ') > -1 ) { - # Received: from [10.22.22.222] (smtp.kyoto.ocn.ne.jp [192.0.2.222]) (authenticated bits=0) - # by nijo.example.jp (V8/cf) with ESMTP id s1QB5ka0018055; Wed, 26 Feb 2014 06:05:47 -0500 - my @received = split(' ', $value->{'from'}); - my @namelist; - my @addrlist; - my $hostname = ''; - my $hostaddr = ''; - - for my $e ( @received ) { - # Received: from [10.22.22.222] (smtp-gateway.kyoto.ocn.ne.jp [192.0.2.222]) - my $cv = Sisimai::String->ipv4($e) || []; - if( scalar @$cv > 0 ) { - # [192.0.2.1] or (192.0.2.1) - push @addrlist, @$cv; + return [] if ref $argv1; + return [] if index($argv1, ' invoked by uid') > 0; + return [] if index($argv1, ' invoked from network') > 0; + + # - https://datatracker.ietf.org/doc/html/rfc5322 + # received = "Received:" *received-token ";" date-time CRLF + # received-token = word / angle-addr / addr-spec / domain + # + # - Appendix A.4. Message with Trace Fields + # Received: + # from x.y.test + # by example.net + # via TCP + # with ESMTP + # id ABC12345 + # for ; 21 Nov 1997 10:05:43 -0600 + my $recvd = [split(' ', $argv1)]; + my $label = [qw|from by via with id for|]; + my $token = {}; + my $other = []; + my $alter = []; + my $right = 0; + my $range = scalar @$recvd; + my $index = -1; + + for my $e ( @$recvd ) { + # Look up each label defined in $label from Received header + last unless ++$index < $range; + next unless grep { lc $e eq $_ } @$label; + + $token->{ $e } = $recvd->[$index + 1] || next; + chop $token->{ $e } if index($token->{ $e }, ';') > 1; + + next unless $e eq 'from'; + last unless $index + 2 < $range; + + if( index($recvd->[$index + 2], '(') == 0 ) { + # Get and keep a hostname in the comment as follows: + # from mx1.example.com (c213502.kyoto.example.ne.jp [192.0.2.135]) by mx.example.jp (V8/cf) + push @$other, substr($recvd->[$index + 2], 1,); + + if( index($other->[0], ')') > 1 ) { + # The 2nd element after the current element is NOT a continuation of the current element. + chop $other->[0]; + next; } else { - # hostname - $e =~ y/()//d; - push @namelist, $e; + # The 2nd element after the current element is a continuation of the current element. + push @$other, substr($recvd->[$index + 3], 0, -1); } } + } - for my $e ( @namelist ) { - # 1. Hostname takes priority over all other IP addresses - next unless rindex($e, '.') > -1; - $hostname = $e; - last; - } + for my $e ( @$other ) { + # Check alternatives in $other, and then delete uninformative values. + next unless $e; + next if length $e < 4; + next if $e eq 'unknown'; + next if $e eq 'localhost'; + next if $e eq '[127.0.0.1]'; + next if $e eq '[IPv6:::1]'; + next if index($e, '.') == -1; + next if index($e, '=') > 1; + push @$alter, $e; + } - unless( $hostname ) { - # 2. Use IP address as a remote host name - for my $e ( @addrlist ) { - # Skip if the address is a private address - next if index($e, '10.') == 0; - next if index($e, '127.') == 0; - next if index($e, '192.168.') == 0; - next if $e =~ /\A172[.](?:1[6-9]|2[0-9]|3[0-1])[.]/; - $hostaddr = $e; - last; - } - } - $value->{'from'} = $hostname || $hostaddr || $addrlist[-1]; + for my $e ($token->{'from'}, $token->{'by'}) { + # Remove square brackets from the IP address such as "[192.0.2.25]" + next unless defined $e; + next unless length $e; + next unless index($e, '[') == 0; + $e = shift Sisimai::String->ipv4($e)->@* || ''; } - for my $e ('from', 'by') { - # Copy entries into $hosts - next unless defined $value->{ $e }; - $value->{ $e } =~ y/()[];?//d; - push @$hosts, $value->{ $e }; + $token->{'from'} ||= ''; + while(1) { + # Prefer hostnames over IP addresses, except for localhost.localdomain and similar. + last if $token->{'from'} eq 'localhost'; + last if $token->{'from'} eq 'localhost.localdomain'; + last if index($token->{'from'}, '.') < 0; # A hostname without a domain name + last if scalar Sisimai::String->ipv4($token->{'from'})->@*; + + # No need to rewrite $token->{'from'} + $right = 1; + last; } - return $hosts; + while(1) { + # Try to rewrite uninformative hostnames and IP addresses in $token->{'from'} + last if $right; # There is no need to rewrite + last if scalar @$alter == 0; # There is no alternative to rewriting + last if index($alter->[0], $token->{'from'}) > -1; + + if( index($token->{'from'}, 'localhost') == 0 ) { + # localhost or localhost.localdomain + $token->{'from'} = $alter->[0]; + + } elsif( index($token->{'from'}, '.') == -1 ) { + # A hostname without a domain name such as "mail", "mx", or "mbox" + $token->{'from'} = $alter->[0] if index($alter->[0], '.') > 0; + + } else { + # An IPv4 address + $token->{'from'} = $alter->[0]; + } + last; + } + delete $token->{'by'} unless defined $token->{'by'}; + delete $token->{'from'} unless defined $token->{'from'}; + $token->{'from'} =~ y/[]//d; + $token->{'for'} = Sisimai::Address->s3s4($token->{'for'}) if exists $token->{'for'}; + + return [ + $token->{'from'} || '', + $token->{'by'} || '', + $token->{'via'} || '', + $token->{'with'} || '', + $token->{'id'} || '', + $token->{'for'} || '', + ]; } sub part { @@ -203,16 +256,21 @@ Sisimai::RFC5322 provide methods for checking email address. =head2 C)>> -C returns array reference which include host names in the Received header. +C returns array reference including elements in the Received header. - my $v = 'from mx.example.org (c1.example.net [192.0.2.1]) by mx.example.jp'; + my $v = 'from mx.example.org (c1.example.org [192.0.2.1]) by neko.libsisimai.org + with ESMTP id neko20180202nyaan for ; ...'; my $r = Sisimai::RFC5322->received($v); warn Dumper $r; $VAR1 = [ - 'mx.example.org', - 'mx.example.jp' - ]; + 'mx.example.org', + 'neko.libsisimai.org', + '', + 'ESMTP', + 'neko20180202nyaan', + 'michitsuna@nyaan.jp' + ]; =head2 C, I)>> @@ -236,7 +294,7 @@ azumakuniyuki =head1 COPYRIGHT -Copyright (C) 2014-2023 azumakuniyuki, All rights reserved. +Copyright (C) 2014-2024 azumakuniyuki, All rights reserved. =head1 LICENSE diff --git a/t/031-rfc5322.t b/t/031-rfc5322.t index b6995d7c..3de4c966 100644 --- a/t/031-rfc5322.t +++ b/t/031-rfc5322.t @@ -78,14 +78,23 @@ MAKETEST: { ]; for my $e ( @$received00 ) { + # Check each value returned from Sisimai::RFC5322->received + # 0: (from) "hostname" + # 1: (by) "hostname" + # 2: (via) "protocol/tcp" + # 3: (with) "protocol/smtp" + # 4: (id) "queue-id" + # 5: (for) "envelope-to address" my $v = $Package->received($e); - ok length $e, $e; isa_ok $v, 'ARRAY'; ok scalar @$v, 'scalar = '.scalar @$v; - for my $f ( @$v ) { - ok length $f, 'received = '.$f; - ok $f =~ qr{\A[-/:.0-9A-Za-z]+\z}, 'Regular expression'; - } + is scalar @$v, 6; + like $v->[0], qr/\A[^\s\(\)\[\];]+\z/, '->received(from) = '.$v->[0] if length $v->[0]; + like $v->[1], qr/\A[^\s\(\)\[\];]+\z/, '->received(by) = '.$v->[1] if length $v->[1]; + is $v->[2], '', '->received(via) = ""'; + like $v->[3], qr/\A[^\s;]+\z/, '->received(with) = '.$v->[3] if length $v->[3]; + like $v->[4], qr/\A[^\s;]+\z/, '->received(id) = '.$v->[4] if length $v->[4]; + like $v->[5], qr/[^\s;]+[@][^\s;]+/, '->received(for) = '.$v->[5] if length $v->[5]; } my $rfc822body = <<'EOB'; From c7247fa4eb36fc2cb5a41924b9300582c6f1aff0 Mon Sep 17 00:00:00 2001 From: azumakuniyuki Date: Mon, 11 Mar 2024 12:40:17 +0900 Subject: [PATCH 02/25] Fix for the upper case "FROM", or "BY" in the Received header #508 --- lib/Sisimai/RFC5322.pm | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/Sisimai/RFC5322.pm b/lib/Sisimai/RFC5322.pm index 921700c2..cf4ac1c8 100644 --- a/lib/Sisimai/RFC5322.pm +++ b/lib/Sisimai/RFC5322.pm @@ -90,11 +90,12 @@ sub received { # Look up each label defined in $label from Received header last unless ++$index < $range; next unless grep { lc $e eq $_ } @$label; + my $f = lc $e; - $token->{ $e } = $recvd->[$index + 1] || next; - chop $token->{ $e } if index($token->{ $e }, ';') > 1; + $token->{ $f } = $recvd->[$index + 1] || next; + chop $token->{ $f } if index($token->{ $f }, ';') > 1; - next unless $e eq 'from'; + next unless $f eq 'from'; last unless $index + 2 < $range; if( index($recvd->[$index + 2], '(') == 0 ) { From e23510fae3e6a7c0adb8810895a9c32492bed37f Mon Sep 17 00:00:00 2001 From: azumakuniyuki Date: Mon, 11 Mar 2024 13:34:17 +0900 Subject: [PATCH 03/25] Fix code to avoid "Use of uninitialized value in substr" warning #508 --- lib/Sisimai/RFC5322.pm | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/Sisimai/RFC5322.pm b/lib/Sisimai/RFC5322.pm index cf4ac1c8..db7e26be 100644 --- a/lib/Sisimai/RFC5322.pm +++ b/lib/Sisimai/RFC5322.pm @@ -110,6 +110,7 @@ sub received { } else { # The 2nd element after the current element is a continuation of the current element. + last unless $index + 3 < $range; push @$other, substr($recvd->[$index + 3], 0, -1); } } From 3b6916bad8c416defe0d8175896e7a7ce1416cfa Mon Sep 17 00:00:00 2001 From: azumakuniyuki Date: Mon, 11 Mar 2024 13:41:01 +0900 Subject: [PATCH 04/25] Replace "alias" address with the value picked from Received header when the "alias" is the same value with the "recipient" #508 --- lib/Sisimai/Fact.pm | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/lib/Sisimai/Fact.pm b/lib/Sisimai/Fact.pm index 5c576d4f..04735193 100644 --- a/lib/Sisimai/Fact.pm +++ b/lib/Sisimai/Fact.pm @@ -167,9 +167,9 @@ sub rise { # Scan "Received:" header of the original message my $recvheader = $mesg1->{'header'}->{'received'} || []; if( scalar @$recvheader ) { - # Get localhost and remote host name from Received header. - $e->{'lhost'} ||= shift Sisimai::RFC5322->received($recvheader->[0])->@*; - $e->{'rhost'} ||= pop Sisimai::RFC5322->received($recvheader->[-1])->@*; + # Get a local host name and a remote host name from the Received header. + $e->{'lhost'} ||= Sisimai::RFC5322->received($recvheader->[0])->[0]; + $e->{'rhost'} ||= Sisimai::RFC5322->received($recvheader->[-1])->[1]; } for my $v ('rhost', 'lhost') { @@ -307,6 +307,30 @@ sub rise { $o->{'timezoneoffset'} = $p->{'timezoneoffset'} // '+0000'; } + ALIAS: while(1) { + # Look up the Envelope-To address from the Received: header in the original message + # when the recipient address is same with the value of $o->{'alias'}. + last if length $o->{'alias'} == 0; + last if $o->{'recipient'}->address ne $o->{'alias'}; + last unless exists $rfc822data->{'received'}; + last unless scalar $rfc822data->{'received'}->@*; + + for my $er ( reverse $rfc822data->{'received'}->@* ) { + # Search for the string " for " from the Received: header + next unless index($er, ' for ') > 1; + my $or = Sisimai::RFC5322->received($er); + + next unless scalar @$or; + next unless length $or->[5]; + next unless Sisimai::Address->is_emailaddress($or->[5]); + next if $o->{'recipient'}->address eq $or->[5]; + + $o->{'alias'} = $or->[5]; + last; + } + last; + } + REASON: { # Decide the reason of email bounce if( $o->{'reason'} eq '' || exists $retryindex->{ $o->{'reason'} } ) { @@ -729,7 +753,7 @@ azumakuniyuki =head1 COPYRIGHT -Copyright (C) 2014-2022 azumakuniyuki, All rights reserved. +Copyright (C) 2014-2024 azumakuniyuki, All rights reserved. =head1 LICENSE From 6951baa14a45d789397cf128b79b67d3f80214d3 Mon Sep 17 00:00:00 2001 From: azumakuniyuki Date: Mon, 11 Mar 2024 13:41:44 +0900 Subject: [PATCH 05/25] Code improvement at the lines calling Sisimai::RFC5322->received --- lib/Sisimai/Lhost/Exim.pm | 25 ++++++++----------------- lib/Sisimai/Lhost/GoogleGroups.pm | 7 +++---- lib/Sisimai/Lhost/MXLogic.pm | 28 +++++++++------------------- lib/Sisimai/Lhost/MailRu.pm | 27 ++++++++------------------- lib/Sisimai/Lhost/mFILTER.pm | 4 ++-- 5 files changed, 30 insertions(+), 61 deletions(-) diff --git a/lib/Sisimai/Lhost/Exim.pm b/lib/Sisimai/Lhost/Exim.pm index 20404ede..b632be75 100644 --- a/lib/Sisimai/Lhost/Exim.pm +++ b/lib/Sisimai/Lhost/Exim.pm @@ -151,7 +151,6 @@ sub inquire { my $readcursor = 0; # (Integer) Points the current cursor position my $nextcursor = 0; my $recipients = 0; # (Integer) The number of 'Final-Recipient' header - my $localhost0 = ''; # (String) Local MTA my $boundary00 = ''; # (String) Boundary string my $v = undef; @@ -338,17 +337,14 @@ sub inquire { } return undef unless $recipients; - if( scalar $mhead->{'received'}->@* ) { - # Get the name of local MTA - # Received: from marutamachi.example.org (c192128.example.net [192.0.2.128]) - $p1 = index($mhead->{'received'}->[-1], 'from '); - $p2 = index($mhead->{'received'}->[-1], ' ', $p1 + 5); - $localhost0 = substr($mhead->{'received'}->[-1], $p1 + 5, $p2 - $p1 - 5) if $p1 > -1 && $p2 > $p1; - } + # Get the name of the local MTA + # Received: from marutamachi.example.org (c192128.example.net [192.0.2.128]) + my $receivedby = $mhead->{'received'} || []; + my $recvdtoken = Sisimai::RFC5322->received($receivedby->[-1]); for my $e ( @$dscontents ) { # Set default values if each value is empty. - $e->{'lhost'} ||= $localhost0; + $e->{'lhost'} ||= $recvdtoken->[0]; if( ! $e->{'diagnosis'} && length($boundary00) > 0 ) { # Empty Diagnostic-Code: or error message @@ -396,13 +392,8 @@ sub inquire { # host neko.example.jp [192.0.2.222]: 550 5.1.1 ... User Unknown $p1 = index($e->{'diagnosis'}, 'host '); $p2 = index($e->{'diagnosis'}, ' ', $p1 + 5); - $e->{'rhost'} = substr($e->{'diagnosis'}, $p1 + 5, $p2 - $p1 - 5) if $p1 > -1; - - if( ! $e->{'rhost'} && scalar $mhead->{'received'}->@* ) { - # Get localhost and remote host name from Received header. - my $r0 = $mhead->{'received'}; - $e->{'rhost'} = pop Sisimai::RFC5322->received($r0->[-1])->@*; - } + $e->{'rhost'} = substr($e->{'diagnosis'}, $p1 + 5, $p2 - $p1 - 5) if $p1 > -1; + $e->{'rhost'} ||= $recvdtoken->[1]; } unless( $e->{'command'} ) { @@ -539,7 +530,7 @@ azumakuniyuki =head1 COPYRIGHT -Copyright (C) 2014-2023 azumakuniyuki, All rights reserved. +Copyright (C) 2014-2024 azumakuniyuki, All rights reserved. =head1 LICENSE diff --git a/lib/Sisimai/Lhost/GoogleGroups.pm b/lib/Sisimai/Lhost/GoogleGroups.pm index 12dd5929..73f0c12d 100644 --- a/lib/Sisimai/Lhost/GoogleGroups.pm +++ b/lib/Sisimai/Lhost/GoogleGroups.pm @@ -56,10 +56,9 @@ sub inquire { my @entiremesg = split(/\n\n/, $emailparts->[0], 5); pop @entiremesg; my $issuedcode = join(' ', @entiremesg); $issuedcode =~ y/\n/ /; + my $receivedby = $mhead->{'received'} || []; $recordwide->{'diagnosis'} = Sisimai::String->sweep($issuedcode); - - my $serverlist = Sisimai::RFC5322->received($mhead->{'received'}->[0]); - $recordwide->{'rhost'} = shift @$serverlist; + $recordwide->{'rhost'} = Sisimai::RFC5322->received($receivedby->[0])->[1]; for my $e ( split(',', $mhead->{'x-failed-recipients'}) ) { # X-Failed-Recipients: neko@example.jp, nyaan@example.org, ... @@ -115,7 +114,7 @@ azumakuniyuki =head1 COPYRIGHT -Copyright (C) 2020-2023 azumakuniyuki, All rights reserved. +Copyright (C) 2020-2024 azumakuniyuki, All rights reserved. =head1 LICENSE diff --git a/lib/Sisimai/Lhost/MXLogic.pm b/lib/Sisimai/Lhost/MXLogic.pm index 96952f00..62df1aff 100644 --- a/lib/Sisimai/Lhost/MXLogic.pm +++ b/lib/Sisimai/Lhost/MXLogic.pm @@ -80,7 +80,6 @@ sub inquire { my $emailparts = Sisimai::RFC5322->part($mbody, $boundaries); my $readcursor = 0; # (Integer) Points the current cursor position my $recipients = 0; # (Integer) The number of 'Final-Recipient' header - my $localhost0 = ''; # (String) Local MTA my $v = undef; for my $e ( split("\n", $emailparts->[0]) ) { @@ -126,20 +125,14 @@ sub inquire { } return undef unless $recipients; - if( scalar $mhead->{'received'}->@* ) { - # Get the name of local MTA - my $p1 = index(lc $mhead->{'received'}->[-1], 'from '); - my $p2 = index( $mhead->{'received'}->[-1], ' ', $p1 + 5); - - if( ($p1 + 1) * ($p2 + 1) > 0 ) { - # Received: from marutamachi.example.org (c192128.example.net [192.0.2.128]) - $localhost0 = substr($mhead->{'received'}->[-1], $p1 + 5, $p2 - $p1 - 5); - } - } + # Get the name of the local MTA + # Received: from marutamachi.example.org (c192128.example.net [192.0.2.128]) + my $receivedby = $mhead->{'received'} || []; + my $recvdtoken = Sisimai::RFC5322->received($receivedby->[-1]); for my $e ( @$dscontents ) { # Set default values if each value is empty. - $e->{'lhost'} ||= $localhost0; + $e->{'lhost'} ||= $recvdtoken->[0]; $e->{'diagnosis'} =~ s/[-]{2}.*\z//g; $e->{'diagnosis'} = Sisimai::String->sweep($e->{'diagnosis'}); @@ -149,12 +142,9 @@ sub inquire { my $p2 = index($e->{'diagnosis'}, ' ', $p1 + 5); # host neko.example.jp [192.0.2.222]: 550 5.1.1 ... User Unknown - $e->{'rhost'} = substr($e->{'diagnosis'}, $p1 + 5, $p2 - $p1 - 5) if $p1 > -1; - - unless( $e->{'rhost'} ) { - # Get localhost and remote host name from Received header. - $e->{'rhost'} = pop Sisimai::RFC5322->received($mhead->{'received'}->[-1])->@* if scalar $mhead->{'received'}->@*; - } + # Get the remote host name from the error message or the Received header. + $e->{'rhost'} = substr($e->{'diagnosis'}, $p1 + 5, $p2 - $p1 - 5) if $p1 > -1; + $e->{'rhost'} ||= $recvdtoken->[1]; } unless( $e->{'command'} ) { @@ -232,7 +222,7 @@ azumakuniyuki =head1 COPYRIGHT -Copyright (C) 2014-2023 azumakuniyuki, All rights reserved. +Copyright (C) 2014-2024 azumakuniyuki, All rights reserved. =head1 LICENSE diff --git a/lib/Sisimai/Lhost/MailRu.pm b/lib/Sisimai/Lhost/MailRu.pm index d60b3fd9..b7836f57 100644 --- a/lib/Sisimai/Lhost/MailRu.pm +++ b/lib/Sisimai/Lhost/MailRu.pm @@ -69,7 +69,6 @@ sub inquire { my $emailparts = Sisimai::RFC5322->part($mbody, $boundaries); my $readcursor = 0; # (Integer) Points the current cursor position my $recipients = 0; # (Integer) The number of 'Final-Recipient' header - my $localhost0 = ''; # (String) Local MTA my $v = undef; for my $e ( split("\n", $emailparts->[0]) ) { @@ -142,14 +141,11 @@ sub inquire { } return undef unless $recipients; + # Get the name of the local MTA + # Received: from marutamachi.example.org (c192128.example.net [192.0.2.128]) + my $receivedby = $mhead->{'received'} || []; + my $recvdtoken = Sisimai::RFC5322->received($receivedby->[-1]); my $p1 = -1; my $p2 = -1; - if( scalar $mhead->{'received'}->@* ) { - # Get the name of local MTA - # Received: from marutamachi.example.org (c192128.example.net [192.0.2.128]) - $p1 = index($mhead->{'received'}->[-1], 'from '); - $p2 = index($mhead->{'received'}->[-1], ' ', $p1 + 5); - $localhost0 = substr($mhead->{'received'}->[-1], $p1 + 5, $p2 - $p1 - 5) if $p1 > -1; - } for my $e ( @$dscontents ) { if( exists $e->{'alterrors'} && $e->{'alterrors'} ) { @@ -170,17 +166,10 @@ sub inquire { # host neko.example.jp [192.0.2.222]: 550 5.1.1 ... User Unknown $p1 = index($e->{'diagnosis'}, 'host '); $p2 = index($e->{'diagnosis'}, ' ', $p1 + 5); - $e->{'rhost'} = substr($e->{'diagnosis'}, $p1 + 5, $p2 - $p1 - 5) if $p1 > -1; - - unless( $e->{'rhost'} ) { - if( scalar $mhead->{'received'}->@* ) { - # Get localhost and remote host name from Received header. - my $r0 = $mhead->{'received'}; - $e->{'rhost'} = pop Sisimai::RFC5322->received($r0->[-1])->@*; - } - } + $e->{'rhost'} = substr($e->{'diagnosis'}, $p1 + 5, $p2 - $p1 - 5) if $p1 > -1; + $e->{'rhost'} ||= $recvdtoken->[1]; } - $e->{'lhost'} ||= $localhost0; + $e->{'lhost'} ||= $recvdtoken->[0]; unless( $e->{'command'} ) { # Get the SMTP command name for the session @@ -254,7 +243,7 @@ azumakuniyuki =head1 COPYRIGHT -Copyright (C) 2014-2023 azumakuniyuki, All rights reserved. +Copyright (C) 2014-2024 azumakuniyuki, All rights reserved. =head1 LICENSE diff --git a/lib/Sisimai/Lhost/mFILTER.pm b/lib/Sisimai/Lhost/mFILTER.pm index 6b8b8ad9..4f9ddb5a 100644 --- a/lib/Sisimai/Lhost/mFILTER.pm +++ b/lib/Sisimai/Lhost/mFILTER.pm @@ -110,7 +110,7 @@ sub inquire { my $rhosts = Sisimai::RFC5322->received($rheads->[-1]); $e->{'lhost'} ||= shift Sisimai::RFC5322->received($rheads->[0])->@*; - for my $ee ( @$rhosts ) { + for my $ee ( $rhosts->[0], $rhosts->[1] ) { # Avoid "... by m-FILTER" next unless rindex($ee, '.') > -1; $e->{'rhost'} = $ee; @@ -156,7 +156,7 @@ azumakuniyuki =head1 COPYRIGHT -Copyright (C) 2014-2023 azumakuniyuki, All rights reserved. +Copyright (C) 2014-2024 azumakuniyuki, All rights reserved. =head1 LICENSE From 5461502b50aafae4964fc6358c25e423e30a12a8 Mon Sep 17 00:00:00 2001 From: azumakuniyuki Date: Mon, 11 Mar 2024 13:48:18 +0900 Subject: [PATCH 06/25] Update the release notes for v5.0.1p1 --- ChangeLog.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/ChangeLog.md b/ChangeLog.md index c6e1d176..319af244 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -4,6 +4,26 @@ RELEASE NOTES for Perl version of Sisimai - download: "https://metacpan.org/pod/Sisimai" - document: "https://libsisimai.org/" +v5.0.1p1 +--------------------------------------------------------------------------------------------------- +- release: "" +- version: "" +- changes: + - #507 Migrate the CI from TravisCI to GitHub Actions + - Fixed an issue where constant initialization would fail on Perl 5.26 + - `5.7.23` returned from Office365 is an error related to SPF vilation (authfailure) + - #508 Fixed an issue that Sisimai could not get the value of `alias` address correctly when an + email forwarded and bounced + - Update the error message patterns in `Sisimai::Rhost::Mimecast` + - Update the error message patterns in the followings: + - `AuthFailure` + - `Blocked` + - `Expired` + - `MailboxFull` + - `SecurityError` + - `SpamDetected` + - `Suspend` + v5.0.1 --------------------------------------------------------------------------------------------------- - release: "Sun, 3 Mar 2024 17:17:17 +0900 (JST)" From ddd9f59d8b81b87ca34f4397e1e9f8f13dca902c Mon Sep 17 00:00:00 2001 From: azumakuniyuki Date: Mon, 11 Mar 2024 20:54:56 +0900 Subject: [PATCH 07/25] Remove elements including a space character #508 --- lib/Sisimai/RFC5322.pm | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/Sisimai/RFC5322.pm b/lib/Sisimai/RFC5322.pm index db7e26be..97e3b8ef 100644 --- a/lib/Sisimai/RFC5322.pm +++ b/lib/Sisimai/RFC5322.pm @@ -169,10 +169,15 @@ sub received { } last; } + delete $token->{'by'} unless defined $token->{'by'}; delete $token->{'from'} unless defined $token->{'from'}; - $token->{'from'} =~ y/[]//d; - $token->{'for'} = Sisimai::Address->s3s4($token->{'for'}) if exists $token->{'for'}; + $token->{'for'} = Sisimai::Address->s3s4($token->{'for'}) if exists $token->{'for'}; + for my $e ( keys %$token ) { + # Delee an invalid value + $token->{ $e } = '' if index($token->{ $e }, ' ') > -1; + $token->{ $e } =~ y/[]//d; + } return [ $token->{'from'} || '', From e9c1c2f9dc4ccc5004a7713cabd82b621d1e24dd Mon Sep 17 00:00:00 2001 From: azumakuniyuki Date: Mon, 11 Mar 2024 20:56:11 +0900 Subject: [PATCH 08/25] Do not include the Received header including "revoked by uid" or "revoked from network" --- lib/Sisimai/Message.pm | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/lib/Sisimai/Message.pm b/lib/Sisimai/Message.pm index 9d0837c7..f5df9a8b 100644 --- a/lib/Sisimai/Message.pm +++ b/lib/Sisimai/Message.pm @@ -195,17 +195,26 @@ sub makemap { # https://gist.github.com/xtetsuji/b080e1f5551d17242f6415aba8a00239 my $firstpairs = { $$argv0 =~ /^([\w-]+):[ ]*(.*?)\n(?![\s\t])/gms }; my $headermaps = { 'subject' => '' }; - my $recvheader = []; + $headermaps->{ lc $_ } = $firstpairs->{ $_ } for keys %$firstpairs; + my $receivedby = []; - $headermaps->{ lc $_ } = $firstpairs->{ $_ } for keys %$firstpairs; for my $e ( values %$headermaps ) { s/\n\s+/ /, y/\t / /s for $e } if( index($$argv0, "\nReceived:") > 0 || index($$argv0, "Received:") == 0 ) { # Capture values of each Received: header - $recvheader = [$$argv0 =~ /^Received:[ ]*(.*?)\n(?![\s\t])/gms]; - for my $e ( @$recvheader ) { s/\n\s+/ /, y/\n\t / /s for $e } + my $re = [$$argv0 =~ /^Received:[ ]*(.*?)\n(?![\s\t])/gms]; + for my $e ( @$re ) { + # 1. Exclude the Received header including "(qmail ** invoked from network)". + # 2. Convert all consecutive spaces and line breaks into a single space character. + next if index($e, ' invoked by uid') > 0; + next if index($e, ' invoked from network') > 0; + + $e =~ s/\n\s+/ /; + $e =~ y/\n\t / /s; + push @$receivedby, $e; + } } - $headermaps->{'received'} = $recvheader; + $headermaps->{'received'} = $receivedby; return $headermaps unless $argv1; return $headermaps unless length $headermaps->{'subject'}; From 036f433b116a4bc411af8c495a90357fffa9e261 Mon Sep 17 00:00:00 2001 From: azumakuniyuki Date: Mon, 11 Mar 2024 20:56:40 +0900 Subject: [PATCH 09/25] Loose check the value of the "lhost" and "rhost" --- t/600-lhost-code | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/t/600-lhost-code b/t/600-lhost-code index 1a52dfd4..67e62290 100644 --- a/t/600-lhost-code +++ b/t/600-lhost-code @@ -261,7 +261,7 @@ my $moduletest = sub { LHOST: { $cv = $rr->lhost; - $cr = qr/\A[-.0-9A-Za-z]+\z/; + $cr = qr/\A[^\s\[\]\(\)]+\z/; $ct = sprintf("[%s-%02d] ->lhost =", $e, $errorindex); ok defined $cv, sprintf("%s %s", $ct, $cv); @@ -363,7 +363,7 @@ my $moduletest = sub { RHOST: { $cv = $rr->rhost; - $cr = qr/\A[-.:0-9A-Za-z]+\z/; + $cr = qr/\A[^\s\[\]\(\)]+\z/; $ct = sprintf("[%s-%02d] ->rhost =", $e, $errorindex); ok defined $cv, sprintf("%s %s", $ct, $cv); From 1e1456086c396b5fff47ecd02b1b39e1e5c55bf4 Mon Sep 17 00:00:00 2001 From: azumakuniyuki Date: Mon, 11 Mar 2024 21:00:44 +0900 Subject: [PATCH 10/25] Replace the "lhost" value with the hostname picked from Received header when the "lhost" is the same with the "rhost" --- lib/Sisimai/Fact.pm | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/Sisimai/Fact.pm b/lib/Sisimai/Fact.pm index 04735193..16de0d00 100644 --- a/lib/Sisimai/Fact.pm +++ b/lib/Sisimai/Fact.pm @@ -165,11 +165,12 @@ sub rise { OTHER_TEXT_HEADERS: { # Scan "Received:" header of the original message - my $recvheader = $mesg1->{'header'}->{'received'} || []; - if( scalar @$recvheader ) { + my $rr = $mesg1->{'header'}->{'received'} || []; + if( scalar @$rr ) { # Get a local host name and a remote host name from the Received header. - $e->{'lhost'} ||= Sisimai::RFC5322->received($recvheader->[0])->[0]; - $e->{'rhost'} ||= Sisimai::RFC5322->received($recvheader->[-1])->[1]; + $p->{'rhost'} ||= Sisimai::RFC5322->received($rr->[-1])->[1] || ''; + $p->{'lhost'} = '' if $p->{'lhost'} eq $p->{'rhost'}; + $p->{'lhost'} ||= Sisimai::RFC5322->received($rr->[ 0])->[0]; } for my $v ('rhost', 'lhost') { From 4b8cbc8ece4e8d28be24c104ac3359abd9fce5d8 Mon Sep 17 00:00:00 2001 From: azumakuniyuki Date: Tue, 12 Mar 2024 09:16:19 +0900 Subject: [PATCH 11/25] #508 Add a test code for checking the "alias" and "recipient" addresses --- .../maildir/bsd/lhost-sendmail-60.eml | 85 +++++++++++++++++++ t/022-mail-maildir.t | 2 +- t/500-fact.t | 7 ++ t/791-lhost-sendmail.t | 1 + 4 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 set-of-emails/maildir/bsd/lhost-sendmail-60.eml diff --git a/set-of-emails/maildir/bsd/lhost-sendmail-60.eml b/set-of-emails/maildir/bsd/lhost-sendmail-60.eml new file mode 100644 index 00000000..a5ba8d00 --- /dev/null +++ b/set-of-emails/maildir/bsd/lhost-sendmail-60.eml @@ -0,0 +1,85 @@ +Return-Path: <> +X-Original-To: nekochan@email.example.jp +Delivered-To: mail@email.example.jp +Received: from mx311.ume.example.ne.jp (ip-192-0-2-25.us-east-1.compute.internal [192.0.2.25]) + by mx1.email.example.jp (Postfix) with ESMTPS id Ln2ZS7LPwxzW4HMF + for ; Wed, 7 Feb 2024 23:34:45 +0900 (JST) +Received: from localhost (localhost) + by mx311.ume.example.ne.jp (8.16.1/8.16.1) id 3LGub1et091679; + Wed, 7 Feb 2024 23:34:45 +0900 (JST) + (envelope-from MAILER-DAEMON) +Date: Wed, 7 Feb 2024 23:34:45 +0900 (JST) +From: Mail Delivery Subsystem +To: +Message-Id: <202402072222.3LGub1et091679@mx311.ume.example.ne.jp> +MIME-Version: 1.0 +Content-Type: multipart/report; report-type=delivery-status; + boundary="3LGub1et091679.1157497350/mx311.ume.example.ne.jp" +Subject: Returned mail: see transcript for details +Auto-Submitted: auto-generated (failure) + +This is a MIME-encapsulated message + +--3LGub1et091679.1157497350/mx311.ume.example.ne.jp + +The original message was received at Wed, 7 Feb 2024 23:34:45 +0900 (JST) +from localhost [127.0.0.1] + + ----- The following addresses had permanent fatal errors ----- + + (reason: 550-5.7.26 The MAIL FROM domain [email.example.jp] has an SPF record with a hard fail) + + ----- Transcript of session follows ----- +... while talking to gmail-smtp-in.l.google.com.: +>>> DATA +<<< 550-5.7.26 The MAIL FROM domain [email.example.jp] has an SPF record with a hard fail +<<< 550-5.7.26 policy (-all) but it fails to pass SPF checks with the ip: +<<< 550-5.7.26 [203.0.113.22]. To best protect our users from spam and phishing, +<<< 550-5.7.26 the message has been blocked. For instructions on setting up +<<< 550-5.7.26 authentication, go to +<<< 550 5.7.26 https://support.google.com/mail/answer/81126#authentication q2.22 - gsmtp +554 5.0.0 Service unavailable + +--3LGub1et091679.1157497350/mx311.ume.example.ne.jp +Content-Type: message/delivery-status + +Reporting-MTA: dns; mx311.ume.example.ne.jp +Arrival-Date: Wed, 7 Feb 2024 23:34:45 +0900 (JST) + +Final-Recipient: RFC822; kijitora-cat@google.example.com +X-Actual-Recipient: rfc822; kijitora-cat@google.example.com +Action: failed +Status: 5.7.26 +Remote-MTA: DNS; gmail-smtp-in.l.google.com +Diagnostic-Code: SMTP; 550-5.7.26 The MAIL FROM domain [email.example.jp] has an SPF record with a hard fail +Last-Attempt-Date: Wed, 7 Feb 2024 23:34:45 +0900 (JST) + +--3LGub1et091679.1157497350/mx311.ume.example.ne.jp +Content-Type: message/rfc822 + +Return-Path: +Received: from mx311.ume.example.ne.jp (localhost [127.0.0.1]) + by mx311.ume.example.ne.jp (8.16.1/8.16.1) with ESMTP id ujmeV2ZG033926 + for ; Wed, 7 Feb 2024 23:34:45 +0900 (JST) + (envelope-from nekochan@email.example.jp) +Received: (from kijitora@localhost) + by mx311.ume.example.ne.jp (8.16.1/8.16.1/Submit) id BJObadmZ060489 + for kijitora-cat@google.example.com; Wed, 7 Feb 2024 23:34:45 +0900 (JST) + (envelope-from nekochan@email.example.jp) +Received: from relay1.email.example.jp (relay1.email.example.jp [192.168.168.168]) + by mx311.ume.example.ne.jp (8.16.1/8.16.1) with ESMTPS id Mf73VCB9P8z4lM3b + (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NO) + for ; Wed, 7 Feb 2024 23:34:45 +0900 (JST) + (envelope-from nekochan@email.example.jp) +Content-Type: text/plain; charset=us-ascii +Message-Id: <50ad190.20240207.2202@relay1.email.example.jp> +Content-Transfer-Encoding: 7bit +Subject: Nyaan +From: +To: +Date: 7 Feb 2024 23:34:45 +0900 +MIME-Version: 1.0 + +Nyaan? + +--3LGub1et091679.1157497350/mx311.ume.example.ne.jp-- diff --git a/t/022-mail-maildir.t b/t/022-mail-maildir.t index 5179e164..727b0de8 100644 --- a/t/022-mail-maildir.t +++ b/t/022-mail-maildir.t @@ -8,7 +8,7 @@ my $Methods = { 'class' => ['new'], 'object' => ['path', 'dir', 'file', 'size', 'offset', 'handle', 'read'], }; -my $MaildirSize = 525; +my $MaildirSize = 526; my $SampleEmail = './set-of-emails/maildir/bsd'; my $NewInstance = $Package->new($SampleEmail); diff --git a/t/500-fact.t b/t/500-fact.t index 09bd2bb0..1348d1d2 100644 --- a/t/500-fact.t +++ b/t/500-fact.t @@ -150,6 +150,13 @@ MAKETEST: { $ci += 1; } + + # Forwarded and bounced + my $fw = Sisimai->make('set-of-emails/maildir/bsd/lhost-sendmail-60.eml'); + isa_ok $fw, 'ARRAY'; + isa_ok $fw->[0], 'Sisimai::Fact'; + is $fw->[0]->alias, 'neko@libsisimai.org', '->alias = neko@libsisimai.org'; + is $fw->[0]->recipient->address, 'kijitora-cat@google.example.com', '->recipient = kijitora-cat@google.example.com'; } done_testing; diff --git a/t/791-lhost-sendmail.t b/t/791-lhost-sendmail.t index c7851a4e..63733799 100644 --- a/t/791-lhost-sendmail.t +++ b/t/791-lhost-sendmail.t @@ -68,6 +68,7 @@ my $isexpected = { '57' => [['5.7.27', '550', 'notaccept', 1]], '58' => [['5.7.1', '550', 'authfailure', 0]], '59' => [['5.7.1', '550', 'authfailure', 0]], + '60' => [['5.7.26', '550', 'authfailure', 0]], }; $enginetest->($enginename, $isexpected); From 78cb14aea705a2a766ac7b52bc115356e25f4f3e Mon Sep 17 00:00:00 2001 From: azumakuniyuki Date: Tue, 12 Mar 2024 13:40:08 +0900 Subject: [PATCH 12/25] Do not copy the "rhost" value to the "lhost" value --- lib/Sisimai/Lhost/AmazonSES.pm | 5 ++--- lib/Sisimai/Lhost/AmazonWorkMail.pm | 3 +-- lib/Sisimai/Lhost/Aol.pm | 3 +-- lib/Sisimai/Lhost/Bigfoot.pm | 3 +-- lib/Sisimai/Lhost/Domino.pm | 3 +-- lib/Sisimai/Lhost/Facebook.pm | 3 +-- lib/Sisimai/Lhost/GSuite.pm | 3 +-- lib/Sisimai/Lhost/MessageLabs.pm | 3 +-- lib/Sisimai/Lhost/Outlook.pm | 5 ++--- lib/Sisimai/Lhost/Postfix.pm | 3 +-- lib/Sisimai/Lhost/ReceivingSES.pm | 3 +-- lib/Sisimai/Lhost/SendGrid.pm | 5 ++--- lib/Sisimai/Lhost/Sendmail.pm | 5 ++--- lib/Sisimai/Lhost/Yandex.pm | 3 +-- 14 files changed, 18 insertions(+), 32 deletions(-) diff --git a/lib/Sisimai/Lhost/AmazonSES.pm b/lib/Sisimai/Lhost/AmazonSES.pm index 7c74fef1..1f124e14 100644 --- a/lib/Sisimai/Lhost/AmazonSES.pm +++ b/lib/Sisimai/Lhost/AmazonSES.pm @@ -288,8 +288,7 @@ sub inquire { for my $e ( @$dscontents ) { # Set default values if each value is empty. - $e->{'lhost'} ||= $permessage->{'rhost'}; - $e->{ $_ } ||= $permessage->{ $_ } || '' for keys %$permessage; + $e->{ $_ } ||= $permessage->{ $_ } || '' for keys %$permessage; $e->{'diagnosis'} =~ y/\n/ /; $e->{'diagnosis'} = Sisimai::String->sweep($e->{'diagnosis'}); @@ -358,7 +357,7 @@ azumakuniyuki =head1 COPYRIGHT -Copyright (C) 2014-2023 azumakuniyuki, All rights reserved. +Copyright (C) 2014-2024 azumakuniyuki, All rights reserved. =head1 LICENSE diff --git a/lib/Sisimai/Lhost/AmazonWorkMail.pm b/lib/Sisimai/Lhost/AmazonWorkMail.pm index 1fb63d4a..cc9e9e50 100644 --- a/lib/Sisimai/Lhost/AmazonWorkMail.pm +++ b/lib/Sisimai/Lhost/AmazonWorkMail.pm @@ -100,7 +100,6 @@ sub inquire { for my $e ( @$dscontents ) { # Set default values if each value is empty. - $e->{'lhost'} ||= $permessage->{'rhost'}; $e->{ $_ } ||= $permessage->{ $_ } || '' for keys %$permessage; $e->{'diagnosis'} = Sisimai::String->sweep($e->{'diagnosis'}); @@ -155,7 +154,7 @@ azumakuniyuki =head1 COPYRIGHT -Copyright (C) 2016-2021,2023 azumakuniyuki, All rights reserved. +Copyright (C) 2016-2021,2023,2024 azumakuniyuki, All rights reserved. =head1 LICENSE diff --git a/lib/Sisimai/Lhost/Aol.pm b/lib/Sisimai/Lhost/Aol.pm index af9608f3..acec5ae7 100644 --- a/lib/Sisimai/Lhost/Aol.pm +++ b/lib/Sisimai/Lhost/Aol.pm @@ -106,7 +106,6 @@ sub inquire { for my $e ( @$dscontents ) { # Set default values if each value is empty. - $e->{'lhost'} ||= $permessage->{'rhost'}; $e->{ $_ } ||= $permessage->{ $_ } || '' for keys %$permessage; $e->{'diagnosis'} =~ y/\n/ /; @@ -158,7 +157,7 @@ azumakuniyuki =head1 COPYRIGHT -Copyright (C) 2014-2023 azumakuniyuki, All rights reserved. +Copyright (C) 2014-2024 azumakuniyuki, All rights reserved. =head1 LICENSE diff --git a/lib/Sisimai/Lhost/Bigfoot.pm b/lib/Sisimai/Lhost/Bigfoot.pm index 91ff3a0d..26f04711 100644 --- a/lib/Sisimai/Lhost/Bigfoot.pm +++ b/lib/Sisimai/Lhost/Bigfoot.pm @@ -113,7 +113,6 @@ sub inquire { for my $e ( @$dscontents ) { # Set default values if each value is empty. - $e->{'lhost'} ||= $permessage->{'rhost'}; $e->{ $_ } ||= $permessage->{ $_ } || '' for keys %$permessage; $e->{'diagnosis'} = Sisimai::String->sweep($e->{'diagnosis'}); @@ -160,7 +159,7 @@ azumakuniyuki =head1 COPYRIGHT -Copyright (C) 2014-2023 azumakuniyuki, All rights reserved. +Copyright (C) 2014-2024 azumakuniyuki, All rights reserved. =head1 LICENSE diff --git a/lib/Sisimai/Lhost/Domino.pm b/lib/Sisimai/Lhost/Domino.pm index 8203903f..b5922f66 100644 --- a/lib/Sisimai/Lhost/Domino.pm +++ b/lib/Sisimai/Lhost/Domino.pm @@ -146,7 +146,6 @@ sub inquire { $e->{'diagnosis'} = Sisimai::String->sweep($e->{'diagnosis'}); $e->{'recipient'} = Sisimai::Address->s3s4($e->{'recipient'}); - $e->{'lhost'} ||= $permessage->{'rhost'}; $e->{ $_ } ||= $permessage->{ $_ } || '' for keys %$permessage; for my $r ( keys %$messagesof ) { @@ -201,7 +200,7 @@ azumakuniyuki =head1 COPYRIGHT -Copyright (C) 2014-2023 azumakuniyuki, All rights reserved. +Copyright (C) 2014-2024 azumakuniyuki, All rights reserved. =head1 LICENSE diff --git a/lib/Sisimai/Lhost/Facebook.pm b/lib/Sisimai/Lhost/Facebook.pm index 54a46ca7..47de5691 100644 --- a/lib/Sisimai/Lhost/Facebook.pm +++ b/lib/Sisimai/Lhost/Facebook.pm @@ -155,7 +155,6 @@ sub inquire { return undef unless $recipients; for my $e ( @$dscontents ) { - $e->{'lhost'} ||= $permessage->{'lhost'}; $e->{'diagnosis'} = Sisimai::String->sweep($e->{'diagnosis'}); my $p0 = index($e->{'diagnosis'}, '-'); @@ -226,7 +225,7 @@ azumakuniyuki =head1 COPYRIGHT -Copyright (C) 2014-2023 azumakuniyuki, All rights reserved. +Copyright (C) 2014-2024 azumakuniyuki, All rights reserved. =head1 LICENSE diff --git a/lib/Sisimai/Lhost/GSuite.pm b/lib/Sisimai/Lhost/GSuite.pm index 8660a130..739701fc 100644 --- a/lib/Sisimai/Lhost/GSuite.pm +++ b/lib/Sisimai/Lhost/GSuite.pm @@ -140,7 +140,6 @@ sub inquire { for my $e ( @$dscontents ) { # Set default values if each value is empty. - $e->{'lhost'} ||= $permessage->{'rhost'}; $e->{ $_ } ||= $permessage->{ $_ } || '' for keys %$permessage; if( exists $anotherset->{'diagnosis'} && $anotherset->{'diagnosis'} ) { @@ -228,7 +227,7 @@ azumakuniyuki =head1 COPYRIGHT -Copyright (C) 2017-2023 azumakuniyuki, All rights reserved. +Copyright (C) 2017-2024 azumakuniyuki, All rights reserved. =head1 LICENSE diff --git a/lib/Sisimai/Lhost/MessageLabs.pm b/lib/Sisimai/Lhost/MessageLabs.pm index 06038349..6d1b1d7e 100644 --- a/lib/Sisimai/Lhost/MessageLabs.pm +++ b/lib/Sisimai/Lhost/MessageLabs.pm @@ -102,7 +102,6 @@ sub inquire { for my $e ( @$dscontents ) { # Set default values if each value is empty. - $e->{'lhost'} ||= $permessage->{'rhost'}; $e->{ $_ } ||= $permessage->{ $_ } || '' for keys %$permessage; $e->{'diagnosis'} = Sisimai::String->sweep($e->{'diagnosis'}); @@ -153,7 +152,7 @@ azumakuniyuki =head1 COPYRIGHT -Copyright (C) 2014-2021,2023 azumakuniyuki, All rights reserved. +Copyright (C) 2014-2021,2023,2024 azumakuniyuki, All rights reserved. =head1 LICENSE diff --git a/lib/Sisimai/Lhost/Outlook.pm b/lib/Sisimai/Lhost/Outlook.pm index a520a668..96943006 100644 --- a/lib/Sisimai/Lhost/Outlook.pm +++ b/lib/Sisimai/Lhost/Outlook.pm @@ -102,8 +102,7 @@ sub inquire { for my $e ( @$dscontents ) { # Set default values if each value is empty. - $e->{'lhost'} ||= $permessage->{'rhost'}; - $e->{ $_ } ||= $permessage->{ $_ } || '' for keys %$permessage; + $e->{ $_ } ||= $permessage->{ $_ } || '' for keys %$permessage; $e->{'diagnosis'} = Sisimai::String->sweep($e->{'diagnosis'}); unless( $e->{'diagnosis'} ) { @@ -166,7 +165,7 @@ azumakuniyuki =head1 COPYRIGHT -Copyright (C) 2014-2023 azumakuniyuki, All rights reserved. +Copyright (C) 2014-2024 azumakuniyuki, All rights reserved. =head1 LICENSE diff --git a/lib/Sisimai/Lhost/Postfix.pm b/lib/Sisimai/Lhost/Postfix.pm index bbc08e55..a07211ce 100644 --- a/lib/Sisimai/Lhost/Postfix.pm +++ b/lib/Sisimai/Lhost/Postfix.pm @@ -232,7 +232,6 @@ sub inquire { for my $e ( @$dscontents ) { # Set default values if each value is empty. - $e->{'lhost'} ||= $permessage->{'rhost'}; $e->{ $_ } ||= $permessage->{ $_ } || '' for keys %$permessage; if( $anotherset->{'diagnosis'} ) { @@ -324,7 +323,7 @@ azumakuniyuki =head1 COPYRIGHT -Copyright (C) 2014-2023 azumakuniyuki, All rights reserved. +Copyright (C) 2014-2024 azumakuniyuki, All rights reserved. =head1 LICENSE diff --git a/lib/Sisimai/Lhost/ReceivingSES.pm b/lib/Sisimai/Lhost/ReceivingSES.pm index a9c80487..f5b762d7 100644 --- a/lib/Sisimai/Lhost/ReceivingSES.pm +++ b/lib/Sisimai/Lhost/ReceivingSES.pm @@ -101,7 +101,6 @@ sub inquire { for my $e ( @$dscontents ) { # Set default values if each value is empty. - $e->{'lhost'} ||= $permessage->{'rhost'}; $e->{ $_ } ||= $permessage->{ $_ } || '' for keys %$permessage; $e->{'diagnosis'} =~ y/\n/ /; $e->{'diagnosis'} = Sisimai::String->sweep($e->{'diagnosis'}); @@ -164,7 +163,7 @@ azumakuniyuki =head1 COPYRIGHT -Copyright (C) 2015-2023 azumakuniyuki, All rights reserved. +Copyright (C) 2015-2024 azumakuniyuki, All rights reserved. =head1 LICENSE diff --git a/lib/Sisimai/Lhost/SendGrid.pm b/lib/Sisimai/Lhost/SendGrid.pm index 85370773..5f9f191d 100644 --- a/lib/Sisimai/Lhost/SendGrid.pm +++ b/lib/Sisimai/Lhost/SendGrid.pm @@ -148,6 +148,7 @@ sub inquire { $e->{'diagnosis'} = Sisimai::String->sweep($e->{'diagnosis'}); $e->{'replycode'} = Sisimai::SMTP::Reply->find($e->{'diagnosis'}) || ''; $e->{'status'} = substr($e->{'replycode'}, 0, 1).'.0.0' if length $e->{'replycode'} == 3; + $e->{'command'} ||= $thecommand; if( $e->{'status'} eq '5.0.0' || $e->{'status'} eq '4.0.0' ) { # Get the value of D.S.N. from the error message or the value of Diagnostic-Code header. @@ -162,8 +163,6 @@ sub inquire { $e->{'status'} = Sisimai::SMTP::Status->code('expired') || $e->{'status'}; } } - $e->{'lhost'} ||= $permessage->{'rhost'}; - $e->{'command'} ||= $thecommand; } return { 'ds' => $dscontents, 'rfc822' => $emailparts->[1] }; } @@ -205,7 +204,7 @@ azumakuniyuki =head1 COPYRIGHT -Copyright (C) 2014-2023 azumakuniyuki, All rights reserved. +Copyright (C) 2014-2024 azumakuniyuki, All rights reserved. =head1 LICENSE diff --git a/lib/Sisimai/Lhost/Sendmail.pm b/lib/Sisimai/Lhost/Sendmail.pm index ffd9908d..93fb9f30 100644 --- a/lib/Sisimai/Lhost/Sendmail.pm +++ b/lib/Sisimai/Lhost/Sendmail.pm @@ -168,8 +168,7 @@ sub inquire { for my $e ( @$dscontents ) { # Set default values if each value is empty. - $e->{'lhost'} ||= $permessage->{'rhost'}; - $e->{ $_ } ||= $permessage->{ $_ } || '' for keys %$permessage; + $e->{ $_ } ||= $permessage->{ $_ } || '' for keys %$permessage; if( exists $anotherset->{'diagnosis'} && $anotherset->{'diagnosis'} ) { # Copy alternative error message @@ -247,7 +246,7 @@ azumakuniyuki =head1 COPYRIGHT -Copyright (C) 2014-2023 azumakuniyuki, All rights reserved. +Copyright (C) 2014-2024 azumakuniyuki, All rights reserved. =head1 LICENSE diff --git a/lib/Sisimai/Lhost/Yandex.pm b/lib/Sisimai/Lhost/Yandex.pm index e489c5d9..810ba4ad 100644 --- a/lib/Sisimai/Lhost/Yandex.pm +++ b/lib/Sisimai/Lhost/Yandex.pm @@ -112,7 +112,6 @@ sub inquire { for my $e ( @$dscontents ) { # Set default values if each value is empty. - $e->{'lhost'} ||= $permessage->{'rhost'}; $e->{ $_ } ||= $permessage->{ $_ } || '' for keys %$permessage; $e->{'diagnosis'} =~ y/\n/ /; $e->{'diagnosis'} = Sisimai::String->sweep($e->{'diagnosis'}); @@ -158,7 +157,7 @@ azumakuniyuki =head1 COPYRIGHT -Copyright (C) 2014-2021,2023 azumakuniyuki, All rights reserved. +Copyright (C) 2014-2021,2023,2024 azumakuniyuki, All rights reserved. =head1 LICENSE From fb518e2aae6e35b852d2110094f19af1f3e5eced Mon Sep 17 00:00:00 2001 From: azumakuniyuki Date: Tue, 12 Mar 2024 13:58:16 +0900 Subject: [PATCH 13/25] Update comments --- lib/Sisimai/Fact.pm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/Sisimai/Fact.pm b/lib/Sisimai/Fact.pm index 16de0d00..6c356575 100644 --- a/lib/Sisimai/Fact.pm +++ b/lib/Sisimai/Fact.pm @@ -176,10 +176,10 @@ sub rise { for my $v ('rhost', 'lhost') { # Check and rewrite each host name $p->{ $v } = [split('@', $p->{ $v })]->[-1] if index($p->{ $v }, '@') > -1; - y/[]()//d, s/\A.+=// for $p->{ $v }; # Remove [] and (), and strings before "=" + y/[]()//d, s/\A.+=// for $p->{ $v }; # Remove [], (), and strings before "=" chop $p->{ $v } if substr($p->{ $v }, -1, 1) eq "\r"; # Remove CR at the end of the value - # Check space character in each value and get the first element + # Check a space character in each value and get the first element $p->{ $v } = (split(' ', $p->{ $v }, 2))[0] if rindex($p->{ $v }, ' ') > -1; chop $p->{ $v } if substr($p->{ $v }, -1, 1) eq '.'; # Remove "." at the end of the value } From 28e560ad15dda800e56e575f81b222809bea32b8 Mon Sep 17 00:00:00 2001 From: azumakuniyuki Date: Tue, 12 Mar 2024 14:34:19 +0900 Subject: [PATCH 14/25] Sisimai->make method is deprecated at v5.0.0 --- t/500-fact.t | 2 +- t/800-cannot-parse-yet.t | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/t/500-fact.t b/t/500-fact.t index 1348d1d2..962534c0 100644 --- a/t/500-fact.t +++ b/t/500-fact.t @@ -152,7 +152,7 @@ MAKETEST: { } # Forwarded and bounced - my $fw = Sisimai->make('set-of-emails/maildir/bsd/lhost-sendmail-60.eml'); + my $fw = Sisimai->rise('set-of-emails/maildir/bsd/lhost-sendmail-60.eml'); isa_ok $fw, 'ARRAY'; isa_ok $fw->[0], 'Sisimai::Fact'; is $fw->[0]->alias, 'neko@libsisimai.org', '->alias = neko@libsisimai.org'; diff --git a/t/800-cannot-parse-yet.t b/t/800-cannot-parse-yet.t index 33677d42..69d1f0c2 100644 --- a/t/800-cannot-parse-yet.t +++ b/t/800-cannot-parse-yet.t @@ -8,8 +8,8 @@ plan 'skip_all', sprintf("%s does not exist", $CannotParse) unless -d $CannotPar MAKETEST: { SISIMAI: { use Sisimai; - my $v = Sisimai->make($CannotParse); - is $v, undef, 'Sisimai->make() returns undef'; + my $v = Sisimai->rise($CannotParse); + is $v, undef, 'Sisimai->rise() returns undef'; } MAILDIR: { From 82f9f2a8f75852b5c6b8d9ddc578337280a25a0b Mon Sep 17 00:00:00 2001 From: azumakuniyuki Date: Tue, 12 Mar 2024 15:13:35 +0900 Subject: [PATCH 15/25] Tiny code improvement: use a Hash key in the loop --- lib/Sisimai/RFC5322.pm | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/Sisimai/RFC5322.pm b/lib/Sisimai/RFC5322.pm index 97e3b8ef..785ffbbb 100644 --- a/lib/Sisimai/RFC5322.pm +++ b/lib/Sisimai/RFC5322.pm @@ -129,12 +129,12 @@ sub received { push @$alter, $e; } - for my $e ($token->{'from'}, $token->{'by'}) { + for my $e ('from', 'by') { # Remove square brackets from the IP address such as "[192.0.2.25]" - next unless defined $e; - next unless length $e; - next unless index($e, '[') == 0; - $e = shift Sisimai::String->ipv4($e)->@* || ''; + next unless defined $token->{ $e }; + next unless length $token->{ $e }; + next unless index($token->{ $e }, '[') == 0; + $token->{ $e } = shift Sisimai::String->ipv4($token->{ $e })->@* || ''; } $token->{'from'} ||= ''; From 37089efa637eaef8f48189acdc3d9df1198134d6 Mon Sep 17 00:00:00 2001 From: azumakuniyuki Date: Tue, 12 Mar 2024 15:43:30 +0900 Subject: [PATCH 16/25] It is possible that the Received header will include "LOCALHOST.LOCALDOMAIN". --- lib/Sisimai/RFC5322.pm | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/Sisimai/RFC5322.pm b/lib/Sisimai/RFC5322.pm index 785ffbbb..67c25b2c 100644 --- a/lib/Sisimai/RFC5322.pm +++ b/lib/Sisimai/RFC5322.pm @@ -93,6 +93,7 @@ sub received { my $f = lc $e; $token->{ $f } = $recvd->[$index + 1] || next; + $token->{ $f } = lc $token->{ $f }; chop $token->{ $f } if index($token->{ $f }, ';') > 1; next unless $f eq 'from'; From e2674b1d0a90533f6400974721501012cb0d4375 Mon Sep 17 00:00:00 2001 From: azumakuniyuki Date: Tue, 12 Mar 2024 16:11:14 +0900 Subject: [PATCH 17/25] Fix comment(delee => delete) --- lib/Sisimai/RFC5322.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Sisimai/RFC5322.pm b/lib/Sisimai/RFC5322.pm index 67c25b2c..555525d6 100644 --- a/lib/Sisimai/RFC5322.pm +++ b/lib/Sisimai/RFC5322.pm @@ -175,7 +175,7 @@ sub received { delete $token->{'from'} unless defined $token->{'from'}; $token->{'for'} = Sisimai::Address->s3s4($token->{'for'}) if exists $token->{'for'}; for my $e ( keys %$token ) { - # Delee an invalid value + # Delete an invalid value $token->{ $e } = '' if index($token->{ $e }, ' ') > -1; $token->{ $e } =~ y/[]//d; } From e5186429cd5a4dd7a7cf8a00b267108b241b055d Mon Sep 17 00:00:00 2001 From: azumakuniyuki Date: Tue, 12 Mar 2024 19:00:53 +0900 Subject: [PATCH 18/25] Improved comments in each loop block --- lib/Sisimai/Lhost/Exim.pm | 5 ++--- lib/Sisimai/Lhost/MXLogic.pm | 4 ++-- lib/Sisimai/Lhost/MailRu.pm | 1 + 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/Sisimai/Lhost/Exim.pm b/lib/Sisimai/Lhost/Exim.pm index b632be75..cc070493 100644 --- a/lib/Sisimai/Lhost/Exim.pm +++ b/lib/Sisimai/Lhost/Exim.pm @@ -343,9 +343,7 @@ sub inquire { my $recvdtoken = Sisimai::RFC5322->received($receivedby->[-1]); for my $e ( @$dscontents ) { - # Set default values if each value is empty. - $e->{'lhost'} ||= $recvdtoken->[0]; - + # Check the error message, the rhost, the lhost, and the smtp command. if( ! $e->{'diagnosis'} && length($boundary00) > 0 ) { # Empty Diagnostic-Code: or error message # --NNNNNNNNNN-eximdsn-MMMMMMMMMM @@ -395,6 +393,7 @@ sub inquire { $e->{'rhost'} = substr($e->{'diagnosis'}, $p1 + 5, $p2 - $p1 - 5) if $p1 > -1; $e->{'rhost'} ||= $recvdtoken->[1]; } + $e->{'lhost'} ||= $recvdtoken->[0]; unless( $e->{'command'} ) { # Get the SMTP command name for the session diff --git a/lib/Sisimai/Lhost/MXLogic.pm b/lib/Sisimai/Lhost/MXLogic.pm index 62df1aff..3584ca6d 100644 --- a/lib/Sisimai/Lhost/MXLogic.pm +++ b/lib/Sisimai/Lhost/MXLogic.pm @@ -131,8 +131,7 @@ sub inquire { my $recvdtoken = Sisimai::RFC5322->received($receivedby->[-1]); for my $e ( @$dscontents ) { - # Set default values if each value is empty. - $e->{'lhost'} ||= $recvdtoken->[0]; + # Check the error message, the rhost, the lhost, and the smtp command. $e->{'diagnosis'} =~ s/[-]{2}.*\z//g; $e->{'diagnosis'} = Sisimai::String->sweep($e->{'diagnosis'}); @@ -146,6 +145,7 @@ sub inquire { $e->{'rhost'} = substr($e->{'diagnosis'}, $p1 + 5, $p2 - $p1 - 5) if $p1 > -1; $e->{'rhost'} ||= $recvdtoken->[1]; } + $e->{'lhost'} ||= $recvdtoken->[0]; unless( $e->{'command'} ) { # Get the SMTP command name for the session diff --git a/lib/Sisimai/Lhost/MailRu.pm b/lib/Sisimai/Lhost/MailRu.pm index b7836f57..97623670 100644 --- a/lib/Sisimai/Lhost/MailRu.pm +++ b/lib/Sisimai/Lhost/MailRu.pm @@ -148,6 +148,7 @@ sub inquire { my $p1 = -1; my $p2 = -1; for my $e ( @$dscontents ) { + # Check the error message, the rhost, the lhost, and the smtp command. if( exists $e->{'alterrors'} && $e->{'alterrors'} ) { # Copy alternative error message $e->{'diagnosis'} ||= $e->{'alterrors'}; From 494fb579093adc5e48024c6cdf28d502a8e2c56d Mon Sep 17 00:00:00 2001 From: azumakuniyuki Date: Tue, 12 Mar 2024 20:46:46 +0900 Subject: [PATCH 19/25] Delete the value of the "alias" when the "recipient" is equal to the "alias" #508 --- lib/Sisimai/Fact.pm | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/Sisimai/Fact.pm b/lib/Sisimai/Fact.pm index 6c356575..d5fd913c 100644 --- a/lib/Sisimai/Fact.pm +++ b/lib/Sisimai/Fact.pm @@ -331,6 +331,7 @@ sub rise { } last; } + $o->{'alias'} = '' if $o->{'alias'} eq $o->{'recipient'}->{'address'}; REASON: { # Decide the reason of email bounce From 05ed695f258326cd9d2e0c8f1cf98c62cc623fdd Mon Sep 17 00:00:00 2001 From: azumakuniyuki Date: Tue, 12 Mar 2024 20:47:21 +0900 Subject: [PATCH 20/25] The "alias" should not be equal to the "recipient" #508 --- t/600-lhost-code | 1 + 1 file changed, 1 insertion(+) diff --git a/t/600-lhost-code b/t/600-lhost-code index 67e62290..354cf5dd 100644 --- a/t/600-lhost-code +++ b/t/600-lhost-code @@ -174,6 +174,7 @@ my $moduletest = sub { $ct = sprintf("[%s-%02d] ->alias =", $e, $errorindex); ok defined $cv, sprintf("%s %s", $ct, $cv); + ok $cv ne $rr->recipient->address, sprintf("%s %s != %s", $ct, $cv, $rr->recipient->address); } CATCH: { From 0c8355ad5e0f3c1540ab910848bed78562bbe15f Mon Sep 17 00:00:00 2001 From: azumakuniyuki Date: Wed, 13 Mar 2024 10:33:48 +0900 Subject: [PATCH 21/25] Bug fix and tiny code refactoring #508 --- lib/Sisimai/RFC5322.pm | 48 ++++++++++++++++++++++++------------------ 1 file changed, 28 insertions(+), 20 deletions(-) diff --git a/lib/Sisimai/RFC5322.pm b/lib/Sisimai/RFC5322.pm index 555525d6..142657e2 100644 --- a/lib/Sisimai/RFC5322.pm +++ b/lib/Sisimai/RFC5322.pm @@ -92,29 +92,37 @@ sub received { next unless grep { lc $e eq $_ } @$label; my $f = lc $e; - $token->{ $f } = $recvd->[$index + 1] || next; - $token->{ $f } = lc $token->{ $f }; - chop $token->{ $f } if index($token->{ $f }, ';') > 1; + $token->{ $f } = $recvd->[$index + 1] || next; + $token->{ $f } = lc $token->{ $f }; + $token->{ $f } =~ y/();//d; next unless $f eq 'from'; last unless $index + 2 < $range; - - if( index($recvd->[$index + 2], '(') == 0 ) { - # Get and keep a hostname in the comment as follows: - # from mx1.example.com (c213502.kyoto.example.ne.jp [192.0.2.135]) by mx.example.jp (V8/cf) - push @$other, substr($recvd->[$index + 2], 1,); - - if( index($other->[0], ')') > 1 ) { - # The 2nd element after the current element is NOT a continuation of the current element. - chop $other->[0]; - next; - - } else { - # The 2nd element after the current element is a continuation of the current element. - last unless $index + 3 < $range; - push @$other, substr($recvd->[$index + 3], 0, -1); - } - } + next unless index($recvd->[$index + 2], '(') == 0; + + # Get and keep a hostname in the comment as follows: + # from mx1.example.com (c213502.kyoto.example.ne.jp [192.0.2.135]) by mx.example.jp (V8/cf) + # [ + # "from", # index + 0 + # "mx1.example.com", # index + 1 + # "(c213502.kyoto.example.ne.jp", # index + 2 + # "[192.0.2.135])", # index + 3 + # "by", + # "mx.example.jp", + # "(V8/cf)", + # ... + # ] + push @$other, $recvd->[$index + 2]; + + # The 2nd element after the current element is NOT a continuation of the current element + # such as "(c213502.kyoto.example.ne.jp)" + $other->[0] =~ y/();//d; + + # The 2nd element after the current element is a continuation of the current element. + # such as "(c213502.kyoto.example.ne.jp", "[192.0.2.135])" + last unless $index + 3 < $range; + push @$other, $recvd->[$index + 3]; + $other->[1] =~ y/();//d; } for my $e ( @$other ) { From 56bd1c430551207a83df813dde32090306634aa8 Mon Sep 17 00:00:00 2001 From: azumakuniyuki Date: Wed, 13 Mar 2024 10:41:07 +0900 Subject: [PATCH 22/25] Add a comment to "y/[]//d" --- lib/Sisimai/RFC5322.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Sisimai/RFC5322.pm b/lib/Sisimai/RFC5322.pm index 142657e2..b74bfb88 100644 --- a/lib/Sisimai/RFC5322.pm +++ b/lib/Sisimai/RFC5322.pm @@ -185,7 +185,7 @@ sub received { for my $e ( keys %$token ) { # Delete an invalid value $token->{ $e } = '' if index($token->{ $e }, ' ') > -1; - $token->{ $e } =~ y/[]//d; + $token->{ $e } =~ y/[]//d; # Remove "[]" from the IP address } return [ From 556458c0a18efe64191a92ea8c4c5eec52fe1ff6 Mon Sep 17 00:00:00 2001 From: azumakuniyuki Date: Wed, 13 Mar 2024 11:05:19 +0900 Subject: [PATCH 23/25] Tiny code improvement #508 --- lib/Sisimai/RFC5322.pm | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/lib/Sisimai/RFC5322.pm b/lib/Sisimai/RFC5322.pm index b74bfb88..9e94f5c7 100644 --- a/lib/Sisimai/RFC5322.pm +++ b/lib/Sisimai/RFC5322.pm @@ -88,12 +88,10 @@ sub received { for my $e ( @$recvd ) { # Look up each label defined in $label from Received header - last unless ++$index < $range; - next unless grep { lc $e eq $_ } @$label; - my $f = lc $e; + last unless ++$index < $range; my $f = lc $e; + next unless grep { $f eq $_ } @$label; - $token->{ $f } = $recvd->[$index + 1] || next; - $token->{ $f } = lc $token->{ $f }; + $token->{ $f } = lc $recvd->[$index + 1] || next; $token->{ $f } =~ y/();//d; next unless $f eq 'from'; From ddb075713ac1fbe080b4c83820c0ed9685974f3a Mon Sep 17 00:00:00 2001 From: azumakuniyuki Date: Wed, 13 Mar 2024 12:14:14 +0900 Subject: [PATCH 24/25] Tiny code improvement, again --- lib/Sisimai/RFC5322.pm | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/Sisimai/RFC5322.pm b/lib/Sisimai/RFC5322.pm index 9e94f5c7..9d7fc5ed 100644 --- a/lib/Sisimai/RFC5322.pm +++ b/lib/Sisimai/RFC5322.pm @@ -110,11 +110,9 @@ sub received { # "(V8/cf)", # ... # ] - push @$other, $recvd->[$index + 2]; - # The 2nd element after the current element is NOT a continuation of the current element # such as "(c213502.kyoto.example.ne.jp)" - $other->[0] =~ y/();//d; + push @$other, $recvd->[$index + 2]; $other->[0] =~ y/();//d; # The 2nd element after the current element is a continuation of the current element. # such as "(c213502.kyoto.example.ne.jp", "[192.0.2.135])" From dcbcf4b8342408c0d988a5a4698e006b82e4b486 Mon Sep 17 00:00:00 2001 From: azumakuniyuki Date: Wed, 13 Mar 2024 12:32:37 +0900 Subject: [PATCH 25/25] Update the release notes about commit 6b14f174d6a0addf8d1dcd0ca8c4a2ceeb48a989 --- ChangeLog.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ChangeLog.md b/ChangeLog.md index 319af244..1c70d7cf 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -14,6 +14,8 @@ v5.0.1p1 - `5.7.23` returned from Office365 is an error related to SPF vilation (authfailure) - #508 Fixed an issue that Sisimai could not get the value of `alias` address correctly when an email forwarded and bounced + - `Sisimai::RFC5322->received` now returns a list including all the elements except date time and + (comments) found in the `Received` header - Update the error message patterns in `Sisimai::Rhost::Mimecast` - Update the error message patterns in the followings: - `AuthFailure`