sisimai 4.25.17-java → 5.0.0-java
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/.travis.yml +3 -3
- data/ANALYTICAL-PRECISION +2 -2
- data/Benchmarks.mk +3 -3
- data/CONTRIBUTING +1 -1
- data/ChangeLog.md +406 -407
- data/Developers.mk +5 -6
- data/Gemfile +1 -1
- data/Makefile +12 -12
- data/README-JA.md +142 -94
- data/README.md +282 -150
- data/Rakefile +9 -3
- data/Repository.mk +2 -3
- data/lib/sisimai/address.rb +118 -74
- data/lib/sisimai/arf.rb +84 -82
- data/lib/sisimai/datetime.rb +5 -52
- data/lib/sisimai/{data → fact}/json.rb +7 -9
- data/lib/sisimai/fact/yaml.rb +31 -0
- data/lib/sisimai/fact.rb +468 -0
- data/lib/sisimai/lhost/activehunter.rb +12 -14
- data/lib/sisimai/lhost/amavis.rb +11 -14
- data/lib/sisimai/lhost/amazonses.rb +37 -41
- data/lib/sisimai/lhost/amazonworkmail.rb +15 -18
- data/lib/sisimai/lhost/aol.rb +12 -14
- data/lib/sisimai/lhost/apachejames.rb +19 -21
- data/lib/sisimai/lhost/barracuda.rb +10 -12
- data/lib/sisimai/lhost/bigfoot.rb +21 -21
- data/lib/sisimai/lhost/biglobe.rb +15 -16
- data/lib/sisimai/lhost/courier.rb +20 -20
- data/lib/sisimai/lhost/domino.rb +23 -19
- data/lib/sisimai/lhost/einsundeins.rb +20 -16
- data/lib/sisimai/lhost/exchange2003.rb +30 -29
- data/lib/sisimai/lhost/exchange2007.rb +70 -58
- data/lib/sisimai/lhost/exim.rb +175 -161
- data/lib/sisimai/lhost/ezweb.rb +31 -56
- data/lib/sisimai/lhost/facebook.rb +21 -33
- data/lib/sisimai/lhost/fml.rb +43 -48
- data/lib/sisimai/lhost/gmail.rb +29 -29
- data/lib/sisimai/lhost/gmx.rb +18 -17
- data/lib/sisimai/lhost/googlegroups.rb +9 -10
- data/lib/sisimai/lhost/gsuite.rb +21 -27
- data/lib/sisimai/lhost/imailserver.rb +25 -39
- data/lib/sisimai/lhost/interscanmss.rb +28 -31
- data/lib/sisimai/lhost/kddi.rb +22 -28
- data/lib/sisimai/lhost/mailfoundry.rb +11 -12
- data/lib/sisimai/lhost/mailmarshalsmtp.rb +25 -29
- data/lib/sisimai/lhost/mailru.rb +33 -27
- data/lib/sisimai/lhost/mcafee.rb +21 -31
- data/lib/sisimai/lhost/messagelabs.rb +17 -20
- data/lib/sisimai/lhost/messagingserver.rb +40 -37
- data/lib/sisimai/lhost/mfilter.rb +15 -16
- data/lib/sisimai/lhost/mxlogic.rb +24 -23
- data/lib/sisimai/lhost/notes.rb +17 -17
- data/lib/sisimai/lhost/office365.rb +63 -27
- data/lib/sisimai/lhost/opensmtpd.rb +12 -13
- data/lib/sisimai/lhost/outlook.rb +12 -15
- data/lib/sisimai/lhost/postfix.rb +179 -129
- data/lib/sisimai/lhost/powermta.rb +12 -14
- data/lib/sisimai/lhost/qmail.rb +44 -47
- data/lib/sisimai/lhost/receivingses.rb +15 -20
- data/lib/sisimai/lhost/sendgrid.rb +34 -32
- data/lib/sisimai/lhost/sendmail.rb +66 -53
- data/lib/sisimai/lhost/surfcontrol.rb +19 -19
- data/lib/sisimai/lhost/v5sendmail.rb +45 -39
- data/lib/sisimai/lhost/verizon.rb +35 -39
- data/lib/sisimai/lhost/x1.rb +18 -17
- data/lib/sisimai/lhost/x2.rb +17 -14
- data/lib/sisimai/lhost/x3.rb +19 -19
- data/lib/sisimai/lhost/x4.rb +72 -57
- data/lib/sisimai/lhost/x5.rb +17 -19
- data/lib/sisimai/lhost/x6.rb +41 -17
- data/lib/sisimai/lhost/yahoo.rb +17 -16
- data/lib/sisimai/lhost/yandex.rb +16 -20
- data/lib/sisimai/lhost/zoho.rb +16 -15
- data/lib/sisimai/lhost.rb +8 -10
- data/lib/sisimai/mail/maildir.rb +1 -3
- data/lib/sisimai/mail/mbox.rb +3 -4
- data/lib/sisimai/mail/memory.rb +0 -1
- data/lib/sisimai/mail/stdin.rb +1 -3
- data/lib/sisimai/mail.rb +3 -7
- data/lib/sisimai/mda.rb +28 -42
- data/lib/sisimai/message.rb +435 -325
- data/lib/sisimai/order.rb +5 -5
- data/lib/sisimai/reason/authfailure.rb +64 -0
- data/lib/sisimai/reason/badreputation.rb +53 -0
- data/lib/sisimai/reason/blocked.rb +94 -160
- data/lib/sisimai/reason/contenterror.rb +8 -9
- data/lib/sisimai/reason/delivered.rb +4 -6
- data/lib/sisimai/reason/exceedlimit.rb +10 -12
- data/lib/sisimai/reason/expired.rb +6 -8
- data/lib/sisimai/reason/feedback.rb +2 -3
- data/lib/sisimai/reason/filtered.rb +17 -19
- data/lib/sisimai/reason/hasmoved.rb +9 -10
- data/lib/sisimai/reason/hostunknown.rb +15 -15
- data/lib/sisimai/reason/mailboxfull.rb +10 -12
- data/lib/sisimai/reason/mailererror.rb +18 -20
- data/lib/sisimai/reason/mesgtoobig.rb +9 -11
- data/lib/sisimai/reason/networkerror.rb +5 -8
- data/lib/sisimai/reason/norelaying.rb +8 -11
- data/lib/sisimai/reason/notaccept.rb +13 -14
- data/lib/sisimai/reason/notcompliantrfc.rb +43 -0
- data/lib/sisimai/reason/onhold.rb +6 -9
- data/lib/sisimai/reason/policyviolation.rb +14 -12
- data/lib/sisimai/reason/rejected.rb +26 -24
- data/lib/sisimai/reason/requireptr.rb +69 -0
- data/lib/sisimai/reason/securityerror.rb +33 -36
- data/lib/sisimai/reason/spamdetected.rb +114 -147
- data/lib/sisimai/reason/speeding.rb +49 -0
- data/lib/sisimai/reason/suspend.rb +11 -11
- data/lib/sisimai/reason/syntaxerror.rb +11 -10
- data/lib/sisimai/reason/systemerror.rb +7 -9
- data/lib/sisimai/reason/systemfull.rb +7 -8
- data/lib/sisimai/reason/toomanyconn.rb +9 -11
- data/lib/sisimai/reason/undefined.rb +2 -3
- data/lib/sisimai/reason/userunknown.rb +129 -146
- data/lib/sisimai/reason/vacation.rb +3 -4
- data/lib/sisimai/reason/virusdetected.rb +10 -11
- data/lib/sisimai/reason.rb +59 -64
- data/lib/sisimai/rfc1894.rb +55 -28
- data/lib/sisimai/rfc2045.rb +373 -0
- data/lib/sisimai/rfc3464.rb +250 -308
- data/lib/sisimai/rfc3834.rb +42 -45
- data/lib/sisimai/rfc5322.rb +75 -100
- data/lib/sisimai/rfc5965.rb +31 -0
- data/lib/sisimai/rhost/cox.rb +5 -6
- data/lib/sisimai/rhost/franceptt.rb +6 -8
- data/lib/sisimai/rhost/godaddy.rb +12 -12
- data/lib/sisimai/rhost/{googleapps.rb → google.rb} +80 -72
- data/lib/sisimai/rhost/iua.rb +9 -10
- data/lib/sisimai/rhost/kddi.rb +6 -8
- data/lib/sisimai/rhost/{exchangeonline.rb → microsoft.rb} +115 -114
- data/lib/sisimai/rhost/mimecast.rb +42 -40
- data/lib/sisimai/rhost/nttdocomo.rb +13 -18
- data/lib/sisimai/rhost/spectrum.rb +10 -12
- data/lib/sisimai/rhost/{tencentqq.rb → tencent.rb} +7 -8
- data/lib/sisimai/rhost.rb +23 -31
- data/lib/sisimai/smtp/command.rb +59 -0
- data/lib/sisimai/smtp/error.rb +4 -7
- data/lib/sisimai/smtp/reply.rb +161 -74
- data/lib/sisimai/smtp/status.rb +504 -393
- data/lib/sisimai/smtp/transcript.rb +124 -0
- data/lib/sisimai/smtp.rb +0 -1
- data/lib/sisimai/string.rb +74 -5
- data/lib/sisimai/time.rb +1 -2
- data/lib/sisimai/version.rb +1 -1
- data/lib/sisimai.rb +35 -21
- data/set-of-emails/maildir/bsd/lhost-domino-02.eml +6 -3
- data/set-of-emails/maildir/bsd/lhost-googlegroups-15.eml +174 -0
- data/set-of-emails/maildir/bsd/lhost-gsuite-15.eml +229 -0
- data/set-of-emails/maildir/bsd/lhost-postfix-75.eml +51 -0
- data/set-of-emails/maildir/bsd/lhost-postfix-76.eml +101 -0
- data/set-of-emails/maildir/bsd/lhost-postfix-77.eml +74 -0
- data/set-of-emails/maildir/bsd/lhost-postfix-78.eml +91 -0
- data/set-of-emails/maildir/bsd/lhost-receivingses-08.eml +88 -0
- data/set-of-emails/maildir/bsd/rfc3464-43.eml +88 -0
- data/set-of-emails/maildir/bsd/rhost-google-03.eml +101 -0
- data/set-of-emails/maildir/bsd/rhost-google-04.eml +102 -0
- data/set-of-emails/maildir/bsd/rhost-google-05.eml +82 -0
- data/set-of-emails/maildir/bsd/rhost-google-06.eml +102 -0
- data/set-of-emails/maildir/bsd/rhost-google-07.eml +69 -0
- data/set-of-emails/maildir/bsd/rhost-google-08.eml +99 -0
- data/sisimai-java.gemspec +1 -1
- data/sisimai.gemspec +1 -1
- metadata +42 -23
- data/.rspec +0 -2
- data/lib/sisimai/data/yaml.rb +0 -33
- data/lib/sisimai/data.rb +0 -411
- data/lib/sisimai/mime.rb +0 -456
- data/set-of-emails/maildir/mac/reported-from-nick4tech-san-01.eml +0 -6
- /data/set-of-emails/maildir/bsd/{rfc3464-41.eml → rfc3834-05.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{rhost-googleapps-01.eml → rhost-google-01.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{rhost-googleapps-02.eml → rhost-google-02.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{rhost-exchangeonline-01.eml → rhost-microsoft-01.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{rhost-exchangeonline-02.eml → rhost-microsoft-02.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{rhost-exchangeonline-03.eml → rhost-microsoft-03.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{rhost-tencentqq-01.eml → rhost-tencent-01.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{rhost-tencentqq-02.eml → rhost-tencent-02.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{rhost-tencentqq-03.eml → rhost-tencent-03.eml} +0 -0
data/lib/sisimai/lhost/exim.rb
CHANGED
@@ -1,24 +1,21 @@
|
|
1
1
|
module Sisimai::Lhost
|
2
|
-
# Sisimai::Lhost::Exim parses a bounce email which created by Exim.
|
3
|
-
#
|
2
|
+
# Sisimai::Lhost::Exim parses a bounce email which created by Exim. Methods in the module are called
|
3
|
+
# from only Sisimai::Message.
|
4
4
|
module Exim
|
5
5
|
class << self
|
6
|
-
# Imported from p5-Sisimail/lib/Sisimai/Lhost/Exim.pm
|
7
6
|
require 'sisimai/lhost'
|
8
7
|
|
9
8
|
Indicators = Sisimai::Lhost.INDICATORS
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
MarkingsOf = {
|
21
|
-
# Error text regular expressions which defined in exim/src/deliver.c
|
9
|
+
Boundaries = [
|
10
|
+
# deliver.c:6423| if (bounce_return_body) fprintf(f,
|
11
|
+
# deliver.c:6424|"------ This is a copy of the message, including all the headers. ------\n");
|
12
|
+
# deliver.c:6425| else fprintf(f,
|
13
|
+
# deliver.c:6426|"------ This is a copy of the message's headers. ------\n");
|
14
|
+
'------ This is a copy of the message, including all the headers. ------',
|
15
|
+
'Content-Type: message/rfc822',
|
16
|
+
].freeze
|
17
|
+
StartingOf = {
|
18
|
+
# Error text strings which defined in exim/src/deliver.c
|
22
19
|
#
|
23
20
|
# deliver.c:6292| fprintf(f,
|
24
21
|
# deliver.c:6293|"This message was created automatically by mail delivery software.\n");
|
@@ -35,19 +32,19 @@ module Sisimai::Lhost
|
|
35
32
|
# deliver.c:6304|"could not be delivered to one or more of its recipients. The following\n"
|
36
33
|
# deliver.c:6305|"address(es) failed:\n", sender_address);
|
37
34
|
# deliver.c:6306| }
|
38
|
-
|
39
|
-
frozen:
|
40
|
-
message:
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
)
|
48
|
-
|
35
|
+
deliverystatus: ['Content-Type: message/delivery-status'],
|
36
|
+
frozen: [' has been frozen', ' was frozen on arrival'],
|
37
|
+
message: [
|
38
|
+
'This message was created automatically by mail delivery software.',
|
39
|
+
'A message that you sent was rejected by the local scannning code',
|
40
|
+
'A message that you sent contained one or more recipient addresses ',
|
41
|
+
'A message that you sent could not be delivered to all of its recipients',
|
42
|
+
' has been frozen',
|
43
|
+
' was frozen on arrival',
|
44
|
+
' router encountered the following error(s):',
|
45
|
+
],
|
49
46
|
}.freeze
|
50
|
-
|
47
|
+
MarkingsOf = { alias: ' an undisclosed address' }.freeze
|
51
48
|
ReCommands = [
|
52
49
|
# transports/smtp.c:564| *message = US string_sprintf("SMTP error from remote mail server after %s%s: "
|
53
50
|
# transports/smtp.c:837| string_sprintf("SMTP error from remote mail server after RCPT TO:<%s>: "
|
@@ -125,30 +122,28 @@ module Sisimai::Lhost
|
|
125
122
|
# @param [String] mbody Message body of a bounce email
|
126
123
|
# @return [Hash] Bounce data list and message/rfc822 part
|
127
124
|
# @return [Nil] it failed to parse or the arguments are missing
|
128
|
-
def
|
129
|
-
return nil if mhead['from']
|
125
|
+
def inquire(mhead, mbody)
|
126
|
+
return nil if mhead['from'].include?('.mail.ru')
|
130
127
|
|
131
128
|
# Message-Id: <E1P1YNN-0003AD-Ga@example.org>
|
132
129
|
# X-Failed-Recipients: kijitora@example.ed.jp
|
133
130
|
match = 0
|
131
|
+
msgid = mhead['message-id'] || ''
|
134
132
|
match += 1 if mhead['from'].start_with?('Mail Delivery System')
|
135
|
-
match += 1 if
|
136
|
-
match += 1 if
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
)
|
144
|
-
}x
|
133
|
+
match += 1 if msgid.start_with?('<') && msgid.index('-') == 8 && msgid.index('@') == 18
|
134
|
+
match += 1 if %w[
|
135
|
+
'Delivery Status Notification',
|
136
|
+
'Mail delivery failed',
|
137
|
+
'Mail failure',
|
138
|
+
'Message frozen',
|
139
|
+
'Warning: message ',
|
140
|
+
'error(s) in forwarding or filtering'].any? { |a| mhead['subject'].include?(a) }
|
145
141
|
return nil if match < 2
|
146
142
|
|
147
|
-
require 'sisimai/rfc1894'
|
148
143
|
fieldtable = Sisimai::RFC1894.FIELDTABLE
|
149
144
|
dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
|
150
|
-
|
151
|
-
bodyslices =
|
145
|
+
emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
|
146
|
+
bodyslices = emailparts[0].split("\n")
|
152
147
|
readcursor = 0 # (Integer) Points the current cursor position
|
153
148
|
nextcursor = 0
|
154
149
|
recipients = 0 # (Integer) The number of 'Final-Recipient' header
|
@@ -157,19 +152,18 @@ module Sisimai::Lhost
|
|
157
152
|
v = nil
|
158
153
|
|
159
154
|
if mhead['content-type']
|
160
|
-
# Get the boundary string and set regular expression for matching with
|
161
|
-
|
162
|
-
boundary00 = Sisimai::MIME.boundary(mhead['content-type']) || ''
|
155
|
+
# Get the boundary string and set regular expression for matching with the boundary string.
|
156
|
+
boundary00 = Sisimai::RFC2045.boundary(mhead['content-type']) || ''
|
163
157
|
end
|
164
158
|
|
165
159
|
while e = bodyslices.shift do
|
166
|
-
# Read error messages and delivery status lines from the head of the email
|
167
|
-
#
|
160
|
+
# Read error messages and delivery status lines from the head of the email to the previous
|
161
|
+
# line of the beginning of the original message.
|
168
162
|
if readcursor == 0
|
169
163
|
# Beginning of the bounce message or message/delivery-status part
|
170
|
-
if
|
164
|
+
if StartingOf[:message].any? { |a| e.include?(a) }
|
171
165
|
readcursor |= Indicators[:deliverystatus]
|
172
|
-
next unless
|
166
|
+
next unless StartingOf[:frozen].any? { |a| e.include?(a) }
|
173
167
|
end
|
174
168
|
end
|
175
169
|
next if (readcursor & Indicators[:deliverystatus]) == 0
|
@@ -185,109 +179,130 @@ module Sisimai::Lhost
|
|
185
179
|
# host neko.example.jp [192.0.2.222]: 550 5.1.1 <kijitora@example.jp>... User Unknown
|
186
180
|
v = dscontents[-1]
|
187
181
|
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
#
|
192
|
-
#
|
193
|
-
#
|
194
|
-
#
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
182
|
+
cv = ''
|
183
|
+
ce = false
|
184
|
+
while true
|
185
|
+
# Check if the line matche the following patterns:
|
186
|
+
break unless e.start_with?(' ') # The line should start with " " (2 spaces)
|
187
|
+
break unless e.include?('@') # "@" should be included (email)
|
188
|
+
break unless e.include?('.') # "." should be included (domain part)
|
189
|
+
break unless e.include?('pipe to |') == false # Exclude "pipe to /path/to/prog" line
|
190
|
+
|
191
|
+
break unless e[2, 1] != ' '
|
192
|
+
break unless e[2, 1] != '<'
|
193
|
+
ce = true
|
194
|
+
break
|
195
|
+
end
|
199
196
|
|
197
|
+
if ce || e.include?(MarkingsOf[:alias])
|
198
|
+
# The line is including an email address
|
200
199
|
if v['recipient']
|
201
200
|
# There are multiple recipient addresses in the message body.
|
202
201
|
dscontents << Sisimai::Lhost.DELIVERYSTATUS
|
203
202
|
v = dscontents[-1]
|
204
203
|
end
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
#
|
209
|
-
#
|
210
|
-
#
|
211
|
-
|
212
|
-
|
213
|
-
#
|
214
|
-
#
|
215
|
-
#
|
216
|
-
|
217
|
-
|
204
|
+
|
205
|
+
if e.include?(MarkingsOf[:alias])
|
206
|
+
# The line does not include an email address
|
207
|
+
# deliver.c:4549| printed = US"an undisclosed address";
|
208
|
+
# an undisclosed address
|
209
|
+
# (generated from kijitora@example.jp)
|
210
|
+
cv = e[2, e.size]
|
211
|
+
else
|
212
|
+
# kijitora@example.jp
|
213
|
+
# sabineko@example.jp: forced freeze
|
214
|
+
# mikeneko@example.jp <nekochan@example.org>: ...
|
215
|
+
p1 = e.index(' <') || -1
|
216
|
+
p2 = e.index('>:') || -1
|
217
|
+
|
218
|
+
if p1 > 1 && p2 > 1
|
219
|
+
# There are an email address and an error message in the line
|
220
|
+
# parser.c:743| while (bracket_count-- > 0) if (*s++ != '>')
|
221
|
+
# parser.c:744| {
|
222
|
+
# parser.c:745| *errorptr = s[-1] == 0
|
223
|
+
# parser.c:746| ? US"'>' missing at end of address"
|
224
|
+
# parser.c:747| : string_sprintf("malformed address: %.32s may not follow %.*s",
|
225
|
+
# parser.c:748| s-1, (int)(s - US mailbox - 1), mailbox);
|
226
|
+
# parser.c:749| goto PARSE_FAILED;
|
227
|
+
# parser.c:750| }
|
228
|
+
cv = Sisimai::Address.s3s4(e[p1 + 1, p2 - p1 - 1])
|
229
|
+
v['diagnosis'] = Sisimai::String.sweep(e[p2 + 1, e.size])
|
230
|
+
else
|
231
|
+
# There is an email address only in the line
|
232
|
+
# kijitora@example.jp
|
233
|
+
cv = Sisimai::Address.s3s4(e[2, e.size])
|
234
|
+
end
|
218
235
|
end
|
219
|
-
v['recipient'] =
|
236
|
+
v['recipient'] = cv
|
220
237
|
recipients += 1
|
221
238
|
|
222
|
-
elsif
|
223
|
-
e.match(/\A[ ]+generated[ ]by[ ]([^ \t]+[@][^ \t]+)/)
|
239
|
+
elsif e.include?(' (generated from ') || e.include?(' generated by ')
|
224
240
|
# (generated from kijitora@example.jp)
|
225
241
|
# pipe to |/bin/echo "Some pipe output"
|
226
242
|
# generated by userx@myhost.test.ex
|
227
|
-
v['alias'] =
|
243
|
+
v['alias'] = Sisimai::Address.s3s4(e[e.rindex(' ') + 1, e.size])
|
244
|
+
|
228
245
|
else
|
229
246
|
next if e.empty?
|
230
247
|
|
231
|
-
if
|
248
|
+
if StartingOf[:frozen].any? { |a| e.include?(a) }
|
232
249
|
# Message *** has been frozen by the system filter.
|
233
250
|
# Message *** was frozen on arrival by ACL.
|
234
251
|
v['alterrors'] ||= ''
|
235
252
|
v['alterrors'] << e + ' '
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
else
|
257
|
-
# Other DSN fields defined in RFC3464
|
258
|
-
next unless fieldtable[o[0]]
|
259
|
-
v[fieldtable[o[0]]] = o[2]
|
260
|
-
end
|
253
|
+
elsif !boundary00.empty?
|
254
|
+
# --NNNNNNNNNN-eximdsn-MMMMMMMMMM
|
255
|
+
# Content-type: message/delivery-status
|
256
|
+
# ...
|
257
|
+
if Sisimai::RFC1894.match(e)
|
258
|
+
# "e" matched with any field defined in RFC3464
|
259
|
+
next unless o = Sisimai::RFC1894.field(e)
|
260
|
+
|
261
|
+
if o[-1] == 'addr'
|
262
|
+
# Final-Recipient: rfc822; kijitora@example.jp
|
263
|
+
# X-Actual-Recipient: rfc822; kijitora@example.co.jp
|
264
|
+
next unless o[0] == 'final-recipient'
|
265
|
+
v['spec'] ||= o[2].include?('@') ? 'SMTP' : 'X-UNIX'
|
266
|
+
|
267
|
+
elsif o[-1] == 'code'
|
268
|
+
# Diagnostic-Code: SMTP; 550 5.1.1 <userunknown@example.jp>... User Unknown
|
269
|
+
v['spec'] = o[1]
|
270
|
+
v['diagnosis'] = o[2]
|
271
|
+
|
261
272
|
else
|
262
|
-
#
|
263
|
-
next
|
273
|
+
# Other DSN fields defined in RFC3464
|
274
|
+
next unless fieldtable[o[0]]
|
275
|
+
v[fieldtable[o[0]]] = o[2]
|
276
|
+
end
|
277
|
+
else
|
278
|
+
# Error message ?
|
279
|
+
next if nextcursor == 1
|
264
280
|
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
end
|
281
|
+
# Content-type: message/delivery-status
|
282
|
+
nextcursor = 1 if e.start_with?(StartingOf[:deliverystatus][0])
|
283
|
+
v['alterrors'] ||= ''
|
284
|
+
if e.start_with?("\s", "\t")
|
285
|
+
e.sub!(/\A[\s\t]+/, '')
|
286
|
+
v['alterrors'] << e + ' ' unless v['alterrors'].include?(e)
|
272
287
|
end
|
288
|
+
end
|
289
|
+
else
|
290
|
+
# There is no boundary string in $boundary00
|
291
|
+
if dscontents.size == recipients
|
292
|
+
# Error message
|
293
|
+
next if e.empty?
|
294
|
+
v['diagnosis'] ||= ''
|
295
|
+
v['diagnosis'] << e + ' '
|
273
296
|
else
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
v['diagnosis']
|
297
|
+
# Error message when email address above does not include '@' and domain part.
|
298
|
+
if e.include?(' pipe to |/')
|
299
|
+
# pipe to |/path/to/prog ...
|
300
|
+
# generated by kijitora@example.com
|
301
|
+
v['diagnosis'] = e
|
279
302
|
else
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
# pipe to |/path/to/prog ...
|
284
|
-
# generated by kijitora@example.com
|
285
|
-
v['diagnosis'] = e
|
286
|
-
else
|
287
|
-
next unless e.start_with?(' ')
|
288
|
-
v['alterrors'] ||= ''
|
289
|
-
v['alterrors'] << e + ' '
|
290
|
-
end
|
303
|
+
next unless e.start_with?(' ')
|
304
|
+
v['alterrors'] ||= ''
|
305
|
+
v['alterrors'] << e + ' '
|
291
306
|
end
|
292
307
|
end
|
293
308
|
end
|
@@ -330,7 +345,9 @@ module Sisimai::Lhost
|
|
330
345
|
unless mhead['received'].empty?
|
331
346
|
# Get the name of local MTA
|
332
347
|
# Received: from marutamachi.example.org (c192128.example.net [192.0.2.128])
|
333
|
-
|
348
|
+
p1 = mhead['received'][-1].index('from ') || -1
|
349
|
+
p2 = mhead['received'][-1].index(' ', p1 + 5) || -1
|
350
|
+
localhost0 = mhead['received'][-1][p1 + 5, p2 - p1 - 5] if p1 > -1 && p2 > -1
|
334
351
|
end
|
335
352
|
|
336
353
|
dscontents.each do |e|
|
@@ -371,25 +388,23 @@ module Sisimai::Lhost
|
|
371
388
|
if e['diagnosis'].start_with?('-') || e['diagnosis'].end_with?('__')
|
372
389
|
# Override the value of diagnostic code message
|
373
390
|
e['diagnosis'] = e['alterrors'] unless e['alterrors'].empty?
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
# Override the value of diagnostic code message because
|
380
|
-
# the value of alterrors includes the value of diagnosis.
|
381
|
-
e['diagnosis'] = e['alterrors'] if e['alterrors'].downcase.include?(e['diagnosis'].downcase)
|
382
|
-
end
|
391
|
+
|
392
|
+
elsif e['diagnosis'].size < e['alterrors'].size
|
393
|
+
# Override the value of diagnostic code message because the value of alterrors includes
|
394
|
+
# the value of diagnosis.
|
395
|
+
e['diagnosis'] = e['alterrors'] if e['alterrors'].downcase.include?(e['diagnosis'].downcase)
|
383
396
|
end
|
384
397
|
e.delete('alterrors')
|
385
398
|
end
|
386
|
-
e['diagnosis'] = Sisimai::String.sweep(e['diagnosis']) || ''
|
387
|
-
e['diagnosis']
|
399
|
+
e['diagnosis'] = Sisimai::String.sweep(e['diagnosis']) || ''; p1 = e['diagnosis'].index('__') || -1
|
400
|
+
e['diagnosis'] = e['diagnosis'][0, p1] if p1 > 1
|
388
401
|
|
389
402
|
unless e['rhost']
|
390
403
|
# Get the remote host name
|
391
404
|
# host neko.example.jp [192.0.2.222]: 550 5.1.1 <kijitora@example.jp>... User Unknown
|
392
|
-
|
405
|
+
p1 = e['diagnosis'].index('host ') || -1
|
406
|
+
p2 = e['diagnosis'].index(' ', p1 + 5) || -1
|
407
|
+
e['rhost'] = e['diagnosis'][p1 + 5, p2 - p1 - 5] if p1 > -1
|
393
408
|
|
394
409
|
unless e['rhost']
|
395
410
|
# Get localhost and remote host name from Received header.
|
@@ -426,55 +441,54 @@ module Sisimai::Lhost
|
|
426
441
|
|
427
442
|
unless e['reason']
|
428
443
|
# The reason "expired"
|
429
|
-
e['reason']
|
444
|
+
e['reason'] = 'expired' if DelayedFor.any? { |a| e['diagnosis'].include?(a) }
|
445
|
+
e['reason'] ||= 'mailererror' if e['diagnosis'].include?('pipe to |')
|
430
446
|
end
|
431
447
|
end
|
432
448
|
end
|
433
449
|
|
434
450
|
# Prefer the value of smtp reply code in Diagnostic-Code:
|
435
|
-
# See eg/maildir-as-a-sample/new/exim-20.eml
|
436
451
|
# Action: failed
|
437
452
|
# Final-Recipient: rfc822;userx@test.ex
|
438
453
|
# Status: 5.0.0
|
439
454
|
# Remote-MTA: dns; 127.0.0.1
|
440
455
|
# Diagnostic-Code: smtp; 450 TEMPERROR: retry timeout exceeded
|
441
|
-
#
|
442
|
-
# of SMTP reply code in
|
443
|
-
|
444
|
-
|
456
|
+
#
|
457
|
+
# The value of "Status:" indicates permanent error but the value of SMTP reply code in
|
458
|
+
# Diagnostic-Code: field is "TEMPERROR"!!!!
|
459
|
+
cs = e['status'] || Sisimai::SMTP::Status.find(e['diagnosis'])
|
460
|
+
cr = e['replycode'] || Sisimai::SMTP::Reply.find(e['diagnosis'])
|
445
461
|
s1 = 0 # First character of Status as integer
|
446
462
|
r1 = 0 # First character of SMTP reply code as integer
|
447
463
|
|
448
464
|
while true
|
449
465
|
# "Status:" field did not exist in the bounce message
|
450
|
-
break if
|
451
|
-
break unless
|
466
|
+
break if cs
|
467
|
+
break unless cr
|
452
468
|
|
453
|
-
# Check SMTP reply code
|
454
|
-
|
455
|
-
r1 = rv[0, 1].to_i
|
469
|
+
# Check SMTP reply code, Generate pseudo DSN code from SMTP reply code
|
470
|
+
r1 = cr[0, 1].to_i
|
456
471
|
if r1 == 4
|
457
472
|
# Get the internal DSN(temporary error)
|
458
|
-
|
473
|
+
cs = Sisimai::SMTP::Status.code(e['reason'], true)
|
459
474
|
|
460
475
|
elsif r1 == 5
|
461
476
|
# Get the internal DSN(permanent error)
|
462
|
-
|
477
|
+
cs = Sisimai::SMTP::Status.code(e['reason'], false)
|
463
478
|
end
|
464
479
|
break
|
465
480
|
end
|
466
481
|
|
467
|
-
s1 =
|
482
|
+
s1 = cs[0, 1].to_i if cs
|
468
483
|
v1 = s1 + r1
|
469
484
|
v1 << e['status'][0, 1].to_i if e['status']
|
470
485
|
|
471
486
|
if v1 > 0
|
472
|
-
# Status or SMTP reply code exists
|
473
|
-
|
474
|
-
e['status'] = sv if r1 > 0
|
487
|
+
# Status or SMTP reply code exists, Set pseudo DSN into the value of "status" accessor
|
488
|
+
e['status'] = cs if r1 > 0
|
475
489
|
else
|
476
490
|
# Neither Status nor SMTP reply code exist
|
477
|
-
|
491
|
+
cs = if %w[expired mailboxfull].include?(e['reason'])
|
478
492
|
# Set pseudo DSN (temporary error)
|
479
493
|
Sisimai::SMTP::Status.code(e['reason'], true)
|
480
494
|
else
|
@@ -482,10 +496,10 @@ module Sisimai::Lhost
|
|
482
496
|
Sisimai::SMTP::Status.code(e['reason'], false)
|
483
497
|
end
|
484
498
|
end
|
485
|
-
e['status'] ||=
|
499
|
+
e['status'] ||= cs.to_s
|
486
500
|
end
|
487
501
|
|
488
|
-
return { 'ds' => dscontents, 'rfc822' =>
|
502
|
+
return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
|
489
503
|
end
|
490
504
|
def description; return 'Exim'; end
|
491
505
|
end
|