Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Go sisimai compatibility 7e91 #570

Merged
merged 25 commits into from
Feb 9, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
b51a4d1
Reporting-MTA: should be dealt as "lhost"
azumakuniyuki Jan 3, 2025
f9a3380
A hostname should be checked by Sisimai::RFC1123->is_internethost() s…
azumakuniyuki Jan 3, 2025
f0a42b7
lhost-amazonses/1024 is "userunknown"
azumakuniyuki Jan 3, 2025
cef39c6
Check the error message generated by Dovecot strictly
azumakuniyuki Jan 3, 2025
77c80d2
Enable 2 private samples: 1004, 1005 in lhost-apachejames
azumakuniyuki Jan 3, 2025
43a2bde
Checks 2nd or more bounce records in private/lhost-exim/
azumakuniyuki Jan 4, 2025
fe6ce69
Bug fix for getting an error code string
azumakuniyuki Jan 4, 2025
e844bef
private/lhost-gmail/1047 have 3 bounce messages
azumakuniyuki Jan 4, 2025
923dd4d
Fix invalid formatted email address
azumakuniyuki Jan 5, 2025
e161ff6
private/lhost-sendmail/1151 have 2 bounce messages in the file
azumakuniyuki Jan 7, 2025
2884f96
Disable private/lhost-sendmail/1207, because the file have 67 bounce …
azumakuniyuki Jan 7, 2025
cff2cb8
#569 Import commit https://github.com/sisimai/go-sisimai/commit/db1c2…
azumakuniyuki Jan 8, 2025
8d4b6e4
#569 Import commit https://github.com/sisimai/go-sisimai/commit/d128a…
azumakuniyuki Jan 8, 2025
910db92
#569 Update the test results for Sisimai::Lhost::V5sendmail
azumakuniyuki Jan 8, 2025
9a185d3
#569 Update the test results for Sisimai::Lhost::V5sendmail, import c…
azumakuniyuki Jan 8, 2025
04f8e12
Tiny code improvement for getting an email address
azumakuniyuki Jan 8, 2025
b3e38bb
Do not check the value of "deliverystatus" ( it is not used in the mo…
azumakuniyuki Jan 8, 2025
092881b
rhost-cox-01.eml have 2 bounce messages
azumakuniyuki Jan 10, 2025
a1fc7c1
Implement Sisimai::Rhost->name(), import commit https://github.com/si…
azumakuniyuki Jan 11, 2025
4cb4e23
Fix the remote host name
azumakuniyuki Jan 11, 2025
7bb8c36
Tiny code improvement in Sisimai::Rhost
azumakuniyuki Jan 11, 2025
1c496c8
Fix some remote host names
azumakuniyuki Jan 11, 2025
7a111d9
Add test suites for Sisimai::Rhost::GSuite, import commit https://git…
azumakuniyuki Jan 11, 2025
98b39e2
Import updates from https://github.com/sisimai/go-sisimai/commit/4a64…
azumakuniyuki Feb 3, 2025
01c2d91
Update some internal status codes, import commit https://github.com/s…
azumakuniyuki Feb 4, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion lib/Sisimai/LDA.pm
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ state $LocalAgent = {
# dovecot/src/deliver/deliver.c
# 11: #define DEFAULT_MAIL_REJECTION_HUMAN_REASON \
# 12: "Your message to <%t> was automatically rejected:%n%r"
"dovecot" => ["Your message to ", " was automatically rejected:"],
"dovecot" => ["Your message to <", "> was automatically rejected:"],
"mail.local" => ["mail.local: "],
"procmail" => ["procmail: ", "/procmail "],
"maildrop" => ["maildrop: "],
Expand Down
4 changes: 3 additions & 1 deletion lib/Sisimai/Lhost/Courier.pm
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ sub inquire {
}
return undef unless $match;

require Sisimai::RFC1123;
require Sisimai::SMTP::Command;
state $indicators = __PACKAGE__->INDICATORS;
state $boundaries = ['Content-Type: :message/rfc822', 'Content-Type: text/rfc822-headers'];
Expand Down Expand Up @@ -98,6 +99,7 @@ sub inquire {
} else {
# Other DSN fields defined in RFC3464
next unless exists $fieldtable->{ $o->[0] };
next if $o->[3] eq "host" && Sisimai::RFC1123->is_internethost($o->[2]) == 0;
$v->{ $fieldtable->{ $o->[0] } } = $o->[2];

next unless $f == 1;
Expand Down Expand Up @@ -194,7 +196,7 @@ azumakuniyuki

=head1 COPYRIGHT

Copyright (C) 2014-2024 azumakuniyuki, All rights reserved.
Copyright (C) 2014-2025 azumakuniyuki, All rights reserved.

=head1 LICENSE

Expand Down
4 changes: 3 additions & 1 deletion lib/Sisimai/Lhost/Domino.pm
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ sub inquire {
],
};

require Sisimai::RFC1123;
my $fieldtable = Sisimai::RFC1894->FIELDTABLE;
my $permessage = {}; # (Hash) Store values of each Per-Message field
my $dscontents = [__PACKAGE__->DELIVERYSTATUS];
Expand Down Expand Up @@ -120,6 +121,7 @@ sub inquire {
} else {
# Other DSN fields defined in RFC3464
next unless exists $fieldtable->{ $o->[0] };
next if $o->[3] eq "host" && Sisimai::RFC1123->is_internethost($o->[2]) == 0;
$v->{ $fieldtable->{ $o->[0] } } = $o->[2];

next unless $f == 1;
Expand Down Expand Up @@ -203,7 +205,7 @@ azumakuniyuki

=head1 COPYRIGHT

Copyright (C) 2014-2024 azumakuniyuki, All rights reserved.
Copyright (C) 2014-2025 azumakuniyuki, All rights reserved.

=head1 LICENSE

Expand Down
4 changes: 3 additions & 1 deletion lib/Sisimai/Lhost/Postfix.pm
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ sub inquire {
return undef if $match == 0;
return undef if $mhead->{'x-aol-ip'};

require Sisimai::RFC1123;
require Sisimai::SMTP::Reply;
require Sisimai::SMTP::Command;
state $indicators = __PACKAGE__->INDICATORS;
Expand Down Expand Up @@ -139,6 +140,7 @@ sub inquire {
} else {
# Other DSN fields defined in RFC3464
next unless exists $fieldtable->{ $o->[0] };
next if $o->[3] eq "host" && Sisimai::RFC1123->is_internethost($o->[2]) == 0;
$v->{ $fieldtable->{ $o->[0] } } = $o->[2];

next unless $f == 1;
Expand Down Expand Up @@ -322,7 +324,7 @@ azumakuniyuki

=head1 COPYRIGHT

Copyright (C) 2014-2024 azumakuniyuki, All rights reserved.
Copyright (C) 2014-2025 azumakuniyuki, All rights reserved.

=head1 LICENSE

Expand Down
4 changes: 3 additions & 1 deletion lib/Sisimai/Lhost/Sendmail.pm
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ sub inquire {
$match ||= 1 if index($mhead->{'subject'}, 'Warning: ') == 0;
return undef unless $match > 0;

require Sisimai::RFC1123;
require Sisimai::SMTP::Reply;
require Sisimai::SMTP::Status;
require Sisimai::SMTP::Command;
Expand Down Expand Up @@ -94,6 +95,7 @@ sub inquire {
} else {
# Other DSN fields defined in RFC3464
next unless exists $fieldtable->{ $o->[0] };
next if $o->[3] eq "host" && Sisimai::RFC1123->is_internethost($o->[2]) == 0;
$v->{ $fieldtable->{ $o->[0] } } = $o->[2];

next unless $f == 1;
Expand Down Expand Up @@ -247,7 +249,7 @@ azumakuniyuki

=head1 COPYRIGHT

Copyright (C) 2014-2024 azumakuniyuki, All rights reserved.
Copyright (C) 2014-2025 azumakuniyuki, All rights reserved.

=head1 LICENSE

Expand Down
160 changes: 94 additions & 66 deletions lib/Sisimai/Lhost/V5sendmail.pm
Original file line number Diff line number Diff line change
Expand Up @@ -36,21 +36,21 @@ sub inquire {
# savemail.c:497| while (fgets(buf, sizeof buf, xfile) != NULL)
# savemail.c:498| putline(buf, fp, m);
# savemail.c:499| (void) fclose(xfile);
'error' => [' while talking to '],
'error' => ['While talking to '],
'message' => ['----- Transcript of session follows -----'],
};

my $emailparts = Sisimai::RFC5322->part($mbody, $boundaries);
return undef unless length $emailparts->[1] > 0;

require Sisimai::RFC1123;
require Sisimai::SMTP::Command;
my $dscontents = [__PACKAGE__->DELIVERYSTATUS];
my $readcursor = 0; # (Integer) Points the current cursor position
my $recipients = 0; # (Integer) The number of 'Final-Recipient' header
my $anotherset = {}; # (Ref->Hash) Another error information
my @responding; # (Array) Responses from remote server
my @commandset; # (Array) SMTP command which is sent to remote server
my $errorindex = -1;
my $anotherone = {}; # (Ref->Hash) Another error information
my $remotehost = ""; # (String) The last remote hostname
my $curcommand = ""; # (String) The last SMTP command
my $v = undef;

for my $e ( split("\n", $emailparts->[0]) ) {
Expand All @@ -71,83 +71,111 @@ sub inquire {
# 550 <[email protected]>... User unknown
# 421 example.org (smtp)... Deferred: Connection timed out during user open with example.org
$v = $dscontents->[-1];
$curcommand = Sisimai::SMTP::Command->find(substr($e, 4,)) if index($e, ">>> ") == 0;

if( (index($e, '5') == 0 || index($e, '4') == 0) && Sisimai::String->aligned(\$e, [' <', '@', '>...']) ) {
if( Sisimai::String->aligned(\$e, [' <', '@', '>...']) || index(uc $e, ">>> RCPT TO:") > -1 ) {
# 550 <[email protected]>... User unknown
if( $v->{'recipient'} ) {
# There are multiple recipient addresses in the message body.
push @$dscontents, __PACKAGE__->DELIVERYSTATUS;
$v = $dscontents->[-1];
}
my $p1 = index($e, '<', 0);
my $p2 = index($e, '>...');
$v->{'recipient'} = substr($e, $p1 + 1, $p2 - $p1 - 1);
$v->{'diagnosis'} = substr($e, $p2 + 5,);

if( $responding[$recipients] ) {
# Concatenate the response of the server and error message
$v->{'diagnosis'} .= ': '.$responding[$recipients];
}
$recipients++;

} elsif( index($e, '>>> ') == 0 ) {
# >>> RCPT To:<[email protected]>
$commandset[$recipients] = Sisimai::SMTP::Command->find($e);

} elsif( index($e, '<<< ') == 0 ) {
# <<< Response
# <<< 501 <[email protected]>... no access from mail server [192.0.2.55] which is an open relay.
# <<< 550 Requested User Mailbox not found. No such user here.
$responding[$recipients] = substr($e, 4,);

} else {
# Detect SMTP session error or connection error
next if $v->{'sessionerr'};
if( index($e, $startingof->{'error'}->[0]) > 0 ) {
# ----- Transcript of session follows -----
# ... while talking to mta.example.org.:
$v->{'sessionerr'} = 1;
my $p0 = index($e, " ");
my $p1 = index($e, "<", $p0);
my $p2 = index($e, ">", $p1);
my $cv = Sisimai::Address->s3s4(substr($e, $p1, $p2 - $p1 + 1));

if( $remotehost eq "" ) {
# Keep error messages before "While talking to ..." line
$anotherone->{ $recipients } .= " ".$e;
next;
}

if( (index($e, '4') == 0 || index($e, '5') == 0) && index($e, '... ') > 1 ) {
# 421 example.org (smtp)... Deferred: Connection timed out during user open with example.org
$anotherset->{'replycode'} = substr($e, 0, 3);
$anotherset->{'diagnosis'} = substr($e, index($e, '... ') + 4,);
if( $cv eq $v->{"recipient"} || ($curcommand eq "MAIL" && index($e, "<<< ") == 0) ) {
# The recipient address is the same address with the last appeared address
# like "550 <[email protected]>... User unknown"
# Append this line to the string which is keeping error messages
$v->{"diagnosis"} .= " ".$e;
$v->{"replycode"} = Sisimai::SMTP::Reply->find($e);
$curcommand = "";

} else {
# The recipient address in this line differs from the last appeared address
# or is the first recipient address in this bounce message
if( $v->{'recipient'} ) {
# There are multiple recipient addresses in the message body.
push @$dscontents, __PACKAGE__->DELIVERYSTATUS;
$v = $dscontents->[-1];
}
$v->{"recipient"} = $cv;
$v->{"rhost"} = $remotehost;
$v->{"replycode"} = Sisimai::SMTP::Reply->find($e);
$v->{"diagnosis"} .= " ".$e;
$v->{"command"} ||= $curcommand;
$recipients++
}
} else {
# This line does not include a recipient address
if( index($e, $startingof->{"error"}->[0]) > -1 ) {
# ... while talking to mta.example.org.:
my $cv = Sisimai::RFC1123->find($e);
$remotehost = $cv if Sisimai::RFC1123->is_internethost($cv);

} else {
# Append this line into the error message string
if( index($e, ">>> ") == 0 || index($e, "<<< ") == 0 ) {
# >>> DATA
# <<< 550 Your E-Mail is redundant. You cannot send E-Mail to yourself ([email protected]).
# >>> QUIT
# <<< 421 dns.example.org Sorry, unable to contact destination SMTP daemon.
# <<< 550 Requested User Mailbox not found. No such user here.
$v->{"diagnosis"} .= " ".$e

} else {
# 421 Other error message
$anotherone->{ $recipients } .= " ".$e;
}
}
}
}

my $p1 = index($emailparts->[1], "\nTo: ");
my $p2 = index($emailparts->[1], "\n", $p1 + 6);
if( $recipients == 0 && $p1 > 0 ) {
# Get the recipient address from "To:" header at the original message
$dscontents->[0]->{'recipient'} = Sisimai::Address->s3s4(substr($emailparts->[1], $p1, $p2 - $p1 - 5));
$recipients = 1;
}
return undef unless $recipients;

for my $e ( @$dscontents ) {
$errorindex++;
delete $e->{'sessionerr'};
if( $recipients == 0 ) {
# There is no recipient address in the error message
for my $e ( keys %$anotherone ) {
# Try to pick an recipient address, a reply code, and error messages
my $cv = Sisimai::Address->s3s4($anotherone->{ $e }); next unless Sisimai::Address->is_emailaddress($cv);
my $cr = Sisimai::SMTP::Reply->find($anotherone->{ $e }) || "";

if( exists $anotherset->{'diagnosis'} && $anotherset->{'diagnosis'} ) {
# Copy alternative error message
$e->{'diagnosis'} ||= $anotherset->{'diagnosis'};
$dscontents->[ $e ]->{"recipient"} = $cv;
$dscontents->[ $e ]->{"replycode"} = $cr;
$dscontents->[ $e ]->{"diagnosis"} = $anotherone->{ $e };
$recipients++;
}

} else {
# Set server response as a error message
$e->{'diagnosis'} ||= $responding[$errorindex];
if( $recipients == 0 ) {
# Try to pick an recipient address from the original message
my $p1 = index($emailparts->[1], "\nTo: ");
my $p2 = index($emailparts->[1], "\n", $p1 + 6);

if( $p1 > 0 ) {
# Get the recipient address from "To:" header at the original message
my $cv = Sisimai::Address->s3s4(substr($emailparts->[1], $p1, $p2 - $p1 - 5));
return undef unless Sisimai::Address->is_emailaddress($cv);
$dscontents->[0]->{'recipient'} = $cv;
$recipients++;
}
}
$e->{'diagnosis'} = Sisimai::String->sweep($e->{'diagnosis'});
$e->{'replycode'} = Sisimai::SMTP::Reply->find($e->{'diagnosis'}) || $anotherset->{'replycode'};
$e->{'command'} = $commandset[$errorindex] || Sisimai::SMTP::Command->find($e->{'diagnosis'}) || '';
}
return undef unless $recipients;

my $j = 0; for my $e ( @$dscontents ) {
# Tidy up the error message in e.Diagnosis
$e->{"diagnosis"} ||= $anotherone->{ $j };
$e->{'diagnosis'} = Sisimai::String->sweep($e->{'diagnosis'});
$e->{"command"} ||= Sisimai::SMTP::Command->find($e->{"diagnosis"});
$e->{'replycode'} = Sisimai::SMTP::Reply->find($e->{'diagnosis'}) || $anotherone->{'replycode'};

# @example.jp, no local part
# Get email address from the value of Diagnostic-Code header
next if index($e->{'recipient'}, '@') > 0;
$p1 = index($e->{'diagnosis'}, '<'); next if $p1 == -1;
$p2 = index($e->{'diagnosis'}, '>'); next if $p2 == -1;
my $p1 = index($e->{'diagnosis'}, '<'); next if $p1 == -1;
my $p2 = index($e->{'diagnosis'}, '>'); next if $p2 == -1;
$e->{'recipient'} = Sisimai::Address->s3s4(substr($e->{'diagnosis'}, $p1, $p2 - $p1));
}
return { 'ds' => $dscontents, 'rfc822' => $emailparts->[1] };
Expand Down Expand Up @@ -190,7 +218,7 @@ azumakuniyuki

=head1 COPYRIGHT

Copyright (C) 2014-2021,2023,2024 azumakuniyuki, All rights reserved.
Copyright (C) 2014-2021,2023-2025 azumakuniyuki, All rights reserved.

=head1 LICENSE

Expand Down
4 changes: 2 additions & 2 deletions lib/Sisimai/RFC1894.pm
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ sub FIELDTABLE {
'original-recipient'=> 'alias',
'received-from-mta' => 'lhost',
'remote-mta' => 'rhost',
'reporting-mta' => 'rhost',
'reporting-mta' => 'lhost',
'status' => 'status',
'x-actual-recipient'=> 'alias',
};
Expand Down Expand Up @@ -263,7 +263,7 @@ azumakuniyuki

=head1 COPYRIGHT

Copyright (C) 2018-2024 azumakuniyuki, All rights reserved.
Copyright (C) 2018-2025 azumakuniyuki, All rights reserved.

=head1 LICENSE

Expand Down
6 changes: 4 additions & 2 deletions lib/Sisimai/RFC3464.pm
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use v5.26;
use strict;
use warnings;
use Sisimai::Lhost;
use Sisimai::RFC1123;
use Sisimai::RFC3464::ThirdParty;

# http://tools.ietf.org/html/rfc3464
Expand Down Expand Up @@ -186,8 +187,9 @@ sub inquire {
$v->{'diagnosis'} .= " ".$o->[4]." ";
}
next unless exists $fieldtable->{ $o->[0] };
$v->{ $fieldtable->{ $o->[0] } } = $o->[2];
next if $o->[3] eq "host" && Sisimai::RFC1123->is_internethost($o->[2]) == 0;

$v->{ $fieldtable->{ $o->[0] } } = $o->[2];
next unless $f == 1;
$permessage->{ $fieldtable->{ $o->[0] } } = $o->[2];
}
Expand Down Expand Up @@ -316,7 +318,7 @@ azumakuniyuki

=head1 COPYRIGHT

Copyright (C) 2014-2024 azumakuniyuki, All rights reserved.
Copyright (C) 2014-2025 azumakuniyuki, All rights reserved.

=head1 LICENSE

Expand Down
3 changes: 2 additions & 1 deletion lib/Sisimai/Reason/Blocked.pm
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ sub match {
['is in an ', 'rbl on '],
['mail server at ', ' is blocked'],
['mail from ',' refused:'],
["mail from "," refused, see ", "orbs"],
['message from ', ' rejected based on blacklist'],
['messages from ', ' temporarily deferred due to user complaints'], # Yahoo!
['server ip ', ' listed as abusive'],
Expand Down Expand Up @@ -170,7 +171,7 @@ azumakuniyuki

=head1 COPYRIGHT

Copyright (C) 2014-2024 azumakuniyuki, All rights reserved.
Copyright (C) 2014-2025 azumakuniyuki, All rights reserved.

=head1 LICENSE

Expand Down
3 changes: 2 additions & 1 deletion lib/Sisimai/Reason/RequirePTR.pm
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ sub match {
'all mail servers must have a ptr record with a valid reverse dns entry',
'bad dns ptr resource record',
'cannot find your hostname',
"cannot resolve your address.",
'client host rejected: cannot find your hostname', # Yahoo!
'fix reverse dns for ',
'ips with missing ptr records',
Expand Down Expand Up @@ -114,7 +115,7 @@ azumakuniyuki

=head1 COPYRIGHT

Copyright (C) 2024 azumakuniyuki, All rights reserved.
Copyright (C) 2024-2025 azumakuniyuki, All rights reserved.

=head1 LICENSE

Expand Down
Loading