sisimai 4.22.3-java → 4.22.4-java
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of sisimai might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/.travis.yml +1 -1
- data/Benchmarks.mk +54 -0
- data/ChangeLog.md +23 -2
- data/Developers.mk +42 -35
- data/Makefile +10 -0
- data/README-JA.md +13 -13
- data/README.md +14 -14
- data/lib/sisimai.rb +12 -18
- data/lib/sisimai/address.rb +64 -82
- data/lib/sisimai/arf.rb +27 -42
- data/lib/sisimai/bite/email.rb +2 -4
- data/lib/sisimai/bite/email/activehunter.rb +12 -17
- data/lib/sisimai/bite/email/amazonses.rb +30 -48
- data/lib/sisimai/bite/email/amazonworkmail.rb +20 -27
- data/lib/sisimai/bite/email/aol.rb +27 -35
- data/lib/sisimai/bite/email/apachejames.rb +17 -28
- data/lib/sisimai/bite/email/bigfoot.rb +20 -33
- data/lib/sisimai/bite/email/biglobe.rb +15 -24
- data/lib/sisimai/bite/email/courier.rb +37 -61
- data/lib/sisimai/bite/email/domino.rb +19 -28
- data/lib/sisimai/bite/email/einsundeins.rb +20 -34
- data/lib/sisimai/bite/email/exchange2003.rb +25 -43
- data/lib/sisimai/bite/email/exchange2007.rb +15 -23
- data/lib/sisimai/bite/email/exim.rb +101 -120
- data/lib/sisimai/bite/email/ezweb.rb +28 -44
- data/lib/sisimai/bite/email/facebook.rb +26 -37
- data/lib/sisimai/bite/email/fml.rb +11 -20
- data/lib/sisimai/bite/email/gmx.rb +17 -27
- data/lib/sisimai/bite/email/google.rb +19 -29
- data/lib/sisimai/bite/email/gsuite.rb +39 -48
- data/lib/sisimai/bite/email/imailserver.rb +25 -39
- data/lib/sisimai/bite/email/interscanmss.rb +19 -26
- data/lib/sisimai/bite/email/kddi.rb +20 -33
- data/lib/sisimai/bite/email/mailfoundry.rb +14 -24
- data/lib/sisimai/bite/email/mailmarshalsmtp.rb +15 -24
- data/lib/sisimai/bite/email/mailru.rb +40 -59
- data/lib/sisimai/bite/email/mcafee.rb +21 -35
- data/lib/sisimai/bite/email/messagelabs.rb +23 -38
- data/lib/sisimai/bite/email/messagingserver.rb +15 -27
- data/lib/sisimai/bite/email/mfilter.rb +19 -28
- data/lib/sisimai/bite/email/mxlogic.rb +31 -49
- data/lib/sisimai/bite/email/notes.rb +16 -24
- data/lib/sisimai/bite/email/office365.rb +29 -38
- data/lib/sisimai/bite/email/opensmtpd.rb +50 -67
- data/lib/sisimai/bite/email/outlook.rb +24 -36
- data/lib/sisimai/bite/email/postfix.rb +33 -42
- data/lib/sisimai/bite/email/qmail.rb +44 -59
- data/lib/sisimai/bite/email/receivingses.rb +28 -36
- data/lib/sisimai/bite/email/sendgrid.rb +28 -37
- data/lib/sisimai/bite/email/sendmail.rb +35 -51
- data/lib/sisimai/bite/email/surfcontrol.rb +17 -25
- data/lib/sisimai/bite/email/userdefined.rb +17 -28
- data/lib/sisimai/bite/email/v5sendmail.rb +32 -41
- data/lib/sisimai/bite/email/verizon.rb +31 -56
- data/lib/sisimai/bite/email/x1.rb +11 -18
- data/lib/sisimai/bite/email/x2.rb +11 -23
- data/lib/sisimai/bite/email/x3.rb +10 -19
- data/lib/sisimai/bite/email/x4.rb +46 -65
- data/lib/sisimai/bite/email/x5.rb +26 -37
- data/lib/sisimai/bite/email/yahoo.rb +11 -19
- data/lib/sisimai/bite/email/yandex.rb +19 -30
- data/lib/sisimai/bite/email/zoho.rb +21 -30
- data/lib/sisimai/bite/json.rb +1 -2
- data/lib/sisimai/bite/json/amazonses.rb +20 -25
- data/lib/sisimai/bite/json/sendgrid.rb +1 -1
- data/lib/sisimai/data.rb +36 -55
- data/lib/sisimai/data/json.rb +3 -3
- data/lib/sisimai/data/yaml.rb +1 -1
- data/lib/sisimai/datetime.rb +5 -21
- data/lib/sisimai/mail.rb +4 -6
- data/lib/sisimai/mail/maildir.rb +1 -1
- data/lib/sisimai/mda.rb +41 -44
- data/lib/sisimai/message.rb +2 -3
- data/lib/sisimai/message/email.rb +42 -52
- data/lib/sisimai/message/json.rb +7 -7
- data/lib/sisimai/mime.rb +25 -23
- data/lib/sisimai/order/email.rb +2 -2
- data/lib/sisimai/order/json.rb +2 -7
- data/lib/sisimai/reason.rb +41 -46
- data/lib/sisimai/reason/blocked.rb +60 -71
- data/lib/sisimai/reason/contenterror.rb +4 -8
- data/lib/sisimai/reason/delivered.rb +1 -3
- data/lib/sisimai/reason/exceedlimit.rb +10 -20
- data/lib/sisimai/reason/expired.rb +5 -9
- data/lib/sisimai/reason/feedback.rb +1 -3
- data/lib/sisimai/reason/filtered.rb +19 -38
- data/lib/sisimai/reason/hasmoved.rb +5 -8
- data/lib/sisimai/reason/hostunknown.rb +11 -18
- data/lib/sisimai/reason/mailboxfull.rb +14 -24
- data/lib/sisimai/reason/mailererror.rb +3 -5
- data/lib/sisimai/reason/mesgtoobig.rb +15 -25
- data/lib/sisimai/reason/networkerror.rb +8 -10
- data/lib/sisimai/reason/norelaying.rb +9 -14
- data/lib/sisimai/reason/notaccept.rb +9 -21
- data/lib/sisimai/reason/onhold.rb +3 -8
- data/lib/sisimai/reason/policyviolation.rb +8 -10
- data/lib/sisimai/reason/rejected.rb +36 -49
- data/lib/sisimai/reason/securityerror.rb +11 -13
- data/lib/sisimai/reason/spamdetected.rb +23 -37
- data/lib/sisimai/reason/suspend.rb +9 -10
- data/lib/sisimai/reason/syntaxerror.rb +3 -4
- data/lib/sisimai/reason/systemerror.rb +7 -9
- data/lib/sisimai/reason/systemfull.rb +2 -4
- data/lib/sisimai/reason/toomanyconn.rb +17 -30
- data/lib/sisimai/reason/undefined.rb +1 -3
- data/lib/sisimai/reason/userunknown.rb +28 -38
- data/lib/sisimai/reason/vacation.rb +4 -6
- data/lib/sisimai/reason/virusdetected.rb +4 -6
- data/lib/sisimai/rfc2606.rb +1 -2
- data/lib/sisimai/rfc3464.rb +87 -101
- data/lib/sisimai/rfc3834.rb +29 -39
- data/lib/sisimai/rfc5322.rb +17 -24
- data/lib/sisimai/rhost.rb +10 -7
- data/lib/sisimai/rhost/exchangeonline.rb +124 -255
- data/lib/sisimai/rhost/franceptt.rb +2 -2
- data/lib/sisimai/rhost/godaddy.rb +12 -25
- data/lib/sisimai/rhost/googleapps.rb +82 -183
- data/lib/sisimai/smtp.rb +4 -4
- data/lib/sisimai/smtp/error.rb +8 -8
- data/lib/sisimai/smtp/reply.rb +1 -1
- data/lib/sisimai/smtp/status.rb +1 -0
- data/lib/sisimai/string.rb +5 -7
- data/lib/sisimai/version.rb +1 -1
- data/set-of-emails/README.md +1 -1
- data/set-of-emails/maildir/bsd/README.md +50 -50
- data/sisimai-java.gemspec +1 -1
- data/sisimai.gemspec +1 -1
- metadata +4 -4
- data/lib/sisimai/skeleton.rb +0 -43
@@ -6,15 +6,11 @@ module Sisimai::Bite::Email
|
|
6
6
|
# Imported from p5-Sisimail/lib/Sisimai/Bite/Email/Yandex.pm
|
7
7
|
require 'sisimai/bite/email'
|
8
8
|
|
9
|
-
Re0 = {
|
10
|
-
:from => %r/\Amailer-daemon[@]yandex[.]ru\z/,
|
11
|
-
}.freeze
|
12
|
-
Re1 = {
|
13
|
-
:begin => %r/\AThis is the mail system at host yandex[.]ru[.]/,
|
14
|
-
:rfc822 => %r|\AContent-Type: message/rfc822|,
|
15
|
-
:endof => %r/\A__END_OF_EMAIL_MESSAGE__\z/,
|
16
|
-
}.freeze
|
17
9
|
Indicators = Sisimai::Bite::Email.INDICATORS
|
10
|
+
StartingOf = {
|
11
|
+
message: ['This is the mail system at host yandex.ru.'],
|
12
|
+
rfc822: ['Content-Type: message/rfc822'],
|
13
|
+
}.freeze
|
18
14
|
|
19
15
|
def description; return 'Yandex.Mail: http://www.yandex.ru'; end
|
20
16
|
def smtpagent; return Sisimai::Bite.smtpagent(self); end
|
@@ -27,7 +23,6 @@ module Sisimai::Bite::Email
|
|
27
23
|
# X-Yandex-Queue-ID: 367D79E130D
|
28
24
|
# X-Yandex-Sender: rfc822; shironeko@yandex.example.com
|
29
25
|
def headerlist; return ['X-Yandex-Uniq']; end
|
30
|
-
def pattern; return Re0; end
|
31
26
|
|
32
27
|
# Parse bounce messages from Yandex.Mail
|
33
28
|
# @param [Hash] mhead Message headers of a bounce email
|
@@ -44,7 +39,7 @@ module Sisimai::Bite::Email
|
|
44
39
|
return nil unless mhead
|
45
40
|
return nil unless mbody
|
46
41
|
return nil unless mhead['x-yandex-uniq']
|
47
|
-
return nil unless mhead['from']
|
42
|
+
return nil unless mhead['from'] == 'mailer-daemon@yandex.ru'
|
48
43
|
|
49
44
|
dscontents = [Sisimai::Bite.DELIVERYSTATUS]
|
50
45
|
hasdivided = mbody.split("\n")
|
@@ -61,14 +56,14 @@ module Sisimai::Bite::Email
|
|
61
56
|
}
|
62
57
|
v = nil
|
63
58
|
|
64
|
-
hasdivided.
|
59
|
+
while e = hasdivided.shift do
|
65
60
|
# Save the current line for the next loop
|
66
61
|
havepassed << e
|
67
62
|
p = havepassed[-2]
|
68
63
|
|
69
64
|
if readcursor.zero?
|
70
65
|
# Beginning of the bounce message or delivery status part
|
71
|
-
if e
|
66
|
+
if e.start_with?(StartingOf[:message][0])
|
72
67
|
readcursor |= Indicators[:deliverystatus]
|
73
68
|
next
|
74
69
|
end
|
@@ -76,7 +71,7 @@ module Sisimai::Bite::Email
|
|
76
71
|
|
77
72
|
if (readcursor & Indicators[:'message-rfc822']).zero?
|
78
73
|
# Beginning of the original message part
|
79
|
-
if e
|
74
|
+
if e.start_with?(StartingOf[:rfc822][0])
|
80
75
|
readcursor |= Indicators[:'message-rfc822']
|
81
76
|
next
|
82
77
|
end
|
@@ -90,7 +85,6 @@ module Sisimai::Bite::Email
|
|
90
85
|
next
|
91
86
|
end
|
92
87
|
rfc822list << e
|
93
|
-
|
94
88
|
else
|
95
89
|
# Before "message/rfc822"
|
96
90
|
next if (readcursor & Indicators[:deliverystatus]).zero?
|
@@ -109,7 +103,7 @@ module Sisimai::Bite::Email
|
|
109
103
|
# Content-Type: message/rfc822
|
110
104
|
v = dscontents[-1]
|
111
105
|
|
112
|
-
if cv = e.match(/\
|
106
|
+
if cv = e.match(/\AFinal-Recipient:[ ]*(?:RFC|rfc)822;[ ]*([^ ]+)\z/)
|
113
107
|
# Final-Recipient: rfc822; kijitora@example.jp
|
114
108
|
if v['recipient']
|
115
109
|
# There are multiple recipient addresses in the message body.
|
@@ -119,33 +113,30 @@ module Sisimai::Bite::Email
|
|
119
113
|
v['recipient'] = cv[1]
|
120
114
|
recipients += 1
|
121
115
|
|
122
|
-
elsif cv = e.match(/\
|
116
|
+
elsif cv = e.match(/\AAction:[ ]*(.+)\z/)
|
123
117
|
# Action: failed
|
124
118
|
v['action'] = cv[1]
|
125
119
|
|
126
|
-
elsif cv = e.match(/\
|
120
|
+
elsif cv = e.match(/\AStatus:[ ]*(\d[.]\d+[.]\d+)/)
|
127
121
|
# Status:5.2.0
|
128
122
|
v['status'] = cv[1]
|
129
123
|
|
130
|
-
elsif cv = e.match(/\
|
124
|
+
elsif cv = e.match(/\ARemote-MTA:[ ]*(?:DNS|dns);[ ]*(.+)\z/)
|
131
125
|
# Remote-MTA: DNS; mx.example.jp
|
132
126
|
v['rhost'] = cv[1].downcase
|
133
|
-
|
134
127
|
else
|
135
128
|
# Get error message
|
136
|
-
if cv = e.match(/\
|
129
|
+
if cv = e.match(/\ADiagnostic-Code:[ ]*(.+?);[ ]*(.+)\z/)
|
137
130
|
# Diagnostic-Code: SMTP; 550 5.1.1 <userunknown@example.jp>... User Unknown
|
138
131
|
v['spec'] = cv[1].upcase
|
139
132
|
v['diagnosis'] = cv[2]
|
140
133
|
|
141
|
-
elsif p
|
134
|
+
elsif p.start_with?('Diagnostic-Code:') && cv = e.match(/\A[ \t]+(.+)\z/)
|
142
135
|
# Continued line of the value of Diagnostic-Code header
|
143
|
-
v['diagnosis']
|
144
|
-
|
145
|
-
havepassed[-1] = 'Diagnostic-Code: ' + e
|
136
|
+
v['diagnosis'] << ' ' << cv[1]
|
137
|
+
havepassed[-1] = 'Diagnostic-Code: ' << e
|
146
138
|
end
|
147
139
|
end
|
148
|
-
|
149
140
|
else
|
150
141
|
# Content-Type: message/delivery-status
|
151
142
|
#
|
@@ -153,18 +144,17 @@ module Sisimai::Bite::Email
|
|
153
144
|
# X-Yandex-Queue-ID: 367D79E130D
|
154
145
|
# X-Yandex-Sender: rfc822; shironeko@yandex.example.com
|
155
146
|
# Arrival-Date: Sat, 6 Dec 2014 20:12:27 +0300 (MSK)
|
156
|
-
if cv = e.match(/\
|
147
|
+
if cv = e.match(/\AReporting-MTA:[ ]*(?:DNS|dns);[ ]*(.+)\z/)
|
157
148
|
# Reporting-MTA: dns; mx.example.jp
|
158
149
|
next if connheader['lhost'].size > 0
|
159
150
|
connheader['lhost'] = cv[1].downcase
|
160
151
|
connvalues += 1
|
161
152
|
|
162
|
-
elsif cv = e.match(/\
|
153
|
+
elsif cv = e.match(/\AArrival-Date:[ ]*(.+)\z/)
|
163
154
|
# Arrival-Date: Wed, 29 Apr 2009 16:03:18 +0900
|
164
155
|
next if connheader['date'].size > 0
|
165
156
|
connheader['date'] = cv[1]
|
166
157
|
connvalues += 1
|
167
|
-
|
168
158
|
else
|
169
159
|
# <kijitora@example.jp>: host mx.example.jp[192.0.2.153] said: 550
|
170
160
|
# 5.1.1 <kijitora@example.jp>... User Unknown (in reply to RCPT TO
|
@@ -179,12 +169,11 @@ module Sisimai::Bite::Email
|
|
179
169
|
end
|
180
170
|
end
|
181
171
|
end
|
182
|
-
|
183
172
|
end
|
184
173
|
end
|
185
174
|
return nil if recipients.zero?
|
186
|
-
require 'sisimai/string'
|
187
175
|
|
176
|
+
require 'sisimai/string'
|
188
177
|
dscontents.map do |e|
|
189
178
|
# Set default values if each value is empty.
|
190
179
|
connheader.each_key { |a| e[a] ||= connheader[a] || '' }
|
@@ -6,24 +6,12 @@ module Sisimai::Bite::Email
|
|
6
6
|
# Imported from p5-Sisimail/lib/Sisimai/Bite/Email/Zoho.pm
|
7
7
|
require 'sisimai/bite/email'
|
8
8
|
|
9
|
-
Re0 = {
|
10
|
-
:'from' => %r/mailer-daemon[@]mail[.]zoho[.]com\z/,
|
11
|
-
:'subject' => %r{\A(?:
|
12
|
-
Undelivered[ ]Mail[ ]Returned[ ]to[ ]Sender
|
13
|
-
|Mail[ ]Delivery[ ]Status[ ]Notification
|
14
|
-
)
|
15
|
-
}x,
|
16
|
-
:'x-mailer' => %r/\AZoho Mail\z/,
|
17
|
-
}.freeze
|
18
|
-
Re1 = {
|
19
|
-
:begin => %r/\AThis message was created automatically by mail delivery/,
|
20
|
-
:rfc822 => %r/\AReceived:[ \t]*from mail[.]zoho[.]com/,
|
21
|
-
:endof => %r/\A__END_OF_EMAIL_MESSAGE__\z/,
|
22
|
-
}.freeze
|
23
|
-
ReFailure = {
|
24
|
-
expired: %r/Host not reachable/
|
25
|
-
}.freeze
|
26
9
|
Indicators = Sisimai::Bite::Email.INDICATORS
|
10
|
+
StartingOf = {
|
11
|
+
message: ['This message was created automatically by mail delivery'],
|
12
|
+
rfc822: ['from mail.zoho.com by mx.zohomail.com'],
|
13
|
+
}.freeze
|
14
|
+
ReFailures = { expired: %r/Host not reachable/ }.freeze
|
27
15
|
|
28
16
|
def description; return 'Zoho Mail: https://www.zoho.com'; end
|
29
17
|
def smtpagent; return Sisimai::Bite.smtpagent(self); end
|
@@ -32,7 +20,6 @@ module Sisimai::Bite::Email
|
|
32
20
|
# X-Zoho-Virus-Status: 2
|
33
21
|
# X-Mailer: Zoho Mail
|
34
22
|
def headerlist; return ['X-ZohoMail']; end
|
35
|
-
def pattern; return Re0; end
|
36
23
|
|
37
24
|
# Parse bounce messages from Zoho Mail
|
38
25
|
# @param [Hash] mhead Message headers of a bounce email
|
@@ -48,6 +35,14 @@ module Sisimai::Bite::Email
|
|
48
35
|
def scan(mhead, mbody)
|
49
36
|
return nil unless mhead
|
50
37
|
return nil unless mbody
|
38
|
+
|
39
|
+
# :'from' => %r/mailer-daemon[@]mail[.]zoho[.]com\z/,
|
40
|
+
# :'subject' => %r{\A(?:
|
41
|
+
# Undelivered[ ]Mail[ ]Returned[ ]to[ ]Sender
|
42
|
+
# |Mail[ ]Delivery[ ]Status[ ]Notification
|
43
|
+
# )
|
44
|
+
# }x,
|
45
|
+
# :'x-mailer' => %r/\AZoho Mail\z/,
|
51
46
|
return nil unless mhead['x-zohomail']
|
52
47
|
|
53
48
|
dscontents = [Sisimai::Bite.DELIVERYSTATUS]
|
@@ -59,10 +54,10 @@ module Sisimai::Bite::Email
|
|
59
54
|
qprintable = false
|
60
55
|
v = nil
|
61
56
|
|
62
|
-
hasdivided.
|
57
|
+
while e = hasdivided.shift do
|
63
58
|
if readcursor.zero?
|
64
59
|
# Beginning of the bounce message or delivery status part
|
65
|
-
if e
|
60
|
+
if e.start_with?(StartingOf[:message][0])
|
66
61
|
readcursor |= Indicators[:deliverystatus]
|
67
62
|
next
|
68
63
|
end
|
@@ -70,7 +65,7 @@ module Sisimai::Bite::Email
|
|
70
65
|
|
71
66
|
if (readcursor & Indicators[:'message-rfc822']).zero?
|
72
67
|
# Beginning of the original message part
|
73
|
-
if e
|
68
|
+
if e.include?(StartingOf[:rfc822][0])
|
74
69
|
readcursor |= Indicators[:'message-rfc822']
|
75
70
|
next
|
76
71
|
end
|
@@ -84,7 +79,6 @@ module Sisimai::Bite::Email
|
|
84
79
|
next
|
85
80
|
end
|
86
81
|
rfc822list << e
|
87
|
-
|
88
82
|
else
|
89
83
|
# Before "message/rfc822"
|
90
84
|
next if (readcursor & Indicators[:deliverystatus]).zero?
|
@@ -115,7 +109,7 @@ module Sisimai::Bite::Email
|
|
115
109
|
|
116
110
|
if v['diagnosis'].end_with?('=')
|
117
111
|
# Quoted printable
|
118
|
-
v['diagnosis'] = v['diagnosis'].
|
112
|
+
v['diagnosis'] = v['diagnosis'].chomp('=')
|
119
113
|
qprintable = true
|
120
114
|
end
|
121
115
|
recipients += 1
|
@@ -131,27 +125,24 @@ module Sisimai::Bite::Email
|
|
131
125
|
v['recipient'] = cv[1]
|
132
126
|
v['diagnosis'] = e
|
133
127
|
recipients += 1
|
134
|
-
|
135
128
|
else
|
136
129
|
# Continued line
|
137
130
|
next unless qprintable
|
138
|
-
v['diagnosis']
|
139
|
-
v['diagnosis'] += e
|
140
|
-
|
131
|
+
v['diagnosis'] << e
|
141
132
|
end
|
142
133
|
end
|
143
134
|
end
|
144
135
|
return nil if recipients.zero?
|
145
|
-
require 'sisimai/string'
|
146
136
|
|
137
|
+
require 'sisimai/string'
|
147
138
|
dscontents.map do |e|
|
148
139
|
e['agent'] = self.smtpagent
|
149
140
|
e['diagnosis'] = e['diagnosis'].gsub(/\\n/, ' ')
|
150
141
|
e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'])
|
151
142
|
|
152
|
-
|
143
|
+
ReFailures.each_key do |r|
|
153
144
|
# Verify each regular expression of session errors
|
154
|
-
next unless e['diagnosis'] =~
|
145
|
+
next unless e['diagnosis'] =~ ReFailures[r]
|
155
146
|
e['reason'] = r.to_s
|
156
147
|
break
|
157
148
|
end
|
data/lib/sisimai/bite/json.rb
CHANGED
@@ -7,12 +7,11 @@ module Sisimai
|
|
7
7
|
require 'sisimai/bite'
|
8
8
|
|
9
9
|
def headerlist; return []; end
|
10
|
-
def pattern; return []; end
|
11
10
|
|
12
11
|
# MTA list
|
13
12
|
# @return [Array] MTA list with order
|
14
13
|
def index
|
15
|
-
return %w
|
14
|
+
return %w[SendGrid AmazonSES]
|
16
15
|
end
|
17
16
|
|
18
17
|
# Convert from JSON object to Sisimai::Message
|
@@ -49,47 +49,45 @@ module Sisimai::Bite::JSON
|
|
49
49
|
jsonthings = nil
|
50
50
|
foldedline = false
|
51
51
|
|
52
|
-
hasdivided.
|
52
|
+
while e = hasdivided.shift do
|
53
53
|
# Find JSON string from the message body
|
54
54
|
next if e.size.zero?
|
55
|
-
break if e
|
55
|
+
break if e == '--'
|
56
56
|
break if e == '__END_OF_EMAIL_MESSAGE__'
|
57
57
|
|
58
58
|
# The line starts with " ", continued from !\n.
|
59
|
-
e = e.
|
59
|
+
e = e.lstrip if foldedline
|
60
60
|
foldedline = false
|
61
61
|
|
62
|
-
if e
|
62
|
+
if e.end_with?('!')
|
63
63
|
# ... long long line ...![\n]
|
64
|
-
e = e.
|
64
|
+
e = e.chomp('!')
|
65
65
|
foldedline = true
|
66
66
|
end
|
67
|
-
jsonstring
|
67
|
+
jsonstring << e
|
68
68
|
end
|
69
69
|
|
70
70
|
begin
|
71
|
-
if RUBY_PLATFORM
|
71
|
+
if RUBY_PLATFORM.include?('java')
|
72
72
|
# java-based ruby environment like JRuby.
|
73
73
|
require 'jrjackson'
|
74
74
|
jsonobject = JrJackson::Json.load(jsonstring)
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
end
|
75
|
+
|
76
|
+
# 'Message' => '{"notificationType":"Bounce",...
|
77
|
+
jsonthings = JrJackson::Json.load(jsonobject['Message']) if jsonobject['Message']
|
79
78
|
else
|
80
79
|
# Matz' Ruby Implementation
|
81
80
|
require 'oj'
|
82
81
|
jsonobject = Oj.load(jsonstring)
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
end
|
82
|
+
|
83
|
+
# 'Message' => '{"notificationType":"Bounce",...
|
84
|
+
jsonthings = Oj.load(jsonobject['Message']) if jsonobject['Message']
|
87
85
|
end
|
88
86
|
jsonthings ||= jsonobject
|
89
87
|
|
90
88
|
rescue StandardError => ce
|
91
89
|
# Something wrong in decoding JSON
|
92
|
-
warn
|
90
|
+
warn ' ***warning: Failed to decode JSON: ' << ce.to_s
|
93
91
|
return nil
|
94
92
|
end
|
95
93
|
|
@@ -117,12 +115,12 @@ module Sisimai::Bite::JSON
|
|
117
115
|
}
|
118
116
|
v = nil
|
119
117
|
|
120
|
-
if argvs['notificationType']
|
118
|
+
if %w[Bounce Complaint].index(argvs['notificationType'])
|
121
119
|
# { "notificationType":"Bounce", "bounce": { "bounceType":"Permanent",...
|
122
|
-
o = argvs[argvs['notificationType'].downcase]
|
120
|
+
o = argvs[argvs['notificationType'].downcase].dup
|
123
121
|
r = o[labeltable[argvs['notificationType'].to_sym]] || []
|
124
122
|
|
125
|
-
r.
|
123
|
+
while e = r.shift do
|
126
124
|
# 'bouncedRecipients' => [ { 'emailAddress' => 'bounce@si...' }, ... ]
|
127
125
|
# 'complainedRecipients' => [ { 'emailAddress' => 'complaint@si...' }, ... ]
|
128
126
|
next unless Sisimai::RFC5322.is_emailaddress(e['emailAddress'])
|
@@ -167,7 +165,6 @@ module Sisimai::Bite::JSON
|
|
167
165
|
# },
|
168
166
|
v['reason'] = BounceType[o['bounceType'].to_sym][o['bounceSubType'].to_sym]
|
169
167
|
end
|
170
|
-
|
171
168
|
else
|
172
169
|
# 'complainedRecipients' => [ {
|
173
170
|
# 'emailAddress' => 'complaint@simulator.amazonses.com' }, ... ],
|
@@ -178,16 +175,15 @@ module Sisimai::Bite::JSON
|
|
178
175
|
v['date'] = o['timestamp'] || argvs['mail']['timestamp']
|
179
176
|
v['date'] = v['date'].sub(/[.]\d+Z\z/, '')
|
180
177
|
end
|
181
|
-
|
182
178
|
elsif argvs['notificationType'] == 'Delivery'
|
183
179
|
# { "notificationType":"Delivery", "delivery": { ...
|
184
180
|
require 'sisimai/smtp/status'
|
185
181
|
require 'sisimai/smtp/reply'
|
186
182
|
|
187
|
-
o = argvs['delivery']
|
183
|
+
o = argvs['delivery'].dup
|
188
184
|
r = o['recipients'] || []
|
189
185
|
|
190
|
-
r.
|
186
|
+
while e = r.shift do
|
191
187
|
# 'delivery' => {
|
192
188
|
# 'timestamp' => '2016-11-23T12:01:03.512Z',
|
193
189
|
# 'processingTimeMillis' => 3982,
|
@@ -217,7 +213,6 @@ module Sisimai::Bite::JSON
|
|
217
213
|
v['date'] = o['timestamp'] || argvs['mail']['timestamp']
|
218
214
|
v['date'] = v['date'].sub(/[.]\d+Z\z/, '')
|
219
215
|
end
|
220
|
-
|
221
216
|
else
|
222
217
|
# The value of "notificationType" is not any of "Bounce", "Complaint",
|
223
218
|
# or "Delivery".
|
@@ -234,7 +229,7 @@ module Sisimai::Bite::JSON
|
|
234
229
|
# "headers":[ { ...
|
235
230
|
argvs['mail']['headers'].each do |e|
|
236
231
|
# 'headers' => [ { 'name' => 'From', 'value' => 'neko@nyaan.jp' }, ... ],
|
237
|
-
next unless
|
232
|
+
next unless %w[From To Subject Message-ID Date].index(e['name'])
|
238
233
|
rfc822head[e['name'].downcase] = e['value']
|
239
234
|
end
|
240
235
|
end
|
@@ -46,7 +46,7 @@ module Sisimai::Bite::JSON
|
|
46
46
|
# 'smtp-id' => '<201709042010.v84KAQ5T032530@example.nyaan.jp>',
|
47
47
|
# 'status' => '5.2.2'
|
48
48
|
# },
|
49
|
-
return nil unless argvs['event']
|
49
|
+
return nil unless %w[bounce deferred delivered spamreport].include?(argvs['event'])
|
50
50
|
dscontents = [Sisimai::Bite.DELIVERYSTATUS]
|
51
51
|
diagnostic = argvs['reason'] || ''
|
52
52
|
diagnostic = argvs['response'] || '' if diagnostic.empty?
|
data/lib/sisimai/data.rb
CHANGED
@@ -44,15 +44,8 @@ module Sisimai
|
|
44
44
|
EndOfEmail = Sisimai::String.EOM
|
45
45
|
RetryIndex = Sisimai::Reason.retry
|
46
46
|
RFC822Head = Sisimai::RFC5322.HEADERFIELDS(:all)
|
47
|
-
AddrHeader = {
|
48
|
-
|
49
|
-
recipient: RFC822Head[:recipient],
|
50
|
-
}.freeze
|
51
|
-
ActionList = %r/\A(?:failed|delayed|delivered|relayed|expanded)\z/
|
52
|
-
ActionHead = {
|
53
|
-
%r/\Afailure\z/ => 'failed',
|
54
|
-
%r/\Aexpired\z/ => 'delayed',
|
55
|
-
}.freeze
|
47
|
+
AddrHeader = { addresser: RFC822Head[:addresser], recipient: RFC822Head[:recipient] }.freeze
|
48
|
+
ActionHead = { failure: 'failed', expired: 'delayed' }.freeze
|
56
49
|
|
57
50
|
# Constructor of Sisimai::Data
|
58
51
|
# @param [Hash] argvs Data
|
@@ -64,7 +57,6 @@ module Sisimai
|
|
64
57
|
|
65
58
|
return nil unless as.is_a? Sisimai::Address
|
66
59
|
return nil unless ar.is_a? Sisimai::Address
|
67
|
-
|
68
60
|
return nil if as.void
|
69
61
|
return nil if ar.void
|
70
62
|
|
@@ -110,7 +102,6 @@ module Sisimai
|
|
110
102
|
rfc822data = messageobj.rfc822
|
111
103
|
fieldorder = { :recipient => [], :addresser => [] }
|
112
104
|
objectlist = []
|
113
|
-
rxcommands = %r/\A(?:EHLO|HELO|MAIL|RCPT|DATA|QUIT)\z/
|
114
105
|
givenorder = argvs[:order] || {}
|
115
106
|
delivered1 = argvs[:delivered] || false
|
116
107
|
|
@@ -133,10 +124,10 @@ module Sisimai
|
|
133
124
|
|
134
125
|
fieldorder.each_key do |e|
|
135
126
|
# If the order is empty, use default order.
|
136
|
-
if fieldorder[e].
|
137
|
-
|
138
|
-
|
139
|
-
|
127
|
+
next if fieldorder[e].size > 0
|
128
|
+
|
129
|
+
# Load default order of each accessor.
|
130
|
+
fieldorder[e] = AddrHeader[e]
|
140
131
|
end
|
141
132
|
|
142
133
|
messageobj.ds.each do |e|
|
@@ -160,7 +151,7 @@ module Sisimai
|
|
160
151
|
}
|
161
152
|
unless delivered1
|
162
153
|
# Skip if the value of "deliverystatus" begins with "2." such as 2.1.5
|
163
|
-
next if p['deliverystatus']
|
154
|
+
next if p['deliverystatus'].start_with?('2.')
|
164
155
|
end
|
165
156
|
|
166
157
|
# EMAIL_ADDRESS:
|
@@ -191,9 +182,7 @@ module Sisimai
|
|
191
182
|
datestring = nil
|
192
183
|
zoneoffset = 0
|
193
184
|
datevalues = []
|
194
|
-
|
195
|
-
datevalues << e['date']
|
196
|
-
end
|
185
|
+
datevalues << e['date'] if e['date'].to_s.size > 0
|
197
186
|
|
198
187
|
# Date information did not exist in message/delivery-status part,...
|
199
188
|
RFC822Head[:date].each do |f|
|
@@ -202,12 +191,10 @@ module Sisimai
|
|
202
191
|
datevalues << rfc822data[f.downcase]
|
203
192
|
end
|
204
193
|
|
205
|
-
|
206
|
-
|
207
|
-
datevalues << messageobj.header['date']
|
208
|
-
end
|
194
|
+
# Set "date" getting from the value of "Date" in the bounce message
|
195
|
+
datevalues << messageobj.header['date'] if datevalues.size < 2
|
209
196
|
|
210
|
-
datevalues.
|
197
|
+
while v = datevalues.shift do
|
211
198
|
# Parse each date value in the array
|
212
199
|
datestring = Sisimai::DateTime.parse(v)
|
213
200
|
break if datestring
|
@@ -229,7 +216,7 @@ module Sisimai
|
|
229
216
|
t = Sisimai::Time.strptime(datestring, '%a, %d %b %Y %T')
|
230
217
|
p['timestamp'] = (t.to_time.to_i - zoneoffset) || nil
|
231
218
|
rescue
|
232
|
-
warn ' ***warning: Failed to strptime '
|
219
|
+
warn ' ***warning: Failed to strptime ' << datestring.to_s
|
233
220
|
end
|
234
221
|
next unless p['timestamp']
|
235
222
|
|
@@ -237,27 +224,24 @@ module Sisimai
|
|
237
224
|
recvheader = mailheader['received'] || []
|
238
225
|
if recvheader.size > 0
|
239
226
|
# Get localhost and remote host name from Received header.
|
240
|
-
%w
|
227
|
+
%w[lhost rhost].each { |a| e[a] ||= '' }
|
241
228
|
e['lhost'] = Sisimai::RFC5322.received(recvheader[0]).shift if e['lhost'].empty?
|
242
229
|
e['rhost'] = Sisimai::RFC5322.received(recvheader[-1]).pop if e['rhost'].empty?
|
243
230
|
end
|
244
231
|
|
245
232
|
# Remove square brackets and curly brackets from the host variable
|
246
|
-
%w
|
233
|
+
%w[rhost lhost].each do |v|
|
247
234
|
p[v] = p[v].delete('[]()') # Remove square brackets and curly brackets from the host variable
|
248
235
|
p[v] = p[v].sub(/\A.+=/, '') # Remove string before "="
|
249
|
-
p[v] = p[v].
|
236
|
+
p[v] = p[v].chomp("\r") # Remove CR at the end of the value
|
250
237
|
|
251
|
-
# Check space character in each value
|
252
|
-
|
253
|
-
# Get the first element
|
254
|
-
p[v] = p[v].split(' ', 2).shift
|
255
|
-
end
|
238
|
+
# Check space character in each value and get the first element
|
239
|
+
p[v] = p[v].split(' ', 2).shift if p[v].include?(' ')
|
256
240
|
end
|
257
241
|
|
258
242
|
# Subject: header of the original message
|
259
243
|
p['subject'] = rfc822data['subject'] || ''
|
260
|
-
p['subject'] = p['subject'].scrub('?').
|
244
|
+
p['subject'] = p['subject'].scrub('?').chomp("\r")
|
261
245
|
|
262
246
|
# The value of "List-Id" header
|
263
247
|
p['listid'] = rfc822data['list-id'] || ''
|
@@ -268,8 +252,8 @@ module Sisimai
|
|
268
252
|
p['listid'] = cv[1]
|
269
253
|
end
|
270
254
|
p['listid'] = p['listid'].delete('<>')
|
271
|
-
p['listid'] = p['listid'].
|
272
|
-
p['listid'] = '' if p['listid']
|
255
|
+
p['listid'] = p['listid'].chomp("\r")
|
256
|
+
p['listid'] = '' if p['listid'].include?(' ')
|
273
257
|
end
|
274
258
|
|
275
259
|
# The value of "Message-Id" header
|
@@ -280,7 +264,7 @@ module Sisimai
|
|
280
264
|
p['messageid'] = cv[1]
|
281
265
|
end
|
282
266
|
p['messageid'] = p['messageid'].delete('<>')
|
283
|
-
p['messageid'] = p['messageid'].
|
267
|
+
p['messageid'] = p['messageid'].chomp("\r")
|
284
268
|
end
|
285
269
|
|
286
270
|
# CHECK_DELIVERY_STATUS_VALUE:
|
@@ -320,10 +304,10 @@ module Sisimai
|
|
320
304
|
end
|
321
305
|
end
|
322
306
|
p['diagnostictype'] ||= 'X-UNIX' if p['reason'] == 'mailererror'
|
323
|
-
p['diagnostictype'] ||= 'SMTP' unless p['reason']
|
307
|
+
p['diagnostictype'] ||= 'SMTP' unless %w[feedback vacation].index(p['reason'])
|
324
308
|
|
325
309
|
# Check the value of SMTP command
|
326
|
-
p['smtpcommand'] = '' unless p['smtpcommand']
|
310
|
+
p['smtpcommand'] = '' unless %w[EHLO HELO MAIL RCPT DATA QUIT].index(p['smtpcommand'])
|
327
311
|
|
328
312
|
# Check the value of "action"
|
329
313
|
if p['action'].size > 0
|
@@ -332,11 +316,11 @@ module Sisimai
|
|
332
316
|
p['action'] = cv[1]
|
333
317
|
end
|
334
318
|
|
335
|
-
unless p['action']
|
319
|
+
unless %w[failed delayed delivered relayed expanded].index(p['action'])
|
336
320
|
# The value of "action" is not in the following values:
|
337
321
|
# "failed" / "delayed" / "delivered" / "relayed" / "expanded"
|
338
322
|
ActionHead.each_key do |q|
|
339
|
-
next unless p['action']
|
323
|
+
next unless p['action'] == q.to_s
|
340
324
|
p['action'] = ActionHead[q]
|
341
325
|
break
|
342
326
|
end
|
@@ -345,7 +329,7 @@ module Sisimai
|
|
345
329
|
if p['reason'] == 'expired'
|
346
330
|
# Action: delayed
|
347
331
|
p['action'] = 'delayed'
|
348
|
-
elsif p['deliverystatus']
|
332
|
+
elsif p['deliverystatus'].start_with?('5', '4')
|
349
333
|
# Action: failed
|
350
334
|
p['action'] = 'failed'
|
351
335
|
end
|
@@ -357,16 +341,13 @@ module Sisimai
|
|
357
341
|
if o.reason.empty? || RetryIndex.index(o.reason)
|
358
342
|
# Decide the reason of email bounce
|
359
343
|
r = ''
|
360
|
-
if Sisimai::Rhost.match(o.rhost)
|
361
|
-
# Remote host dependent error
|
362
|
-
r = Sisimai::Rhost.get(o)
|
363
|
-
end
|
344
|
+
r = Sisimai::Rhost.get(o) if Sisimai::Rhost.match(o.rhost) # Remote host dependent error
|
364
345
|
r = Sisimai::Reason.get(o) if r.empty?
|
365
346
|
r = 'undefined' if r.empty?
|
366
347
|
o.reason = r
|
367
348
|
end
|
368
349
|
|
369
|
-
if o.reason
|
350
|
+
if %w[delivered feedback vacation].index(o.reason)
|
370
351
|
# The value of reason is "vacation" or "feedback"
|
371
352
|
o.softbounce = -1
|
372
353
|
o.replycode = '' unless o.reason == 'delivered'
|
@@ -377,8 +358,8 @@ module Sisimai
|
|
377
358
|
|
378
359
|
if o.softbounce.to_s.empty?
|
379
360
|
# The value is not set yet
|
380
|
-
textasargv =
|
381
|
-
textasargv = textasargv.
|
361
|
+
textasargv = p['deliverystatus'] + ' ' + p['diagnosticcode']
|
362
|
+
textasargv = textasargv.lstrip
|
382
363
|
softorhard = Sisimai::SMTP::Error.soft_or_hard(o.reason, textasargv)
|
383
364
|
|
384
365
|
o.softbounce = if softorhard.size > 0
|
@@ -392,8 +373,8 @@ module Sisimai
|
|
392
373
|
|
393
374
|
if o.deliverystatus.empty?
|
394
375
|
# Set pseudo status code
|
395
|
-
textasargv =
|
396
|
-
textasargv = textasargv.
|
376
|
+
textasargv = o.replycode + ' ' + p['diagnosticcode']
|
377
|
+
textasargv = textasargv.lstrip
|
397
378
|
|
398
379
|
getchecked = Sisimai::SMTP::Error.is_permanent(textasargv)
|
399
380
|
tmpfailure = getchecked.nil? ? false : (getchecked ? false : true)
|
@@ -435,7 +416,7 @@ module Sisimai
|
|
435
416
|
def damn
|
436
417
|
data = {}
|
437
418
|
@@rwaccessors.each do |e|
|
438
|
-
next if e.to_s
|
419
|
+
next if %w[addresser recipient timestamp].index(e.to_s)
|
439
420
|
data[e.to_s] = self.send(e) || ''
|
440
421
|
end
|
441
422
|
data['addresser'] = self.addresser.address
|
@@ -450,13 +431,13 @@ module Sisimai
|
|
450
431
|
# @return [String, Nil] Dumped data or nil if the value of the first
|
451
432
|
# argument is neither "json" nor "yaml"
|
452
433
|
def dump(type = 'json')
|
453
|
-
return nil unless %w
|
454
|
-
referclass =
|
434
|
+
return nil unless %w[json yaml].index(type)
|
435
|
+
referclass = 'Sisimai::Data::' << type.upcase
|
455
436
|
|
456
437
|
begin
|
457
438
|
require referclass.downcase.gsub('::', '/')
|
458
439
|
rescue
|
459
|
-
warn '***warning: Failed to load'
|
440
|
+
warn '***warning: Failed to load' << referclass
|
460
441
|
end
|
461
442
|
|
462
443
|
dumpeddata = Module.const_get(referclass).dump(self)
|