The Perl and Raku Conference 2025: Greenville, South Carolina - June 27-29 Learn more

use v5.26;
use strict;
sub description { "Google Workspace: https://workspace.google.com/" }
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.
# 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