File Coverage

lib/Sisimai/Rhost/Cox.pm
Criterion Covered Total %
statement 22 24 91.6
branch 7 8 87.5
condition 4 4 100.0
subroutine 4 4 100.0
pod 0 1 0.0
total 37 41 90.2


line stmt bran cond sub pod time code
1             package Sisimai::Rhost::Cox;
2 4     4   2205 use v5.26;
  4         17  
3 4     4   25 use strict;
  4         11  
  4         132  
4 4     4   22 use warnings;
  4         5  
  4         2168  
5              
6             sub find {
7             # Detect bounce reason from https://cox.com/
8             # @param [Sisimai::Fact] argvs Decoded email object
9             # @return [String] The bounce reason at Cox
10             # @see
11             # - Email Error Codes: https://www.cox.com/business/support/email-error-codes.html
12             # - Feedback Loop Service https://www.cox.com/business/support/feedback-loop-service.html
13             # @since v4.25.8
14 12     12 0 1108 my $class = shift;
15 12 100 100     42 my $argvs = shift // return ""; return "" unless $argvs->{'diagnosticcode'};
  11         49  
16              
17 10         91 state $errorcodes = {
18             # CXBL
19             # - The sending IP address has been blocked by Cox due to exhibiting spam-like behavior.
20             # - Send an email request to Cox to ask for a sending IP address be unblocked.
21             # Note: Cox has sole discretion whether to unblock the sending IP address.
22             'CXBL' => 'blocked',
23              
24             # CXDNS
25             # - There was an issue with the connecting IP address Domain Name System (DNS).
26             # - The Reverse DNS (rDNS) lookup for your IP address is failing.
27             # - Confirm the IP address that sends your email.
28             # - Check the rDNS of that IP address. If it passes, then wait 24 hours and try resending
29             # your email.
30             'CXDNS' => 'requireptr',
31              
32             # CXSNDR
33             # - There was a problem with the sender's domain.
34             # - Your email failed authentication checks against your sending domain's SPF, DomainKeys,
35             # or DKIM policy.
36             'CXSNDR' => 'authfailure',
37              
38             # CXSMTP
39             # - There was a violation of SMTP protocol.
40             # - Your email wasn't delivered because Cox was unable to verify that it came from a
41             # legitimate email sender.
42             'CXSMTP' => 'rejected',
43              
44             # CXCNCT
45             # - There was a connection issue from the IP address.
46             # - There is a limit to the number of concurrent SMTP connections per IP address to
47             # protect the systems against attack. Ensure that the sending email server is not
48             # opening more than 10 concurrent connections to avoid reaching this limit.
49             'CXCNCT' => 'ratelimited',
50              
51             # CXMXRT
52             # - The sender has sent email to too many recipients and needs to wait before sending
53             # more email.
54             # - The email sender has exceeded the maximum number of sent email allowed.
55             'CXMXRT' => 'ratelimited',
56              
57             # CDRBL
58             # - The sending IP address has been temporarily blocked by Cox due to exhibiting spam-like
59             # behavior.
60             # - The block duration varies depending on reputation and other factors, but will not exceed
61             # 24 hours. Inspect email traffic for potential spam, and retry email delivery.
62             'CDRBL' => 'blocked',
63              
64             'CXTHRT' => 'securityerror', # Email sending limited due to suspicious account activity.
65             'CXMJ' => 'securityerror', # Email sending blocked due to suspicious account activity on primary Cox account.
66             'IPBL0001' => 'blocked', # The sending IP address is listed in the Spamhaus Zen DNSBL.
67             'IPBL0010' => 'blocked', # The sending IP is listed in the Return Path DNSBL.
68             'IPBL0100' => 'blocked', # The sending IP is listed in the Invaluement ivmSIP DNSBL.
69             'IPBL0011' => 'blocked', # The sending IP is in the Spamhaus Zen and Return Path DNSBLs.
70             'IPBL0101' => 'blocked', # The sending IP is in the Spamhaus Zen and Invaluement ivmSIP DNSBLs.
71             'IPBL0110' => 'blocked', # The sending IP is in the Return Path and Invaluement ivmSIP DNSBLs.
72             'IPBL0111' => 'blocked', # The sending IP is in the Spamhaus Zen, Return Path and Invaluement ivmSIP DNSBLs.
73             'IPBL1000' => 'blocked', # The sending IP address is listed on a CSI blacklist.
74             'IPBL1001' => 'blocked', # The sending IP is listed in the Cloudmark CSI and Spamhaus Zen DNSBLs.
75             'IPBL1010' => 'blocked', # The sending IP is listed in the Cloudmark CSI and Return Path DNSBLs.
76             'IPBL1011' => 'blocked', # The sending IP is in the Cloudmark CSI, Spamhaus Zen and Return Path DNSBLs.
77             'IPBL1100' => 'blocked', # The sending IP is listed in the Cloudmark CSI and Invaluement ivmSIP DNSBLs.
78             'IPBL1101' => 'blocked', # The sending IP is in the Cloudmark CSI, Spamhaus Zen and Invaluement IVMsip DNSBLs.
79             'IPBL1110' => 'blocked', # The sending IP is in the Cloudmark CSI, Return Path and Invaluement ivmSIP DNSBLs.
80             'IPBL1111' => 'blocked', # The sending IP is in the Cloudmark CSI, Spamhaus Zen, Return Path and Invaluement ivmSIP DNSBLs.
81             'IPBL00001' => 'blocked', # The sending IP address is listed on a Spamhaus blacklist.
82              
83             'URLBL011' => 'spamdetected', # A URL within the body of the message was found on blocklists SURBL and Spamhaus DBL.
84             'URLBL101' => 'spamdetected', # A URL within the body of the message was found on blocklists SURBL and ivmURI.
85             'URLBL110' => 'spamdetected', # A URL within the body of the message was found on blocklists Spamhaus DBL and ivmURI.
86             'URLBL1001' => 'spamdetected', # The URL is listed on a Spamhaus blacklist.
87             };
88 10         75 state $messagesof = {
89             'blocked' => [
90             # - An email client has repeatedly sent bad commands or invalid passwords resulting in
91             # a three-hour block of the client's IP address.
92             # - The sending IP address has exceeded the threshold of invalid recipients and has
93             # been blocked.
94             'cox too many bad commands from',
95             'too many invalid recipients',
96             ],
97             'contenterror' => [
98             # - The message has been rejected because it contains an attachment with one of the
99             # following prohibited file types, which commonly contain viruses: .shb, .shs, .vbe,
100             # .vbs, .wsc, .wsf, .wsh, .pif, .msc, .msi, .msp, .reg, .sct, .bat, .chm, .isp, .cpl,
101             # .js, .jse, .scr, .exe.
102             'attachment extension is forbidden',
103             ],
104             'policyviolation' => [
105             # - The sending server has attempted to communicate too soon within the SMTP transaction
106             'esmtp no data before greeting',
107             ],
108             'ratelimited' => [
109             # - The sending IP address has exceeded the five maximum concurrent connection limit.
110             # - The SMTP connection has exceeded the 100 email message threshold and was disconnected.
111             # - The sending IP address has exceeded one of these rate limits and has been temporarily
112             # blocked.
113             # - Cox enforces various rate limits to protect our platform. The sending IP address
114             # has exceeded one of these rate limits and has been temporarily blocked.
115             'too many sessions from',
116             'requested action aborted: try again later',
117             'message threshold exceeded',
118             ],
119             'rejected' => [
120             # Cox requires that all sender domains resolve to a valid MX or A-record within DNS.
121             'sender rejected',
122             ],
123             'requireptr' => [
124             # - The reverse DNS check of the sending server IP address has failed.
125             # - Cox requires that all connecting email servers contain valid reverse DNS PTR records.
126             'dns check failure - try again later',
127             'rejected - no rdns',
128             ],
129             'systemerror' => [
130             # - Our systems are experiencing an issue which is causing a temporary inability to
131             # accept new email.
132             'esmtp server temporarily not available',
133             ],
134             'userunknown' => [
135             # - The intended recipient is not a valid Cox Email account.
136             'recipient rejected',
137             ],
138             };
139 10         43 my $issuedcode = $argvs->{'diagnosticcode'};
140 10 100       86 my $codenumber = $issuedcode =~ m/AUP#([0-9A-Z]+)/ ? $1 : 0;
141 10   100     44 my $reasontext = $errorcodes->{ $codenumber } || '';
142              
143 10 100       27 unless( $reasontext ) {
144             # The error code was not found in $errorcodes
145 2         7 $issuedcode = lc $issuedcode;
146 2         10 for my $e ( keys %$messagesof ) {
147             # Try to find with each error message defined in $messagesof
148 16 50       30 next unless grep { index($issuedcode, $_) > -1 } $messagesof->{ $e }->@*;
  24         54  
149 0         0 $reasontext = $e;
150 0         0 last;
151             }
152             }
153 10         47 return $reasontext;
154             }
155              
156             1;
157             __END__