1package Sisimai::Lhost::GoogleGroups;
2use parent 'Sisimai::Lhost';
3use feature ':5.10';
4use strict;
5use warnings;
6
7sub description { 'Google Groups: https://groups.google.com' }
8sub make {
9    # Detect an error from Google Groups
10    # @param    [Hash] mhead    Message headers of a bounce email
11    # @param    [String] mbody  Message body of a bounce email
12    # @return   [Hash]          Bounce data list and message/rfc822 part
13    # @return   [Undef]         failed to parse or the arguments are missing
14    # @since v4.25.6
15    my $class = shift;
16    my $mhead = shift // return undef;
17    my $mbody = shift // return undef;
18
19    return undef unless rindex($mhead->{'from'}, '<mailer-daemon@googlemail.com>') > -1;
20    return undef unless index($mhead->{'subject'}, 'Delivery Status Notification') > -1;
21    return undef unless exists $mhead->{'x-failed-recipients'};
22    return undef unless index($mhead->{'x-failed-recipients'}, '@googlegroups.com') > -1;
23
24    # Hello kijitora@libsisimai.org,
25    #
26    # We're writing to let you know that the group you tried to contact (group-name)
27    # may not exist, or you may not have permission to post messages to the group.
28    # A few more details on why you weren't able to post:
29    #
30    #  * You might have spelled or formatted the group name incorrectly.
31    #  * The owner of the group may have removed this group.
32    #  * You may need to join the group before receiving permission to post.
33    #  * This group may not be open to posting.
34    #
35    # If you have questions related to this or any other Google Group,
36    # visit the Help Center at https://groups.google.com/support/.
37    #
38    # Thanks,
39    #
40    # Google Groups
41    state $indicators = __PACKAGE__->INDICATORS;
42    state $rebackbone = qr/^-----[ ]Original[ ]message[ ]-----$/m;
43
44    my $dscontents = [__PACKAGE__->DELIVERYSTATUS];
45    my $emailsteak = Sisimai::RFC5322->fillet($mbody, $rebackbone);
46    my $recordwide = { 'rhost' => '', 'reason' => '', 'diagnosis' => '' };
47    my $recipients = 0;
48    my $v = $dscontents->[-1];
49
50    # * You might have spelled or formatted the group name incorrectly.
51    # * The owner of the group may have removed this group.
52    # * You may need to join the group before receiving permission to post.
53    # * This group may not be open to posting.
54    my $fewdetails = [$emailsteak->[0] =~ /^[ ]?[*][ ]?/gm] || [];
55    $recordwide->{'reason'} = scalar @$fewdetails == 4 ? 'rejected' : 'onhold';
56
57    my @entiremesg = split(/\n\n/, $emailsteak->[0], 5); pop @entiremesg;
58    my $diagnostic = join(' ', @entiremesg); $diagnostic =~ y/\n/ /;
59    $recordwide->{'diagnosis'} = Sisimai::String->sweep($diagnostic);
60
61    my $serverlist = Sisimai::RFC5322->received($mhead->{'received'}->[0]);
62    $recordwide->{'rhost'} = shift @$serverlist;
63
64    for my $e ( split(',', $mhead->{'x-failed-recipients'}) ) {
65        # X-Failed-Recipients: neko@example.jp, nyaan@example.org, ...
66        next unless index($e, '@googlegroups.com') > -1;
67        next unless Sisimai::RFC5322->is_emailaddress($e);
68
69        if( $v->{'recipient'} ) {
70            # There are multiple recipient addresses in the message body.
71            push @$dscontents, __PACKAGE__->DELIVERYSTATUS;
72            $v = $dscontents->[-1];
73        }
74        $v->{'recipient'} = Sisimai::Address->s3s4($e);
75        $recipients++;
76        $v->{ $_ } = $recordwide->{ $_ } for keys %$recordwide;
77    }
78    return undef unless $recipients;
79    return { 'ds' => $dscontents, 'rfc822' => $emailsteak->[1] };
80}
81
821;
83__END__
84
85=encoding utf-8
86
87=head1 NAME
88
89Sisimai::Lhost::GoogleGroups - bounce mail parser class for C<Google Groups>.
90
91=head1 SYNOPSIS
92
93    use Sisimai::Lhost::GoogleGroups;
94
95=head1 DESCRIPTION
96
97Sisimai::Lhost::GoogleGroups parses a bounce email which created by C<Gmail>.
98Methods in the module are called from only Sisimai::Message.
99
100=head1 CLASS METHODS
101
102=head2 C<B<description()>>
103
104C<description()> returns description string of this module.
105
106    print Sisimai::Lhost::GoogleGroups->description;
107
108=head2 C<B<make(I<header data>, I<reference to body string>)>>
109
110C<make()> method parses a bounced email and return results as a array reference.
111See Sisimai::Message for more details.
112
113=head1 AUTHOR
114
115azumakuniyuki
116
117=head1 COPYRIGHT
118
119Copyright (C) 2020 azumakuniyuki, All rights reserved.
120
121=head1 LICENSE
122
123This software is distributed under The BSD 2-Clause License.
124
125=cut
126
127