—package
Sisimai::Lhost::GoogleWorkspace;
use
v5.26;
use
strict;
use
warnings;
sub
inquire {
# Detect an error from Google Workspace (Transfer from the Google Workspace to the destination host)
# @param [Hash] mhead Message headers of a bounce email
# @param [String] mbody Message body of a bounce email
# @return [Hash] Bounce data list and message/rfc822 part
# @return [undef] failed to decode or the arguments are missing
# @since v4.21.0
my
$class
=
shift
;
my
$mhead
=
shift
//
return
undef
;
my
$mbody
=
shift
//
return
undef
;
return
undef
if
index
(
$$mbody
,
"\nDiagnostic-Code:"
) > -1;
return
undef
if
index
(
$$mbody
,
"\nFinal-Recipient:"
) > -1;
return
undef
unless
rindex
(
$mhead
->{
'from'
},
'<mailer-daemon@googlemail.com>'
) > -1;
return
undef
unless
index
(
$mhead
->{
'subject'
},
"Delivery Status Notification"
) > -1;
state
$indicators
= __PACKAGE__->INDICATORS;
state
$boundaries
= [
"Content-Type: message/rfc822"
,
"Content-Type: text/rfc822-headers"
];
state
$startingof
= {
'message'
=> [
"** "
],
'error'
=> [
"The response was:"
,
"The response from the remote server was:"
],
};
state
$messagesof
= {
"userunknown"
=> [
"because the address couldn't be found. Check for typos or unnecessary spaces and try again."
],
"notaccept"
=> [
"Null MX"
],
"networkerror"
=> [
" had no relevant answers."
,
" responded with code NXDOMAIN"
],
};
my
$dscontents
= [__PACKAGE__->DELIVERYSTATUS];
my
$emailparts
= Sisimai::RFC5322->part(
$mbody
,
$boundaries
);
my
$entiremesg
=
""
;
my
$readcursor
= 0;
# (Integer) Points the current cursor position
my
$recipients
= 0;
for
my
$e
(
split
(
"\n"
,
$emailparts
->[0]) ) {
# Read error messages and delivery status lines from the head of the email to the previous
# line of the beginning of the original message.
unless
(
$readcursor
) {
# Beginning of the bounce message or message/delivery-status part
if
(
index
(
$e
,
$startingof
->{
'message'
}->[0]) == 0 ) {
# ** Message not delivered **
$readcursor
|=
$indicators
->{
'deliverystatus'
};
$entiremesg
.=
$e
.
" "
;
}
}
next
unless
$readcursor
&
$indicators
->{
'deliverystatus'
};
next
unless
$e
;
# ** Message not delivered **
# You're sending this from a different address or alias using the 'Send mail as' feature.
# The settings for your 'Send mail as' account are misconfigured or out of date. Check those settings and try resending.
# Learn more here: https://support.google.com/mail/?p=CustomFromDenied
# The response was:
# Unspecified Error (SENT_SECOND_EHLO): Smtp server does not advertise AUTH capability
next
if
index
(
$e
,
"Content-Type: "
) == 0;
$entiremesg
.=
$e
.
" "
;
}
while
(
$recipients
== 0 ) {
# Pick the recipient address from the value of To: header of the original message after
# Content-Type: message/rfc822 field
my
$p0
=
index
(
$emailparts
->[1],
"\nTo:"
);
last
if
$p0
< 0;
my
$p1
=
index
(
$emailparts
->[1],
"\n"
,
$p0
+ 2);
my
$cv
= Sisimai::Address->s3s4(
substr
(
$emailparts
->[1],
$p0
+ 4,
$p1
-
$p0
));
$dscontents
->[0]->{
'recipient'
} =
$cv
;
$recipients
++;
}
return
undef
unless
$recipients
;
$dscontents
->[0]->{
'diagnosis'
} =
$entiremesg
;
for
my
$e
(
@$dscontents
) {
# Tidy up the error message in e.Diagnosis, Try to detect the bounce reason.
$e
->{
'diagnosis'
} = Sisimai::String->sweep(
$e
->{
'diagnosis'
});
for
my
$r
(
keys
%$messagesof
) {
# Guess an reason of the bounce
next
unless
grep
{
index
(
$e
->{
'diagnosis'
},
$_
) > -1 }
$messagesof
->{
$r
}->@*;
$e
->{
'reason'
} =
$r
;
last
;
}
}
return
{
'ds'
=>
$dscontents
,
'rfc822'
=>
$emailparts
->[1] };
}
1;
__END__
=encoding utf-8
=head1 NAME
Sisimai::Lhost::GoogleWorkspace - bounce mail decoder class for Google Workspace L<https://workspace.google.com/>
=head1 SYNOPSIS
use Sisimai::Lhost::GoogleWorkspace;
=head1 DESCRIPTION
C<Sisimai::Lhost::GoogleWorkspace> decodes a bounce email which created by Google Workspace L<https://workspace.google.com/>.
Methods in the module are called from only C<Sisimai::Message>.
=head1 CLASS METHODS
=head2 C<B<description()>>
C<description()> returns description string of this module.
print Sisimai::Lhost::GoogleWorkspace->description;
=head2 C<B<inquire(I<header data>, I<reference to body string>)>>
C<inquire()> method decodes a bounced email and return results as a array reference.
See C<Sisimai::Message> for more details.
=head1 AUTHOR
azumakuniyuki
=head1 COPYRIGHT
Copyright (C) 2017-2024 azumakuniyuki, All rights reserved.
=head1 LICENSE
This software is distributed under The BSD 2-Clause License.
=cut