File Coverage

lib/Sisimai/Rhost/GoogleApps.pm
Criterion Covered Total %
statement 26 26 100.0
branch 6 8 75.0
condition 2 2 100.0
subroutine 4 4 100.0
pod 0 1 0.0
total 38 41 92.6


line stmt bran cond sub pod time code
1             package Sisimai::Rhost::GoogleApps;
2 7     7   1336 use feature ':5.10';
  7         9  
  7         609  
3 7     7   36 use strict;
  7         12  
  7         139  
4 7     7   39 use warnings;
  7         11  
  7         3314  
5              
6             sub get {
7             # Detect bounce reason from Google Apps
8             # @param [Sisimai::Data] argvs Parsed email object
9             # @return [String] The bounce reason for Google Apps
10             # @see https://support.google.com/a/answer/3726730?hl=en
11 82     82 0 881 my $class = shift;
12 82   100     214 my $argvs = shift // return undef;
13 81 50       235 return $argvs->reason if $argvs->reason;
14              
15 81         694 state $statuslist = {
16             # https://support.google.com/a/answer/3726730
17             'X.1.1' => [{ 'reason' => 'userunknown', 'string' => ['The email account that you tried to reach does not exist.'] }],
18             'X.1.2' => [{ 'reason' => 'hostunknown', 'string' => ["We weren't able to find the recipient domain."] }],
19             'X.2.1' => [
20             { 'reason' => 'suspend', 'string' => ['The email account that you tried to reach is disabled.'] },
21             { 'reason' => 'exceedlimit', 'string' => ['The user you are trying to contact is receiving mail '] },
22             ],
23             'X.2.2' => [{ 'reason' => 'mailboxfull', 'string' => ['The email account that you tried to reach is over quota.'] }],
24             'X.2.3' => [{ 'reason' => 'exceedlimit', 'string' => ["Your message exceeded Google's message size limits."] }],
25             'X.3.0' => [
26             { 'reason' => 'syntaxerror', 'string' => ['Multiple destination domains per transaction is unsupported.'] },
27             { 'reason' => 'undefined', 'string' => ['Mail server temporarily rejected message.'] },
28             ],
29             'X.4.2' => [{ 'reason' => 'expired', 'string' => ['Timeout - closing connection.'] }],
30             'X.4.5' => [
31             { 'reason' => 'exceedlimit', 'string' => ['Daily sending quota exceeded.'] },
32             { 'reason' => 'undefined', 'string' => ['Server busy, try again later.'] },
33             ],
34             'X.5.0' => [{ 'reason' => 'syntaxerror', 'string' => ['SMTP protocol violation'] }],
35             'X.5.1' => [
36             { 'reason' => 'securityerror', 'string' => ['Authentication Required.'] },
37             { 'reason' => 'syntaxerror', 'string' => [
38             'STARTTLS may not be repeated',
39             'Too many unrecognized commands, goodbye.',
40             'Unimplemented command.',
41             'Unrecognized command.',
42             'EHLO/HELO first.',
43             'MAIL first.',
44             'RCPT first.',
45             ]},
46             ],
47             'X.5.2' => [
48             { 'reason' => 'securityerror', 'string' => ['Cannot Decode response.'] }, # 2FA related error, maybe.
49             { 'reason' => 'syntaxerror', 'string' => ['Syntax error.'] },
50             ],
51             'X.5.3' => [
52             { 'reason' => 'mailboxfull', 'string' => ['Domain policy size per transaction exceeded,'] },
53             { 'reason' => 'policyviolation','string' => ['Your message has too many recipients.'] },
54             ],
55             'X.5.4' => [{ 'reason' => 'syntaxerror', 'string' => ['Optional Argument not permitted for that AUTH mode.'] }],
56             'X.6.0' => [
57             { 'reason' => 'contenterror', 'string' => ['Mail message is malformed.'] },
58             { 'reason' => 'networkerror', 'string' => ['Message exceeded 50 hops'] }
59             ],
60             'X.7.0' => [
61             { 'reason' => 'blocked', 'string' => [
62             'IP not in whitelist for RCPT domain, closing connection.',
63             'unusual rate of unsolicited mail originating from your IP address.',
64             ]},
65             { 'reason' => 'expired', 'string' => [
66             'Temporary System Problem. Try again later.',
67             'Try again later, closing connection.',
68             ]},
69             { 'reason' => 'securityerror', 'string' => [
70             'TLS required for RCPT domain, closing connection.',
71             'No identity changes permitted.',
72             'Must issue a STARTTLS command first.',
73             'Too Many Unauthenticated commands.',
74             ]},
75             { 'reason' => 'policyviolation','string' => [
76             'an illegal attachment on your message',
77             'This message was blocked because its content presents a potential',
78             ]},
79             { 'reason' => 'systemerror', 'string' => ['Cannot authenticate due to temporary system problem.'] },
80             { 'reason' => 'norelaying', 'string' => ['Mail relay denied.'] },
81             { 'reason' => 'rejected', 'string' => ['Mail Sending denied.'] },
82             ],
83             'X.7.1' => [
84             { 'reason' => 'mailboxfull', 'string' => ['Email quota exceeded.'] },
85             { 'reason' => 'securityerror', 'string' => [
86             'Application-specific password required.',
87             'Please log in with your web browser and then try again.',
88             'Username and Password not accepted.',
89             ]},
90             { 'reason' => 'blocked', 'string' => [
91             'The IP address sending this message does not have a PTR record setup.',
92             "The IP you're using to send mail is not authorized to send email directly to our servers.",
93             'this message is likely suspicious due to the very low reputation of the sending IP address',
94             'unusual rate of unsolicited mail originating from your IP address.',
95             ]},
96             { 'reason' => 'spamdetected', 'string' => ['this message is likely unsolicited mail.'] },
97             { 'reason' => 'policyviolation','string' => [
98             'Messages with multiple addresses in From: header are not accepted.',
99             'The user or domain that you are sending to (or from) has a policy',
100             ]},
101             { 'reason' => 'rejected', 'string' => [
102             'This message does not have authentication information or fails to pass authentication checks',
103             'Unauthenticated email is not accepted from this domain.'
104             ] },
105             ],
106             'X.7.4' => [{ 'reason' => 'syntaxerror', 'string' => ['Unrecognized Authentication Type.'] }],
107             };
108              
109 81         217 substr(my $statuscode = $argvs->deliverystatus, 0, 1, 'X');
110 81 100       488 return '' unless exists $statuslist->{ $statuscode };
111 76 50       106 return '' unless scalar @{ $statuslist->{ $statuscode } };
  76         207  
112              
113 76         111 my $reasontext = '';
114 76         120 for my $e ( @{ $statuslist->{ $statuscode } } ) {
  76         154  
115             # Try to match
116 258 100       933 next unless grep { rindex($argvs->diagnosticcode, $_) > -1 } @{ $e->{'string'} };
  557         1534  
  258         476  
117 71         381 $reasontext = $e->{'reason'};
118 71         119 last;
119             }
120 76         214 return $reasontext;
121             }
122              
123             1;
124             __END__