File Coverage

lib/Sisimai/Lhost/X2.pm
Criterion Covered Total %
statement 46 47 97.8
branch 27 28 96.4
condition 20 27 74.0
subroutine 6 6 100.0
pod 2 2 100.0
total 101 110 91.8


line stmt bran cond sub pod time code
1             package Sisimai::Lhost::X2;
2 37     37   2862 use parent 'Sisimai::Lhost';
  37         64  
  37         238  
3 37     37   2510 use v5.26;
  37         153  
4 37     37   163 use strict;
  37         65  
  37         834  
5 37     37   132 use warnings;
  37         72  
  37         19526  
6              
7 1     1 1 3 sub description { 'Unknown MTA #2' }
8             sub inquire {
9             # Detect an error from Unknown MTA #2
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 decode or the arguments are missing
14             # @since v4.1.7
15 911     911 1 2685 my $class = shift;
16 911   100     1794 my $mhead = shift // return undef;
17 910   100     1555 my $mbody = shift // return undef;
18 909 100 50     917 my $match = 0; $match ||= 1 if index($mhead->{'from'}, 'MAILER-DAEMON@') > -1;
  909         3161  
19 909 100 100     2053 $match ||= 1 if index($mhead->{'subject'}, 'Delivery failure') == 0;
20 909 100 50     1914 $match ||= 1 if index($mhead->{'subject'}, 'failure delivery') == 0;
21 909 100 50     2134 $match ||= 1 if index($mhead->{'subject'}, 'failed delivery') == 0;
22 909 100       1895 return undef unless $match > 0;
23              
24 319         600 state $indicators = __PACKAGE__->INDICATORS;
25 319         400 state $boundaries = ['--- Original message follows.'];
26 319         473 state $startingof = {
27             'message' => [
28             'Unable to deliver message to the following address',
29             'This Delivery Status Notification is sent from MTA',
30             ]
31             };
32              
33 319         1071 my $dscontents = [__PACKAGE__->DELIVERYSTATUS]; my $v = undef;
  319         487  
34 319         1337 my $emailparts = Sisimai::RFC5322->part($mbody, $boundaries);
35 319         607 my $readcursor = 0; # (Integer) Points the current cursor position
36 319         413 my $recipients = 0; # (Integer) The number of 'Final-Recipient' header
37              
38 319         3838 for my $e ( split("\n", $emailparts->[0]) ) {
39             # Read error messages and delivery status lines from the head of the email to the previous
40             # line of the beginning of the original message.
41 11989 100       12917 unless( $readcursor ) {
42             # Beginning of the bounce message or message/delivery-status part
43 11801 100       10659 $readcursor |= $indicators->{'deliverystatus'} if grep { index($e, $_) == 0 } $startingof->{'message'}->@*;
  23602         27699  
44 11801         10568 next;
45             }
46 188 100 66     438 next if ($readcursor & $indicators->{'deliverystatus'}) == 0 || $e eq "";
47              
48             # Message from example.com.
49             # Unable to deliver message to the following address(es).
50             #
51             # :
52             # This user doesn't have a example.com account (kijitora@example.com) [0]
53             #
54             # --- OR ---
55             #
56             # This Delivery Status Notification is sent from MTA...
57             #
58             # Your delivery to the following address has been failed.
59             # Please refer to the below for details.
60             # ------------------------------------------------------
61             #
62             # Delivery failed: kijitora@example.co.jp
63             # 192.0.2.25 does not like recipient.
64             # Remote host said[Response Message]: 550 5.1.1 :
65             # Recipient address rejected: User unknown in local recipient table
66             # Giving up on 192.0.2.25.
67             # STEP: RCPT TO
68 137         130 $v = $dscontents->[-1];
69              
70 137 100 66     687 if( index($e, '<') == 0 && Sisimai::String->aligned(\$e, ['<', '@', '>:']) ||
    50 66        
    100 100        
71             index($e, 'Delivery failed: ') == 0 && Sisimai::String->aligned(\$e, ['failed: ', '@']) ) {
72             # :
73             # Delivery failed: kijitora@example.co.jp
74 46 100       110 if( $v->{'recipient'} ) {
75             # There are multiple recipient addresses in the message body.
76 10         21 push @$dscontents, __PACKAGE__->DELIVERYSTATUS;
77 10         13 $v = $dscontents->[-1];
78             }
79 46 100       126 $v->{'recipient'} = substr($e, 1, length($e) - 3 ) if index($e, '<') == 0;
80 46   66     86 $v->{'recipient'} ||= substr($e, index($e, ': ') + 2,);
81 46         92 $recipients++;
82              
83             } elsif( index($e, 'STTEP: ') == 0 ) {
84             # STEP: RCPT TO
85             # STEP: DATA SEND
86 0         0 $v->{'command'} = Sisimai::SMTP::Command->find($e)
87              
88             } elsif( index($e, '-----') != 0 ) {
89             # This user doesn't have a example.com account (kijitora@example.com) [0]
90 86         164 $v->{'diagnosis'} .= ' '.$e;
91             }
92             }
93 319 100       2401 return undef unless $recipients;
94 36         129 return {"ds" => $dscontents, "rfc822" => $emailparts->[1]};
95             }
96              
97             1;
98             __END__