| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package Sisimai::RFC3464; |
|
2
|
32
|
|
|
32
|
|
18827
|
use v5.26; |
|
|
32
|
|
|
|
|
126
|
|
|
3
|
32
|
|
|
32
|
|
213
|
use strict; |
|
|
32
|
|
|
|
|
60
|
|
|
|
32
|
|
|
|
|
817
|
|
|
4
|
32
|
|
|
32
|
|
153
|
use warnings; |
|
|
32
|
|
|
|
|
77
|
|
|
|
32
|
|
|
|
|
1772
|
|
|
5
|
32
|
|
|
32
|
|
165
|
use Sisimai::Lhost; |
|
|
32
|
|
|
|
|
57
|
|
|
|
32
|
|
|
|
|
910
|
|
|
6
|
32
|
|
|
32
|
|
432
|
use Sisimai::RFC1123; |
|
|
32
|
|
|
|
|
54
|
|
|
|
32
|
|
|
|
|
925
|
|
|
7
|
32
|
|
|
32
|
|
18913
|
use Sisimai::RFC3464::ThirdParty; |
|
|
32
|
|
|
|
|
275
|
|
|
|
32
|
|
|
|
|
77785
|
|
|
8
|
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
# http://tools.ietf.org/html/rfc3464 |
|
10
|
1
|
|
|
1
|
1
|
21
|
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
|
893
|
|
|
893
|
1
|
30251
|
my $class = shift; |
|
18
|
893
|
100
|
100
|
|
|
3072
|
my $mhead = shift // return undef; return undef unless keys %$mhead; |
|
|
875
|
|
|
|
|
4154
|
|
|
19
|
856
|
100
|
50
|
|
|
2500
|
my $mbody = shift // return undef; return undef unless ref $mbody eq 'SCALAR'; |
|
|
856
|
|
|
|
|
2915
|
|
|
20
|
|
|
|
|
|
|
|
|
21
|
855
|
|
|
|
|
3275
|
require Sisimai::RFC1894; |
|
22
|
855
|
|
|
|
|
3169
|
require Sisimai::RFC2045; |
|
23
|
855
|
|
|
|
|
2572
|
require Sisimai::RFC5322; |
|
24
|
855
|
|
|
|
|
3885
|
require Sisimai::Address; |
|
25
|
855
|
|
|
|
|
2730
|
require Sisimai::String; |
|
26
|
|
|
|
|
|
|
|
|
27
|
855
|
|
|
|
|
1562
|
state $indicators = Sisimai::Lhost->INDICATORS; |
|
28
|
855
|
|
|
|
|
1331
|
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
|
855
|
|
|
|
|
1389
|
state $startingof = {"message" => ["Content-Type: message/delivery-status"]}; |
|
37
|
855
|
|
|
|
|
1921
|
state $fieldtable = Sisimai::RFC1894->FIELDTABLE; |
|
38
|
|
|
|
|
|
|
|
|
39
|
855
|
100
|
|
|
|
2240
|
unless( grep { index($$mbody, $_) > 0 } @$boundaries ) { |
|
|
3420
|
|
|
|
|
11452
|
|
|
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
|
124
|
|
|
|
|
450
|
my $p0 = index($$mbody, "\n\nReturn-Path:"); |
|
43
|
124
|
100
|
|
|
|
695
|
$$mbody = sprintf("%s%s%s", substr($$mbody, 0, $p0), $boundaries->[0], substr($$mbody, $p0 + 1,)) if $p0 > 0; |
|
44
|
|
|
|
|
|
|
} |
|
45
|
|
|
|
|
|
|
|
|
46
|
855
|
|
|
|
|
1627
|
my $permessage = {}; |
|
47
|
855
|
|
|
|
|
5312
|
my $dscontents = [Sisimai::Lhost->DELIVERYSTATUS]; my $v = undef; |
|
|
855
|
|
|
|
|
1999
|
|
|
48
|
855
|
|
|
|
|
2295
|
my $alternates = Sisimai::Lhost->DELIVERYSTATUS; |
|
49
|
855
|
|
|
|
|
4630
|
my $emailparts = Sisimai::RFC5322->part($mbody, $boundaries); |
|
50
|
855
|
|
|
|
|
1731
|
my $readcursor = 0; # (Integer) Points the current cursor position |
|
51
|
855
|
|
|
|
|
1278
|
my $recipients = 0; # (Integer) The number of 'Final-Recipient' header |
|
52
|
855
|
|
|
|
|
1616
|
my $beforemesg = ""; # (String) String before $startingof->{"message"} |
|
53
|
855
|
|
|
|
|
1404
|
my $goestonext = 0; # (Bool) Flag: do not append the line into $beforemesg |
|
54
|
855
|
|
100
|
|
|
5051
|
my $isboundary = [Sisimai::RFC2045->boundary($mhead->{"content-type"}, 0)]; $isboundary->[0] ||= ""; |
|
|
855
|
|
|
|
|
3076
|
|
|
55
|
855
|
|
|
|
|
2140
|
my $p = ""; |
|
56
|
|
|
|
|
|
|
|
|
57
|
855
|
|
|
|
|
3827
|
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
|
|
|
|
|
60
|
my $p0 = -1; # The index of the boundary string found first |
|
61
|
28
|
|
|
|
|
51
|
my $p1 = 0; # Offset position of the message body after the boundary string |
|
62
|
28
|
|
|
|
|
92
|
my $ct = ""; # Boundary string found first such as "Content-Type: message/rfc822" |
|
63
|
|
|
|
|
|
|
|
|
64
|
28
|
|
|
|
|
93
|
for my $e ( @$boundaries ) { |
|
65
|
|
|
|
|
|
|
# Look for a boundary string from the message body |
|
66
|
73
|
100
|
|
|
|
150
|
$p0 = index($$mbody, $e."\n"); next if $p0 < 0; |
|
|
73
|
|
|
|
|
179
|
|
|
67
|
13
|
|
|
|
|
58
|
$p1 = $p0 + length($e) + 2; |
|
68
|
13
|
|
|
|
|
26
|
$ct = $e; last; |
|
|
13
|
|
|
|
|
28
|
|
|
69
|
|
|
|
|
|
|
} |
|
70
|
28
|
100
|
|
|
|
90
|
last if $p0 < 0; |
|
71
|
|
|
|
|
|
|
|
|
72
|
13
|
|
|
|
|
156
|
my $cx = substr($$mbody, $p1,); |
|
73
|
13
|
|
|
|
|
41
|
my $p2 = index($cx,, "\n\n"); |
|
74
|
13
|
|
|
|
|
82
|
my $cv = substr($cx, $p2 + 2,); |
|
75
|
13
|
|
|
|
|
80
|
$emailparts = Sisimai::RFC5322->part(\$cv, [$ct], 0); |
|
76
|
13
|
|
|
|
|
38
|
last; |
|
77
|
|
|
|
|
|
|
} |
|
78
|
|
|
|
|
|
|
|
|
79
|
855
|
100
|
|
|
|
4260
|
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
|
169
|
|
|
|
|
332
|
my $cv = "\n\nReporting-MTA:"; |
|
83
|
169
|
|
|
|
|
361
|
my $e0 = $emailparts->[0]; |
|
84
|
169
|
|
|
|
|
352
|
my $p0 = index($e0, $cv); |
|
85
|
169
|
100
|
|
|
|
933
|
$emailparts->[0] = sprintf("%s\n\n%s%s", substr($e0, 0, $p0), $startingof->{"message"}->[0], substr($e0, $p0,)) if $p0 > 0; |
|
86
|
|
|
|
|
|
|
} |
|
87
|
|
|
|
|
|
|
|
|
88
|
855
|
|
|
|
|
2273
|
for my $e ("Final-Recipient", "Original-Recipient") { |
|
89
|
|
|
|
|
|
|
# Fix the malformed field "Final-Recipient: " |
|
90
|
1710
|
|
|
|
|
2895
|
my $cv = "\n".$e.": "; |
|
91
|
1710
|
|
|
|
|
2425
|
my $cx = $cv."<"; |
|
92
|
1710
|
100
|
|
|
|
3650
|
my $p0 = index($emailparts->[0], $cx); next if $p0 < 0; |
|
|
1710
|
|
|
|
|
4159
|
|
|
93
|
|
|
|
|
|
|
|
|
94
|
26
|
|
|
|
|
126
|
substr($emailparts->[0], $p0, length($cv) + 1, $cv."rfc822; "); |
|
95
|
26
|
|
|
|
|
66
|
my $p1 = index($emailparts->[0], ">\n", $p0 + 2); substr($emailparts->[0], $p1, 1, ""); |
|
|
26
|
|
|
|
|
116
|
|
|
96
|
|
|
|
|
|
|
} |
|
97
|
|
|
|
|
|
|
|
|
98
|
855
|
|
|
|
|
9376
|
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
|
18016
|
100
|
|
|
|
30522
|
if( $readcursor == 0 ) { |
|
102
|
|
|
|
|
|
|
# Beginning of the bounce message or message/delivery-status part |
|
103
|
11169
|
100
|
|
|
|
29515
|
$readcursor |= $indicators->{'deliverystatus'} if index($e, $startingof->{'message'}->[0]) == 0; |
|
104
|
|
|
|
|
|
|
|
|
105
|
11169
|
|
|
|
|
12233
|
while(1) { |
|
106
|
|
|
|
|
|
|
# Append each string before startingof["message"][0] except the following patterns |
|
107
|
|
|
|
|
|
|
# for the later reference |
|
108
|
11169
|
100
|
66
|
|
|
29850
|
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
|
7369
|
100
|
|
|
|
10634
|
if( grep { index($e, $_) == 0 } @$isboundary ) { $goestonext = 0; last } |
|
|
7369
|
|
|
|
|
21561
|
|
|
|
988
|
|
|
|
|
2620
|
|
|
|
988
|
|
|
|
|
1293
|
|
|
113
|
6381
|
100
|
|
|
|
13323
|
if( index($e, "Content-Type:") == 0 ) { |
|
114
|
|
|
|
|
|
|
# Content-Type: field in multipart/* |
|
115
|
825
|
50
|
|
|
|
3717
|
if( index($e, "multipart/") > 0 ) { |
|
|
|
50
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
# Content-Type: multipart/alternative; boundary=aa00220022222222ffeebb |
|
117
|
|
|
|
|
|
|
# Pick the boundary string and store it into "isboucdary" |
|
118
|
0
|
|
|
|
|
0
|
push @$isboundary, Sisimai::RFC2045->boundary($e, 0); |
|
119
|
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
} elsif( index($e, "text/plain") ) { |
|
121
|
|
|
|
|
|
|
# Content-Type: "text/plain" |
|
122
|
825
|
|
|
|
|
1737
|
$goestonext = 0; |
|
123
|
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
} else { |
|
125
|
|
|
|
|
|
|
# Other types: for example, text/html, image/jpg, and so on |
|
126
|
0
|
|
|
|
|
0
|
$goestonext = 1; |
|
127
|
|
|
|
|
|
|
} |
|
128
|
825
|
|
|
|
|
1436
|
last; |
|
129
|
|
|
|
|
|
|
} |
|
130
|
|
|
|
|
|
|
|
|
131
|
5556
|
100
|
|
|
|
9955
|
last if index($e, "Content-") == 0; # Content-Disposition, ... |
|
132
|
5531
|
100
|
|
|
|
10122
|
last if index($e, "This is a MIME") == 0; # This is a MIME-formatted message. |
|
133
|
5351
|
100
|
|
|
|
10008
|
last if index($e, "This is a multi") == 0; # This is a multipart message in MIME format |
|
134
|
5263
|
100
|
|
|
|
9821
|
last if index($e, "This is an auto") == 0; # This is an automatically generated ... |
|
135
|
5143
|
100
|
|
|
|
11904
|
last if index($e, "This multi-part") == 0; # This multi-part MIME message contains... |
|
136
|
5138
|
100
|
|
|
|
11072
|
last if index($e, "###") == 0; # A frame like ##### |
|
137
|
5128
|
50
|
|
|
|
9204
|
last if index($e, "***") == 0; # A frame like ***** |
|
138
|
5128
|
100
|
|
|
|
12188
|
last if index($e, "--") == 0; # Boundary string |
|
139
|
5095
|
100
|
|
|
|
8635
|
last if index($e, "--- The follow") > -1; # ----- The following addresses had delivery problems ----- |
|
140
|
5030
|
100
|
|
|
|
9088
|
last if index($e, "--- Transcript") > -1; # ----- Transcript of session follows ----- |
|
141
|
5007
|
|
|
|
|
8111
|
$beforemesg .= $e." "; last; |
|
|
5007
|
|
|
|
|
6669
|
|
|
142
|
|
|
|
|
|
|
} |
|
143
|
11169
|
|
|
|
|
13235
|
next; |
|
144
|
|
|
|
|
|
|
} |
|
145
|
6847
|
100
|
66
|
|
|
28859
|
next if ($readcursor & $indicators->{'deliverystatus'}) == 0 || $e eq ""; |
|
146
|
|
|
|
|
|
|
|
|
147
|
5968
|
100
|
|
|
|
24033
|
if( my $f = Sisimai::RFC1894->match($e) ) { |
|
148
|
|
|
|
|
|
|
# $e matched with any field defined in RFC3464 |
|
149
|
5247
|
100
|
|
|
|
14002
|
next unless my $o = Sisimai::RFC1894->field($e); |
|
150
|
5082
|
|
|
|
|
10096
|
$v = $dscontents->[-1]; |
|
151
|
|
|
|
|
|
|
|
|
152
|
5082
|
100
|
|
|
|
12342
|
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
|
|
|
|
2530
|
if( $o->[0] eq "final-recipient" ) { |
|
156
|
|
|
|
|
|
|
# Final-Recipient: rfc822; kijitora@example.jp |
|
157
|
|
|
|
|
|
|
# Final-Recipient: x400; /PN=... |
|
158
|
745
|
50
|
|
|
|
6024
|
my $cv = Sisimai::Address->s3s4($o->[2]); next unless Sisimai::Address->is_emailaddress($cv); |
|
|
745
|
|
|
|
|
3316
|
|
|
159
|
745
|
50
|
33
|
|
|
2210
|
my $cw = scalar @$dscontents; next if $cw > 0 && $cv eq $dscontents->[$cw - 1]->{'recipient'}; |
|
|
745
|
|
|
|
|
5125
|
|
|
160
|
|
|
|
|
|
|
|
|
161
|
745
|
100
|
|
|
|
1993
|
if( $v->{'recipient'} ) { |
|
162
|
|
|
|
|
|
|
# There are multiple recipient addresses in the message body. |
|
163
|
32
|
|
|
|
|
177
|
push @$dscontents, Sisimai::Lhost->DELIVERYSTATUS; |
|
164
|
32
|
|
|
|
|
94
|
$v = $dscontents->[-1]; |
|
165
|
|
|
|
|
|
|
} |
|
166
|
745
|
|
|
|
|
1840
|
$v->{'recipient'} = $cv; |
|
167
|
745
|
|
|
|
|
2625
|
$recipients++; |
|
168
|
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
} else { |
|
170
|
|
|
|
|
|
|
# X-Actual-Recipient: rfc822; kijitora@example.co.jp |
|
171
|
212
|
|
|
|
|
866
|
$v->{'alias'} = $o->[2]; |
|
172
|
|
|
|
|
|
|
} |
|
173
|
|
|
|
|
|
|
} elsif( $o->[3] eq "code" ) { |
|
174
|
|
|
|
|
|
|
# Diagnostic-Code: SMTP; 550 5.1.1 ... User Unknown |
|
175
|
670
|
|
|
|
|
1923
|
$v->{'spec'} = $o->[1]; |
|
176
|
670
|
|
|
|
|
2732
|
$v->{'diagnosis'} .= $o->[2]." "; |
|
177
|
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
} else { |
|
179
|
|
|
|
|
|
|
# Other DSN fields defined in RFC3464 |
|
180
|
3455
|
100
|
|
|
|
7382
|
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
|
|
|
|
|
1851
|
$v->{'diagnosis'} .= " ".$o->[4]." "; |
|
185
|
|
|
|
|
|
|
} |
|
186
|
3455
|
50
|
|
|
|
8871
|
next unless exists $fieldtable->{ $o->[0] }; |
|
187
|
3455
|
100
|
100
|
|
|
13939
|
next if $o->[3] eq "host" && Sisimai::RFC1123->is_internethost($o->[2]) == 0; |
|
188
|
|
|
|
|
|
|
|
|
189
|
3215
|
|
|
|
|
9553
|
$v->{ $fieldtable->{ $o->[0] } } = $o->[2]; |
|
190
|
3215
|
100
|
|
|
|
8728
|
next unless $f == 1; |
|
191
|
1292
|
|
|
|
|
5390
|
$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
|
721
|
100
|
66
|
|
|
3377
|
if( index($e, "X-") == 0 && index($e, ": ") > 1 ) { |
|
196
|
|
|
|
|
|
|
# This line is a MTA-Specific fields begins with "X-" |
|
197
|
238
|
100
|
|
|
|
1381
|
next unless Sisimai::RFC3464::ThirdParty->is3rdparty($e); |
|
198
|
|
|
|
|
|
|
|
|
199
|
32
|
|
|
|
|
89
|
my $cv = Sisimai::RFC3464::ThirdParty->xfield($e); |
|
200
|
32
|
100
|
66
|
|
|
142
|
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
|
|
|
|
86
|
$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
|
|
|
|
|
151
|
|
|
207
|
16
|
|
33
|
|
|
55
|
$v->{ $z } ||= $cv->[2]; |
|
208
|
|
|
|
|
|
|
} |
|
209
|
|
|
|
|
|
|
} else { |
|
210
|
|
|
|
|
|
|
# The line may be a continued line of the value of the Diagnostic-Code: field |
|
211
|
483
|
100
|
|
|
|
1570
|
if( index($p, 'Diagnostic-Code:') < 0 ) { |
|
212
|
|
|
|
|
|
|
# In the case of multiple "message/delivery-status" line |
|
213
|
274
|
100
|
|
|
|
833
|
next if index($e, "Content-") == 0; # Content-Disposition:, ... |
|
214
|
254
|
100
|
|
|
|
878
|
next if index($e, "--") == 0; # Boundary string |
|
215
|
207
|
|
|
|
|
512
|
$beforemesg .= $e." "; next |
|
216
|
207
|
|
|
|
|
416
|
} |
|
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
|
|
|
|
857
|
next unless index($e, " ") == 0; |
|
221
|
176
|
|
|
|
|
817
|
$v->{'diagnosis'} .= " ".Sisimai::String->sweep($e); |
|
222
|
|
|
|
|
|
|
} |
|
223
|
|
|
|
|
|
|
} |
|
224
|
|
|
|
|
|
|
} continue { |
|
225
|
|
|
|
|
|
|
# Save the current line for the next loop |
|
226
|
18016
|
|
|
|
|
31411
|
$p = $e; |
|
227
|
|
|
|
|
|
|
} |
|
228
|
|
|
|
|
|
|
|
|
229
|
855
|
|
|
|
|
5070
|
while( $recipients == 0 ) { |
|
230
|
|
|
|
|
|
|
# There is no valid recipient address, Try to use the alias addaress as a final recipient |
|
231
|
142
|
100
|
|
|
|
590
|
last unless length $dscontents->[0]->{'alias'} > 0; |
|
232
|
26
|
50
|
|
|
|
242
|
last unless Sisimai::Address->is_emailaddress($dscontents->[0]->{'alias'}); |
|
233
|
26
|
|
|
|
|
114
|
$dscontents->[0]->{'recipient'} = $dscontents->[0]->{'alias'}; |
|
234
|
26
|
|
|
|
|
399
|
$recipients++; |
|
235
|
|
|
|
|
|
|
} |
|
236
|
855
|
100
|
|
|
|
3746
|
return undef unless $recipients; |
|
237
|
|
|
|
|
|
|
|
|
238
|
739
|
|
|
|
|
5511
|
require Sisimai::SMTP::Reply; |
|
239
|
739
|
|
|
|
|
3093
|
require Sisimai::SMTP::Status; |
|
240
|
739
|
|
|
|
|
3000
|
require Sisimai::SMTP::Command; |
|
241
|
|
|
|
|
|
|
|
|
242
|
739
|
100
|
|
|
|
2417
|
if( $beforemesg ne "" ) { |
|
243
|
|
|
|
|
|
|
# Pick some values of $dscontents from the string before $startingof->{'message'} |
|
244
|
729
|
|
|
|
|
2314
|
$beforemesg = Sisimai::String->sweep($beforemesg); |
|
245
|
729
|
|
|
|
|
7429
|
$alternates->{'command'} = Sisimai::SMTP::Command->find($beforemesg); |
|
246
|
729
|
|
|
|
|
6291
|
$alternates->{'replycode'} = Sisimai::SMTP::Reply->find($beforemesg, $dscontents->[0]->{'status'}); |
|
247
|
729
|
|
|
|
|
6146
|
$alternates->{'status'} = Sisimai::SMTP::Status->find($beforemesg, $alternates->{'replycode'}); |
|
248
|
|
|
|
|
|
|
} |
|
249
|
739
|
|
|
|
|
3028
|
my $issuedcode = lc $beforemesg; |
|
250
|
|
|
|
|
|
|
|
|
251
|
739
|
|
|
|
|
1794
|
for my $e ( @$dscontents ) { |
|
252
|
|
|
|
|
|
|
# Set default values stored in "permessage" if each value in "dscontents" is empty. |
|
253
|
771
|
|
50
|
|
|
4790
|
$e->{ $_ } ||= $permessage->{ $_ } || '' for keys %$permessage; |
|
|
|
|
66
|
|
|
|
|
|
254
|
771
|
|
|
|
|
3696
|
$e->{'diagnosis'} = Sisimai::String->sweep($e->{'diagnosis'}); |
|
255
|
771
|
|
|
|
|
2496
|
my $lowercased = lc $e->{'diagnosis'}; |
|
256
|
|
|
|
|
|
|
|
|
257
|
771
|
100
|
|
|
|
2089
|
if( $recipients == 1 ) { |
|
258
|
|
|
|
|
|
|
# Do not mix the error message of each recipient with "beforemesg" when there is |
|
259
|
|
|
|
|
|
|
# multiple recipient addresses in the bounce message |
|
260
|
712
|
100
|
|
|
|
2375
|
if( index($issuedcode, $lowercased) > -1 ) { |
|
261
|
|
|
|
|
|
|
# $beforemesg contains the entire strings of $e->{'diagnosis'} |
|
262
|
115
|
|
|
|
|
300
|
$e->{'diagnosis'} = $beforemesg; |
|
263
|
|
|
|
|
|
|
|
|
264
|
|
|
|
|
|
|
} else { |
|
265
|
|
|
|
|
|
|
# The value of $e->{'diagnosis'} is not contained in $beforemesg |
|
266
|
|
|
|
|
|
|
# There may be an important error message in $beforemesg |
|
267
|
597
|
|
|
|
|
3092
|
$e->{'diagnosis'} = Sisimai::String->sweep(sprintf("%s %s", $beforemesg, $e->{'diagnosis'})) |
|
268
|
|
|
|
|
|
|
} |
|
269
|
|
|
|
|
|
|
} |
|
270
|
771
|
|
100
|
|
|
3177
|
$e->{'command'} = Sisimai::SMTP::Command->find($e->{'diagnosis'}) || $alternates->{'command'}; |
|
271
|
771
|
|
66
|
|
|
3475
|
$e->{'replycode'} = Sisimai::SMTP::Reply->find($e->{'diagnosis'}, $e->{'status'}) || $alternates->{'replycode'}; |
|
272
|
771
|
|
66
|
|
|
2880
|
$e->{'status'} ||= Sisimai::SMTP::Status->find($e->{'diagnosis'}, $e->{'replycode'}) || $alternates->{'status'}; |
|
|
|
|
100
|
|
|
|
|
|
273
|
|
|
|
|
|
|
} |
|
274
|
|
|
|
|
|
|
|
|
275
|
|
|
|
|
|
|
# Set the recipient address as To: header in the original message part |
|
276
|
739
|
100
|
|
|
|
2530
|
$emailparts->[1] = sprintf("To: <%s>\n", $dscontents->[0]->{'recipient'}) unless $emailparts->[1]; |
|
277
|
|
|
|
|
|
|
|
|
278
|
739
|
|
|
|
|
9547
|
return {"ds" => $dscontents, "rfc822" => $emailparts->[1]}; |
|
279
|
|
|
|
|
|
|
} |
|
280
|
|
|
|
|
|
|
|
|
281
|
|
|
|
|
|
|
1; |
|
282
|
|
|
|
|
|
|
|
|
283
|
|
|
|
|
|
|
__END__ |