| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package Sisimai::RFC3464; |
|
2
|
33
|
|
|
33
|
|
13721
|
use v5.26; |
|
|
33
|
|
|
|
|
97
|
|
|
3
|
33
|
|
|
33
|
|
126
|
use strict; |
|
|
33
|
|
|
|
|
46
|
|
|
|
33
|
|
|
|
|
629
|
|
|
4
|
33
|
|
|
33
|
|
98
|
use warnings; |
|
|
33
|
|
|
|
|
156
|
|
|
|
33
|
|
|
|
|
1381
|
|
|
5
|
33
|
|
|
33
|
|
153
|
use Sisimai::Lhost; |
|
|
33
|
|
|
|
|
42
|
|
|
|
33
|
|
|
|
|
761
|
|
|
6
|
33
|
|
|
33
|
|
121
|
use Sisimai::RFC1123; |
|
|
33
|
|
|
|
|
56
|
|
|
|
33
|
|
|
|
|
577
|
|
|
7
|
33
|
|
|
33
|
|
12733
|
use Sisimai::RFC3464::ThirdParty; |
|
|
33
|
|
|
|
|
75
|
|
|
|
33
|
|
|
|
|
55744
|
|
|
8
|
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
# http://tools.ietf.org/html/rfc3464 |
|
10
|
1
|
|
|
1
|
1
|
2
|
sub description { 'RFC3464' }; |
|
11
|
|
|
|
|
|
|
sub inquire { |
|
12
|
|
|
|
|
|
|
# Decode a bounce mail which have fields defined in RFC3464 |
|
13
|
|
|
|
|
|
|
# @param [Hash] mhead Message headers of a bounce email |
|
14
|
|
|
|
|
|
|
# @param [String] mbody Message body of a bounce email |
|
15
|
|
|
|
|
|
|
# @return [Hash] Bounce data list and message/rfc822 part |
|
16
|
|
|
|
|
|
|
# @return [undef] failed to decode or the arguments are missing |
|
17
|
891
|
|
|
891
|
1
|
22245
|
my $class = shift; |
|
18
|
891
|
100
|
100
|
|
|
1786
|
my $mhead = shift // return undef; return undef unless keys %$mhead; |
|
|
873
|
|
|
|
|
2584
|
|
|
19
|
854
|
100
|
50
|
|
|
1413
|
my $mbody = shift // return undef; return undef unless ref $mbody eq 'SCALAR'; |
|
|
854
|
|
|
|
|
2009
|
|
|
20
|
|
|
|
|
|
|
|
|
21
|
853
|
|
|
|
|
1991
|
require Sisimai::RFC1894; |
|
22
|
853
|
|
|
|
|
1932
|
require Sisimai::RFC2045; |
|
23
|
853
|
|
|
|
|
1865
|
require Sisimai::RFC5322; |
|
24
|
853
|
|
|
|
|
2032
|
require Sisimai::Address; |
|
25
|
853
|
|
|
|
|
2303
|
require Sisimai::String; |
|
26
|
|
|
|
|
|
|
|
|
27
|
853
|
|
|
|
|
1019
|
state $indicators = Sisimai::Lhost->INDICATORS; |
|
28
|
853
|
|
|
|
|
1005
|
state $boundaries = [ |
|
29
|
|
|
|
|
|
|
# When the new value added, the part of the value should be listed in $delimiters variable |
|
30
|
|
|
|
|
|
|
# defined at Sisimai::RFC2045->makeFlat() method |
|
31
|
|
|
|
|
|
|
"Content-Type: message/rfc822", |
|
32
|
|
|
|
|
|
|
"Content-Type: text/rfc822-headers", |
|
33
|
|
|
|
|
|
|
"Content-Type: message/partial", |
|
34
|
|
|
|
|
|
|
"Content-Disposition: inline", # See lhost-amavis-*.eml, lhost-facebook-*.eml |
|
35
|
|
|
|
|
|
|
]; |
|
36
|
853
|
|
|
|
|
931
|
state $startingof = {"message" => ["Content-Type: message/delivery-status"]}; |
|
37
|
853
|
|
|
|
|
1471
|
state $fieldtable = Sisimai::RFC1894->FIELDTABLE; |
|
38
|
|
|
|
|
|
|
|
|
39
|
853
|
100
|
|
|
|
1357
|
unless( grep { index($$mbody, $_) > 0 } @$boundaries ) { |
|
|
3412
|
|
|
|
|
7208
|
|
|
40
|
|
|
|
|
|
|
# There is no "Content-Type: message/rfc822" line in the message body |
|
41
|
|
|
|
|
|
|
# Insert "Content-Type: message/rfc822" before "Return-Path:" of the original message |
|
42
|
121
|
|
|
|
|
277
|
my $p0 = index($$mbody, "\n\nReturn-Path:"); |
|
43
|
121
|
100
|
|
|
|
14922
|
$$mbody = sprintf("%s%s%s", substr($$mbody, 0, $p0), $boundaries->[0], substr($$mbody, $p0 + 1,)) if $p0 > 0; |
|
44
|
|
|
|
|
|
|
} |
|
45
|
|
|
|
|
|
|
|
|
46
|
853
|
|
|
|
|
1616
|
my $permessage = {}; |
|
47
|
853
|
|
|
|
|
3437
|
my $dscontents = [Sisimai::Lhost->DELIVERYSTATUS]; my $v = undef; |
|
|
853
|
|
|
|
|
1210
|
|
|
48
|
853
|
|
|
|
|
1665
|
my $alternates = Sisimai::Lhost->DELIVERYSTATUS; |
|
49
|
853
|
|
|
|
|
3401
|
my $emailparts = Sisimai::RFC5322->part($mbody, $boundaries); |
|
50
|
853
|
|
|
|
|
1018
|
my $readcursor = 0; # (Integer) Points the current cursor position |
|
51
|
853
|
|
|
|
|
1009
|
my $recipients = 0; # (Integer) The number of 'Final-Recipient' header |
|
52
|
853
|
|
|
|
|
1061
|
my $beforemesg = ""; # (String) String before $startingof->{"message"} |
|
53
|
853
|
|
|
|
|
971
|
my $goestonext = 0; # (Bool) Flag: do not append the line into $beforemesg |
|
54
|
853
|
|
100
|
|
|
3168
|
my $isboundary = [Sisimai::RFC2045->boundary($mhead->{"content-type"}, 0)]; $isboundary->[0] ||= ""; |
|
|
853
|
|
|
|
|
1961
|
|
|
55
|
853
|
|
|
|
|
1155
|
my $p = ""; |
|
56
|
|
|
|
|
|
|
|
|
57
|
853
|
|
|
|
|
2747
|
while( index($emailparts->[0], '@') < 0 ) { |
|
58
|
|
|
|
|
|
|
# There is no email address in the first element of emailparts |
|
59
|
|
|
|
|
|
|
# There is a bounce message inside of message/rfc822 part at lhost-x5-* |
|
60
|
28
|
|
|
|
|
37
|
my $p0 = -1; # The index of the boundary string found first |
|
61
|
28
|
|
|
|
|
44
|
my $p1 = 0; # Offset position of the message body after the boundary string |
|
62
|
28
|
|
|
|
|
47
|
my $ct = ""; # Boundary string found first such as "Content-Type: message/rfc822" |
|
63
|
|
|
|
|
|
|
|
|
64
|
28
|
|
|
|
|
41
|
for my $e ( @$boundaries ) { |
|
65
|
|
|
|
|
|
|
# Look for a boundary string from the message body |
|
66
|
73
|
100
|
|
|
|
105
|
$p0 = index($$mbody, $e."\n"); next if $p0 < 0; |
|
|
73
|
|
|
|
|
131
|
|
|
67
|
13
|
|
|
|
|
20
|
$p1 = $p0 + length($e) + 2; |
|
68
|
13
|
|
|
|
|
17
|
$ct = $e; last; |
|
|
13
|
|
|
|
|
13
|
|
|
69
|
|
|
|
|
|
|
} |
|
70
|
28
|
100
|
|
|
|
59
|
last if $p0 < 0; |
|
71
|
|
|
|
|
|
|
|
|
72
|
13
|
|
|
|
|
204
|
my $cx = substr($$mbody, $p1,); |
|
73
|
13
|
|
|
|
|
27
|
my $p2 = index($cx,, "\n\n"); |
|
74
|
13
|
|
|
|
|
32
|
my $cv = substr($cx, $p2 + 2,); |
|
75
|
13
|
|
|
|
|
47
|
$emailparts = Sisimai::RFC5322->part(\$cv, [$ct], 0); |
|
76
|
13
|
|
|
|
|
30
|
last; |
|
77
|
|
|
|
|
|
|
} |
|
78
|
|
|
|
|
|
|
|
|
79
|
853
|
100
|
|
|
|
2840
|
if( index($emailparts->[0], $startingof->{"message"}->[0]) < 0 ) { |
|
80
|
|
|
|
|
|
|
# There is no "Content-Type: message/delivery-status" line in the message body |
|
81
|
|
|
|
|
|
|
# Insert "Content-Type: message/delivery-status" before "Reporting-MTA:" field |
|
82
|
167
|
|
|
|
|
256
|
my $cv = "\n\nReporting-MTA:"; |
|
83
|
167
|
|
|
|
|
275
|
my $e0 = $emailparts->[0]; |
|
84
|
167
|
|
|
|
|
303
|
my $p0 = index($e0, $cv); |
|
85
|
167
|
100
|
|
|
|
620
|
$emailparts->[0] = sprintf("%s\n\n%s%s", substr($e0, 0, $p0), $startingof->{"message"}->[0], substr($e0, $p0,)) if $p0 > 0; |
|
86
|
|
|
|
|
|
|
} |
|
87
|
|
|
|
|
|
|
|
|
88
|
853
|
|
|
|
|
1440
|
for my $e ("Final-Recipient", "Original-Recipient") { |
|
89
|
|
|
|
|
|
|
# Fix the malformed field "Final-Recipient: " |
|
90
|
1706
|
|
|
|
|
1847
|
my $cv = "\n".$e.": "; |
|
91
|
1706
|
|
|
|
|
1628
|
my $cx = $cv."<"; |
|
92
|
1706
|
100
|
|
|
|
2343
|
my $p0 = index($emailparts->[0], $cx); next if $p0 < 0; |
|
|
1706
|
|
|
|
|
2767
|
|
|
93
|
|
|
|
|
|
|
|
|
94
|
26
|
|
|
|
|
93
|
substr($emailparts->[0], $p0, length($cv) + 1, $cv."rfc822; "); |
|
95
|
26
|
|
|
|
|
43
|
my $p1 = index($emailparts->[0], ">\n", $p0 + 2); substr($emailparts->[0], $p1, 1, ""); |
|
|
26
|
|
|
|
|
54
|
|
|
96
|
|
|
|
|
|
|
} |
|
97
|
|
|
|
|
|
|
|
|
98
|
853
|
|
|
|
|
6737
|
for my $e ( split("\n", $emailparts->[0]) ) { |
|
99
|
|
|
|
|
|
|
# Read error messages and delivery status lines from the head of the email to the previous |
|
100
|
|
|
|
|
|
|
# line of the beginning of the original message. |
|
101
|
17837
|
100
|
|
|
|
19856
|
if( $readcursor == 0 ) { |
|
102
|
|
|
|
|
|
|
# Beginning of the bounce message or message/delivery-status part |
|
103
|
11119
|
100
|
|
|
|
15302
|
$readcursor |= $indicators->{'deliverystatus'} if index($e, $startingof->{'message'}->[0]) == 0; |
|
104
|
|
|
|
|
|
|
|
|
105
|
11119
|
|
|
|
|
8031
|
while(1) { |
|
106
|
|
|
|
|
|
|
# Append each string before startingof["message"][0] except the following patterns |
|
107
|
|
|
|
|
|
|
# for the later reference |
|
108
|
11119
|
100
|
66
|
|
|
18610
|
last if $e eq "" || $goestonext; # Blank line or the part is text/html, image/icon, in multipart/* |
|
109
|
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
# This line is a boundary kept in "multiparts" as a string, when the end of the boundary |
|
111
|
|
|
|
|
|
|
# appeared, the condition above also returns true. |
|
112
|
7322
|
100
|
|
|
|
6680
|
if( grep { index($e, $_) == 0 } @$isboundary ) { $goestonext = 0; last } |
|
|
7337
|
|
|
|
|
12058
|
|
|
|
976
|
|
|
|
|
810
|
|
|
|
976
|
|
|
|
|
763
|
|
|
113
|
6346
|
100
|
|
|
|
7944
|
if( index($e, "Content-Type:") == 0 ) { |
|
114
|
|
|
|
|
|
|
# Content-Type: field in multipart/* |
|
115
|
795
|
100
|
|
|
|
2187
|
if( index($e, "multipart/") > 0 ) { |
|
|
|
50
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
# Content-Type: multipart/alternative; boundary=aa00220022222222ffeebb |
|
117
|
|
|
|
|
|
|
# Pick the boundary string and store it into "isboucdary" |
|
118
|
1
|
|
|
|
|
3
|
push @$isboundary, Sisimai::RFC2045->boundary($e, 0); |
|
119
|
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
} elsif( index($e, "text/plain") ) { |
|
121
|
|
|
|
|
|
|
# Content-Type: "text/plain" |
|
122
|
794
|
|
|
|
|
1016
|
$goestonext = 0; |
|
123
|
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
} else { |
|
125
|
|
|
|
|
|
|
# Other types: for example, text/html, image/jpg, and so on |
|
126
|
0
|
|
|
|
|
0
|
$goestonext = 1; |
|
127
|
|
|
|
|
|
|
} |
|
128
|
795
|
|
|
|
|
828
|
last; |
|
129
|
|
|
|
|
|
|
} |
|
130
|
|
|
|
|
|
|
|
|
131
|
5551
|
100
|
|
|
|
6534
|
last if index($e, "Content-") == 0; # Content-Disposition, ... |
|
132
|
5536
|
100
|
|
|
|
6396
|
last if index($e, "This is a MIME") == 0; # This is a MIME-formatted message. |
|
133
|
5356
|
100
|
|
|
|
6495
|
last if index($e, "This is a multi") == 0; # This is a multipart message in MIME format |
|
134
|
5268
|
100
|
|
|
|
6786
|
last if index($e, "This is an auto") == 0; # This is an automatically generated ... |
|
135
|
5148
|
100
|
|
|
|
6113
|
last if index($e, "This multi-part") == 0; # This multi-part MIME message contains... |
|
136
|
5143
|
100
|
|
|
|
6380
|
last if index($e, "###") == 0; # A frame like ##### |
|
137
|
5133
|
50
|
|
|
|
6014
|
last if index($e, "***") == 0; # A frame like ***** |
|
138
|
5133
|
100
|
|
|
|
6235
|
last if index($e, "--") == 0; # Boundary string |
|
139
|
5100
|
100
|
|
|
|
6524
|
last if index($e, "--- The follow") > -1; # ----- The following addresses had delivery problems ----- |
|
140
|
5035
|
100
|
|
|
|
5965
|
last if index($e, "--- Transcript") > -1; # ----- Transcript of session follows ----- |
|
141
|
5012
|
|
|
|
|
7501
|
$beforemesg .= $e." "; last; |
|
|
5012
|
|
|
|
|
3952
|
|
|
142
|
|
|
|
|
|
|
} |
|
143
|
11119
|
|
|
|
|
9412
|
next; |
|
144
|
|
|
|
|
|
|
} |
|
145
|
6718
|
100
|
66
|
|
|
16991
|
next if ($readcursor & $indicators->{'deliverystatus'}) == 0 || $e eq ""; |
|
146
|
|
|
|
|
|
|
|
|
147
|
5927
|
100
|
|
|
|
13601
|
if( my $f = Sisimai::RFC1894->match($e) ) { |
|
148
|
|
|
|
|
|
|
# $e matched with any field defined in RFC3464 |
|
149
|
5247
|
100
|
|
|
|
8147
|
next unless my $o = Sisimai::RFC1894->field($e); |
|
150
|
5082
|
|
|
|
|
5735
|
$v = $dscontents->[-1]; |
|
151
|
|
|
|
|
|
|
|
|
152
|
5082
|
100
|
|
|
|
8951
|
if( $o->[3] eq "addr" ) { |
|
|
|
100
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
# Final-Recipient: rfc822; kijitora@example.jp |
|
154
|
|
|
|
|
|
|
# X-Actual-Recipient: rfc822; kijitora@example.co.jp |
|
155
|
957
|
100
|
|
|
|
1550
|
if( $o->[0] eq "final-recipient" ) { |
|
156
|
|
|
|
|
|
|
# Final-Recipient: rfc822; kijitora@example.jp |
|
157
|
|
|
|
|
|
|
# Final-Recipient: x400; /PN=... |
|
158
|
745
|
50
|
|
|
|
4069
|
my $cv = Sisimai::Address->s3s4($o->[2]); next unless Sisimai::Address->is_emailaddress($cv); |
|
|
745
|
|
|
|
|
2201
|
|
|
159
|
745
|
50
|
33
|
|
|
1522
|
my $cw = scalar @$dscontents; next if $cw > 0 && $cv eq $dscontents->[$cw - 1]->{'recipient'}; |
|
|
745
|
|
|
|
|
3367
|
|
|
160
|
|
|
|
|
|
|
|
|
161
|
745
|
100
|
|
|
|
1398
|
if( $v->{'recipient'} ) { |
|
162
|
|
|
|
|
|
|
# There are multiple recipient addresses in the message body. |
|
163
|
32
|
|
|
|
|
121
|
push @$dscontents, Sisimai::Lhost->DELIVERYSTATUS; |
|
164
|
32
|
|
|
|
|
59
|
$v = $dscontents->[-1]; |
|
165
|
|
|
|
|
|
|
} |
|
166
|
745
|
|
|
|
|
1094
|
$v->{'recipient'} = $cv; |
|
167
|
745
|
|
|
|
|
1730
|
$recipients++; |
|
168
|
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
} else { |
|
170
|
|
|
|
|
|
|
# X-Actual-Recipient: rfc822; kijitora@example.co.jp |
|
171
|
212
|
|
|
|
|
463
|
$v->{'alias'} = $o->[2]; |
|
172
|
|
|
|
|
|
|
} |
|
173
|
|
|
|
|
|
|
} elsif( $o->[3] eq "code" ) { |
|
174
|
|
|
|
|
|
|
# Diagnostic-Code: SMTP; 550 5.1.1 ... User Unknown |
|
175
|
670
|
|
|
|
|
1183
|
$v->{'spec'} = $o->[1]; |
|
176
|
670
|
|
|
|
|
1933
|
$v->{'diagnosis'} .= $o->[2]." "; |
|
177
|
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
} else { |
|
179
|
|
|
|
|
|
|
# Other DSN fields defined in RFC3464 |
|
180
|
3455
|
100
|
|
|
|
4904
|
if( $o->[4] ne "" ) { |
|
181
|
|
|
|
|
|
|
# There are other error messages as a comment such as the following: |
|
182
|
|
|
|
|
|
|
# Status: 5.0.0 (permanent failure) |
|
183
|
|
|
|
|
|
|
# Status: 4.0.0 (cat.example.net: host name lookup failure) |
|
184
|
659
|
|
|
|
|
1157
|
$v->{'diagnosis'} .= " ".$o->[4]." "; |
|
185
|
|
|
|
|
|
|
} |
|
186
|
3455
|
50
|
|
|
|
5760
|
next unless exists $fieldtable->{ $o->[0] }; |
|
187
|
3455
|
100
|
100
|
|
|
9964
|
next if $o->[3] eq "host" && Sisimai::RFC1123->is_internethost($o->[2]) == 0; |
|
188
|
|
|
|
|
|
|
|
|
189
|
3215
|
|
|
|
|
5929
|
$v->{ $fieldtable->{ $o->[0] } } = $o->[2]; |
|
190
|
3215
|
100
|
|
|
|
5587
|
next unless $f == 1; |
|
191
|
1292
|
|
|
|
|
3255
|
$permessage->{ $fieldtable->{ $o->[0] } } = $o->[2]; |
|
192
|
|
|
|
|
|
|
} |
|
193
|
|
|
|
|
|
|
} else { |
|
194
|
|
|
|
|
|
|
# Check that the line is a continued line of the value of Diagnostic-Code: field or not |
|
195
|
680
|
100
|
66
|
|
|
2046
|
if( index($e, "X-") == 0 && index($e, ": ") > 1 ) { |
|
196
|
|
|
|
|
|
|
# This line is a MTA-Specific fields begins with "X-" |
|
197
|
238
|
100
|
|
|
|
850
|
next unless Sisimai::RFC3464::ThirdParty->is3rdparty($e); |
|
198
|
|
|
|
|
|
|
|
|
199
|
32
|
|
|
|
|
64
|
my $cv = Sisimai::RFC3464::ThirdParty->xfield($e); |
|
200
|
32
|
100
|
66
|
|
|
137
|
if( scalar(@$cv) > 0 && not exists $fieldtable->{ lc $cv->[0] } ) { |
|
201
|
|
|
|
|
|
|
# Check the first element is a field defined in RFC1894 or not |
|
202
|
16
|
50
|
|
|
|
69
|
$v->{'reason'} = substr($cv->[4], index($cv->[4], ":") + 1,) if index($cv->[4], "reason:") == 0; |
|
203
|
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
} else { |
|
205
|
|
|
|
|
|
|
# Set the value picked from "X-*" field to $dscontents when the current value is empty |
|
206
|
16
|
50
|
|
|
|
32
|
my $z = $fieldtable->{ lc $cv->[0] }; next unless $z; |
|
|
16
|
|
|
|
|
22
|
|
|
207
|
16
|
|
33
|
|
|
42
|
$v->{ $z } ||= $cv->[2]; |
|
208
|
|
|
|
|
|
|
} |
|
209
|
|
|
|
|
|
|
} else { |
|
210
|
|
|
|
|
|
|
# The line may be a continued line of the value of the Diagnostic-Code: field |
|
211
|
442
|
100
|
|
|
|
921
|
if( index($p, 'Diagnostic-Code:') < 0 ) { |
|
212
|
|
|
|
|
|
|
# In the case of multiple "message/delivery-status" line |
|
213
|
233
|
100
|
|
|
|
494
|
next if index($e, "Content-") == 0; # Content-Disposition:, ... |
|
214
|
223
|
100
|
|
|
|
447
|
next if index($e, "--") == 0; # Boundary string |
|
215
|
207
|
|
|
|
|
289
|
$beforemesg .= $e." "; next |
|
216
|
207
|
|
|
|
|
227
|
} |
|
217
|
|
|
|
|
|
|
|
|
218
|
|
|
|
|
|
|
# Diagnostic-Code: SMTP; 550-5.7.26 The MAIL FROM domain [email.example.jp] |
|
219
|
|
|
|
|
|
|
# has an SPF record with a hard fail |
|
220
|
209
|
100
|
|
|
|
590
|
next unless index($e, " ") == 0; |
|
221
|
176
|
|
|
|
|
422
|
$v->{'diagnosis'} .= " ".$e; |
|
222
|
|
|
|
|
|
|
} |
|
223
|
|
|
|
|
|
|
} |
|
224
|
|
|
|
|
|
|
} continue { |
|
225
|
|
|
|
|
|
|
# Save the current line for the next loop |
|
226
|
17837
|
|
|
|
|
18647
|
$p = $e; |
|
227
|
|
|
|
|
|
|
} |
|
228
|
|
|
|
|
|
|
|
|
229
|
853
|
|
|
|
|
3728
|
while( $recipients == 0 ) { |
|
230
|
|
|
|
|
|
|
# There is no valid recipient address, Try to use the alias addaress as a final recipient |
|
231
|
140
|
100
|
|
|
|
330
|
last unless length $dscontents->[0]->{'alias'} > 0; |
|
232
|
26
|
50
|
|
|
|
168
|
last unless Sisimai::Address->is_emailaddress($dscontents->[0]->{'alias'}); |
|
233
|
26
|
|
|
|
|
79
|
$dscontents->[0]->{'recipient'} = $dscontents->[0]->{'alias'}; |
|
234
|
26
|
|
|
|
|
56
|
$recipients++; |
|
235
|
|
|
|
|
|
|
} |
|
236
|
853
|
100
|
|
|
|
2018
|
return undef unless $recipients; |
|
237
|
|
|
|
|
|
|
|
|
238
|
739
|
|
|
|
|
3839
|
require Sisimai::SMTP::Reply; |
|
239
|
739
|
|
|
|
|
2184
|
require Sisimai::SMTP::Status; |
|
240
|
739
|
|
|
|
|
1952
|
require Sisimai::SMTP::Command; |
|
241
|
|
|
|
|
|
|
|
|
242
|
739
|
100
|
|
|
|
1424
|
if( $beforemesg ne "" ) { |
|
243
|
|
|
|
|
|
|
# Pick some values of $dscontents from the string before $startingof->{'message'} |
|
244
|
729
|
|
|
|
|
1621
|
$beforemesg = Sisimai::String->sweep($beforemesg); |
|
245
|
729
|
|
|
|
|
5192
|
$alternates->{'command'} = Sisimai::SMTP::Command->find($beforemesg); |
|
246
|
729
|
|
|
|
|
3944
|
$alternates->{'replycode'} = Sisimai::SMTP::Reply->find($beforemesg, $dscontents->[0]->{'status'}); |
|
247
|
729
|
|
|
|
|
3664
|
$alternates->{'status'} = Sisimai::SMTP::Status->find($beforemesg, $alternates->{'replycode'}); |
|
248
|
|
|
|
|
|
|
} |
|
249
|
739
|
|
|
|
|
2165
|
my $issuedcode = lc $beforemesg; |
|
250
|
|
|
|
|
|
|
|
|
251
|
739
|
|
|
|
|
997
|
for my $e ( @$dscontents ) { |
|
252
|
|
|
|
|
|
|
# Set default values stored in "permessage" if each value in "dscontents" is empty. |
|
253
|
771
|
|
50
|
|
|
3045
|
$e->{ $_ } ||= $permessage->{ $_ } || '' for keys %$permessage; |
|
|
|
|
66
|
|
|
|
|
|
254
|
771
|
|
|
|
|
1696
|
my $lowercased = lc $e->{'diagnosis'}; |
|
255
|
|
|
|
|
|
|
|
|
256
|
771
|
100
|
|
|
|
1300
|
if( $recipients == 1 ) { |
|
257
|
|
|
|
|
|
|
# Do not mix the error message of each recipient with "beforemesg" when there is |
|
258
|
|
|
|
|
|
|
# multiple recipient addresses in the bounce message |
|
259
|
712
|
100
|
|
|
|
1619
|
if( index($issuedcode, $lowercased) > -1 ) { |
|
260
|
|
|
|
|
|
|
# $beforemesg contains the entire strings of $e->{'diagnosis'} |
|
261
|
83
|
|
|
|
|
214
|
$e->{'diagnosis'} = $beforemesg; |
|
262
|
|
|
|
|
|
|
|
|
263
|
|
|
|
|
|
|
} else { |
|
264
|
|
|
|
|
|
|
# The value of $e->{'diagnosis'} is not contained in $beforemesg |
|
265
|
|
|
|
|
|
|
# There may be an important error message in $beforemesg |
|
266
|
629
|
|
|
|
|
2640
|
$e->{'diagnosis'} = sprintf("%s %s", $beforemesg, $e->{'diagnosis'}); |
|
267
|
|
|
|
|
|
|
} |
|
268
|
|
|
|
|
|
|
} |
|
269
|
771
|
|
100
|
|
|
1965
|
$e->{'command'} = Sisimai::SMTP::Command->find($e->{'diagnosis'}) || $alternates->{'command'}; |
|
270
|
771
|
|
66
|
|
|
2169
|
$e->{'replycode'} = Sisimai::SMTP::Reply->find($e->{'diagnosis'}, $e->{'status'}) || $alternates->{'replycode'}; |
|
271
|
771
|
|
66
|
|
|
1727
|
$e->{'status'} ||= Sisimai::SMTP::Status->find($e->{'diagnosis'}, $e->{'replycode'}) || $alternates->{'status'}; |
|
|
|
|
100
|
|
|
|
|
|
272
|
|
|
|
|
|
|
} |
|
273
|
|
|
|
|
|
|
|
|
274
|
|
|
|
|
|
|
# Set the recipient address as To: header in the original message part |
|
275
|
739
|
100
|
|
|
|
1447
|
$emailparts->[1] = sprintf("To: <%s>\n", $dscontents->[0]->{'recipient'}) unless $emailparts->[1]; |
|
276
|
|
|
|
|
|
|
|
|
277
|
739
|
|
|
|
|
6153
|
return {"ds" => $dscontents, "rfc822" => $emailparts->[1]}; |
|
278
|
|
|
|
|
|
|
} |
|
279
|
|
|
|
|
|
|
|
|
280
|
|
|
|
|
|
|
1; |
|
281
|
|
|
|
|
|
|
|
|
282
|
|
|
|
|
|
|
__END__ |