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
data/lib/sisimai/rfc3834.rb
CHANGED
@@ -4,34 +4,31 @@ module Sisimai
|
|
4
4
|
# Imported from p5-Sisimail/lib/Sisimai/RFC3834.pm
|
5
5
|
class << self
|
6
6
|
# http://tools.ietf.org/html/rfc3834
|
7
|
-
|
7
|
+
MarkingsOf = { :boundary => %r/\A__SISIMAI_PSEUDO_BOUNDARY__\z/ }
|
8
|
+
AutoReply1 = {
|
8
9
|
# http://www.iana.org/assignments/auto-submitted-keywords/auto-submitted-keywords.xhtml
|
9
|
-
:'auto-submitted' => %r/\Aauto-(?:generated|replied|notified)
|
10
|
+
:'auto-submitted' => %r/\Aauto-(?:generated|replied|notified)/,
|
10
11
|
# https://msdn.microsoft.com/en-us/library/ee219609(v=exchg.80).aspx
|
11
|
-
:'x-auto-response-suppress' => %r/(?:
|
12
|
+
:'x-auto-response-suppress' => %r/(?:oof|autoreply)/,
|
12
13
|
:'precedence' => %r/\Aauto_reply\z/,
|
13
14
|
:'subject' => %r/\A(?>
|
14
|
-
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
auto:
|
16
|
+
|auto[ ]response:
|
17
|
+
|automatic[ ]reply:
|
18
|
+
|out[ ]of[ ](?:the[ ])*office:
|
18
19
|
)
|
19
|
-
/
|
20
|
+
/x,
|
20
21
|
}.freeze
|
21
|
-
|
22
|
-
:boundary => %r/\A__SISIMAI_PSEUDO_BOUNDARY__\z/,
|
23
|
-
:endof => %r/\A__END_OF_EMAIL_MESSAGE__\z/
|
24
|
-
}
|
25
|
-
Re2 = {
|
22
|
+
Excludings = {
|
26
23
|
:subject => %r/(?:
|
27
|
-
|
28
|
-
|
|
24
|
+
security[ ]information[ ]for # sudo
|
25
|
+
|mail[ ]failure[ ][-] # Exim
|
29
26
|
)
|
30
27
|
/x,
|
31
|
-
:from => %r/(?:root|postmaster|mailer-daemon)[@]
|
28
|
+
:from => %r/(?:root|postmaster|mailer-daemon)[@]/,
|
32
29
|
:to => %r/root[@]/,
|
33
30
|
}.freeze
|
34
|
-
|
31
|
+
SubjectSet = %r{\A(?>
|
35
32
|
(?:.+?)?Re:
|
36
33
|
|Auto(?:[ ]Response):
|
37
34
|
|Automatic[ ]reply:
|
@@ -42,14 +39,7 @@ module Sisimai
|
|
42
39
|
|
43
40
|
def description; 'Detector for auto replied message'; end
|
44
41
|
def smtpagent; 'RFC3834'; end
|
45
|
-
def
|
46
|
-
def headerlist
|
47
|
-
return [
|
48
|
-
'Auto-Submitted',
|
49
|
-
'Precedence',
|
50
|
-
'X-Auto-Response-Suppress',
|
51
|
-
]
|
52
|
-
end
|
42
|
+
def headerlist; return %w[Auto-Submitted Precedence X-Auto-Response-Suppress]; end
|
53
43
|
|
54
44
|
# Detect auto reply message as RFC3834
|
55
45
|
# @param [Hash] mhead Message header of a bounce email
|
@@ -72,22 +62,22 @@ module Sisimai
|
|
72
62
|
match = 0
|
73
63
|
|
74
64
|
# DETECT_EXCLUSION_MESSAGE
|
75
|
-
|
65
|
+
Excludings.each_key do |e|
|
76
66
|
# Exclude message from root@
|
77
67
|
next unless mhead.key?(e.to_s)
|
78
68
|
next unless mhead[e.to_s]
|
79
|
-
next unless mhead[e.to_s] =~
|
69
|
+
next unless mhead[e.to_s].downcase =~ Excludings[e]
|
80
70
|
leave = 1
|
81
71
|
break
|
82
72
|
end
|
83
73
|
return nil if leave > 0
|
84
74
|
|
85
75
|
# DETECT_AUTO_REPLY_MESSAGE
|
86
|
-
|
76
|
+
AutoReply1.each_key do |e|
|
87
77
|
# RFC3834 Auto-Submitted and other headers
|
88
78
|
next unless mhead.key?(e.to_s)
|
89
79
|
next unless mhead[e.to_s]
|
90
|
-
next unless mhead[e.to_s] =~
|
80
|
+
next unless mhead[e.to_s].downcase =~ AutoReply1[e]
|
91
81
|
match += 1
|
92
82
|
break
|
93
83
|
end
|
@@ -95,7 +85,6 @@ module Sisimai
|
|
95
85
|
|
96
86
|
require 'sisimai/bite/email'
|
97
87
|
require 'sisimai/address'
|
98
|
-
|
99
88
|
dscontents = [Sisimai::Bite.DELIVERYSTATUS]
|
100
89
|
hasdivided = mbody.scrub('?').split("\n")
|
101
90
|
rfc822part = '' # (String) message/rfc822-headers part
|
@@ -107,7 +96,7 @@ module Sisimai
|
|
107
96
|
v = dscontents[-1]
|
108
97
|
|
109
98
|
# RECIPIENT_ADDRESS
|
110
|
-
[
|
99
|
+
%w[from return-path].each do |e|
|
111
100
|
# Try to get the address of the recipient
|
112
101
|
next unless mhead.key?(e)
|
113
102
|
next unless mhead[e]
|
@@ -127,13 +116,13 @@ module Sisimai
|
|
127
116
|
# the boundary string.
|
128
117
|
require 'sisimai/mime'
|
129
118
|
b0 = Sisimai::MIME.boundary(mhead['content-type'], 0)
|
130
|
-
|
119
|
+
MarkingsOf[:boundary] = %r/\A\Q#{b0}\E\z/ unless b0.empty?
|
131
120
|
end
|
132
121
|
|
133
122
|
# BODY_PARSER: Get vacation message
|
134
|
-
hasdivided.
|
123
|
+
while e = hasdivided.shift do
|
135
124
|
# Read the first 5 lines except a blank line
|
136
|
-
countuntil += 1 if e =~
|
125
|
+
countuntil += 1 if e =~ MarkingsOf[:boundary]
|
137
126
|
|
138
127
|
unless e.size > 0
|
139
128
|
# Check a blank line
|
@@ -141,11 +130,12 @@ module Sisimai
|
|
141
130
|
break if blanklines > countuntil
|
142
131
|
next
|
143
132
|
end
|
144
|
-
next unless e
|
145
|
-
next if e
|
133
|
+
next unless e.include?(' ')
|
134
|
+
next if e.start_with?('Content-Type')
|
135
|
+
next if e.start_with?('Content-Transfer')
|
146
136
|
|
147
137
|
v['diagnosis'] ||= ''
|
148
|
-
v['diagnosis']
|
138
|
+
v['diagnosis'] << e + ' '
|
149
139
|
haveloaded += 1
|
150
140
|
break if haveloaded >= maxmsgline
|
151
141
|
end
|
@@ -160,9 +150,9 @@ module Sisimai
|
|
160
150
|
|
161
151
|
v.each_key { |a| v[a] ||= '' }
|
162
152
|
|
163
|
-
if cv = mhead['subject'].match(
|
153
|
+
if cv = mhead['subject'].match(SubjectSet)
|
164
154
|
# Get the Subject header from the original message
|
165
|
-
rfc822part =
|
155
|
+
rfc822part = 'Subject: ' << cv[1] + "\n"
|
166
156
|
end
|
167
157
|
return { 'ds' => dscontents, 'rfc822' => rfc822part }
|
168
158
|
end
|
data/lib/sisimai/rfc5322.rb
CHANGED
@@ -7,15 +7,11 @@ module Sisimai
|
|
7
7
|
:messageid => ['Message-Id'],
|
8
8
|
:subject => ['Subject'],
|
9
9
|
:listid => ['List-Id'],
|
10
|
-
:date => [
|
11
|
-
:addresser => [
|
12
|
-
|
13
|
-
|
14
|
-
],
|
15
|
-
:recipient => [
|
16
|
-
'To', 'Delivered-To', 'Forward-Path', 'Envelope-To',
|
17
|
-
'X-Envelope-To', 'Resent-To', 'Apparently-To'
|
18
|
-
],
|
10
|
+
:date => %w[Date Posted-Date Posted Resent-Date],
|
11
|
+
:addresser => %w[
|
12
|
+
From Return-Path Reply-To Errors-To Reverse-Path X-Postfix-Sender Envelope-From X-Envelope-From
|
13
|
+
],
|
14
|
+
:recipient => %w[To Delivered-To Forward-Path Envelope-To X-Envelope-To Resent-To Apparently-To],
|
19
15
|
}.freeze
|
20
16
|
|
21
17
|
build_regular_expressions = lambda do
|
@@ -95,7 +91,7 @@ module Sisimai
|
|
95
91
|
def is_domainpart(dpart)
|
96
92
|
return false unless dpart.is_a?(::String)
|
97
93
|
return false if dpart =~ /(?:[\x00-\x1f]|\x1f)/
|
98
|
-
return false if dpart
|
94
|
+
return false if dpart.include?('@')
|
99
95
|
return true if dpart =~ Re[:domain]
|
100
96
|
return false
|
101
97
|
end
|
@@ -113,8 +109,8 @@ module Sisimai
|
|
113
109
|
|\A(?:mailer-daemon|postmaster)\z
|
114
110
|
|[ ]?mailer-daemon[ ]
|
115
111
|
)
|
116
|
-
/
|
117
|
-
return true if email =~ re
|
112
|
+
/x
|
113
|
+
return true if email.downcase =~ re
|
118
114
|
return false
|
119
115
|
end
|
120
116
|
|
@@ -144,7 +140,7 @@ module Sisimai
|
|
144
140
|
value['by'] = cr[1]
|
145
141
|
end
|
146
142
|
|
147
|
-
if value['from']
|
143
|
+
if value['from'].include?(' ')
|
148
144
|
# Received: from [10.22.22.222] (smtp-gateway.kyoto.ocn.ne.jp [192.0.2.222])
|
149
145
|
# (authenticated bits=0)
|
150
146
|
# by nijo.example.jp (V8/cf) with ESMTP id s1QB5ka0018055;
|
@@ -155,13 +151,12 @@ module Sisimai
|
|
155
151
|
hostname = ''
|
156
152
|
hostaddr = ''
|
157
153
|
|
158
|
-
received.
|
154
|
+
while e = received.shift do
|
159
155
|
# Received: from [10.22.22.222] (smtp-gateway.kyoto.ocn.ne.jp [192.0.2.222])
|
160
156
|
if e =~ /\A[\[(]\d+[.]\d+[.]\d+[.]\d+[)\]]\z/
|
161
157
|
# [192.0.2.1] or (192.0.2.1)
|
162
158
|
e = e.delete('[]()')
|
163
159
|
addrlist << e
|
164
|
-
|
165
160
|
else
|
166
161
|
# hostname
|
167
162
|
e = e.delete('()')
|
@@ -169,9 +164,9 @@ module Sisimai
|
|
169
164
|
end
|
170
165
|
end
|
171
166
|
|
172
|
-
namelist.
|
167
|
+
while e = namelist.shift do
|
173
168
|
# 1. Hostname takes priority over all other IP addresses
|
174
|
-
next unless e
|
169
|
+
next unless e.include?('.')
|
175
170
|
hostname = e
|
176
171
|
break
|
177
172
|
end
|
@@ -180,9 +175,8 @@ module Sisimai
|
|
180
175
|
# 2. Use IP address as a remote host name
|
181
176
|
addrlist.each do |e|
|
182
177
|
# Skip if the address is a private address
|
183
|
-
next if e
|
178
|
+
next if e.start_with?('10.', '127.', '192.168.')
|
184
179
|
next if e =~ /\A172[.](?:1[6-9]|2[0-9]|3[0-1])[.]/
|
185
|
-
next if e =~ /\A192[.]168[.]/
|
186
180
|
hostaddr = e
|
187
181
|
break
|
188
182
|
end
|
@@ -210,7 +204,7 @@ module Sisimai
|
|
210
204
|
rfc822part = '' # (String) message/rfc822-headers part
|
211
205
|
previousfn = '' # (String) Previous field name
|
212
206
|
|
213
|
-
argv1.
|
207
|
+
while e = argv1.shift do
|
214
208
|
# After "message/rfc822"
|
215
209
|
if cv = e.match(/\A([-0-9A-Za-z]+?)[:][ ]*.+\z/)
|
216
210
|
# Get required headers
|
@@ -219,13 +213,12 @@ module Sisimai
|
|
219
213
|
next unless HeaderIndex.key?(lhs)
|
220
214
|
|
221
215
|
previousfn = lhs
|
222
|
-
rfc822part
|
216
|
+
rfc822part << e + "\n"
|
223
217
|
|
224
|
-
elsif e
|
218
|
+
elsif e.start_with?(' ', "\t")
|
225
219
|
# Continued line from the previous line
|
226
220
|
next if rfc822next[previousfn]
|
227
|
-
rfc822part
|
228
|
-
|
221
|
+
rfc822part << e + "\n" if LongHeaders.key?(previousfn)
|
229
222
|
else
|
230
223
|
# Check the end of headers in rfc822 part
|
231
224
|
next unless LongHeaders.key?(previousfn)
|
data/lib/sisimai/rhost.rb
CHANGED
@@ -7,10 +7,13 @@ module Sisimai
|
|
7
7
|
class << self
|
8
8
|
# Imported from p5-Sisimail/lib/Sisimai/Rhost.pm
|
9
9
|
RhostClass = {
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
10
|
+
'aspmx.l.google.com' => 'GoogleApps',
|
11
|
+
'.prod.outlook.com' => 'ExchangeOnline',
|
12
|
+
'.protection.outlook.com' => 'ExchangeOnline',
|
13
|
+
'smtp.secureserver.net' => 'GoDaddy',
|
14
|
+
'mailstore1.secureserver.net' => 'GoDaddy',
|
15
|
+
'laposte.net' => 'FrancePTT',
|
16
|
+
'orange.fr' => 'FrancePTT',
|
14
17
|
}.freeze
|
15
18
|
|
16
19
|
# Retrun the list of remote hosts Sisimai support
|
@@ -32,7 +35,7 @@ module Sisimai
|
|
32
35
|
|
33
36
|
RhostClass.each_key do |e|
|
34
37
|
# Try to match with each key of RhostClass
|
35
|
-
next unless host0
|
38
|
+
next unless host0.end_with?(e)
|
36
39
|
match = true
|
37
40
|
break
|
38
41
|
end
|
@@ -53,8 +56,8 @@ module Sisimai
|
|
53
56
|
|
54
57
|
RhostClass.each_key do |e|
|
55
58
|
# Try to match with each key of RhostClass
|
56
|
-
next unless remotehost
|
57
|
-
modulename = 'Sisimai::Rhost::'
|
59
|
+
next unless remotehost.end_with?(e)
|
60
|
+
modulename = 'Sisimai::Rhost::' << RhostClass[e]
|
58
61
|
rhostclass = modulename.gsub('::', '/').downcase
|
59
62
|
break
|
60
63
|
end
|
@@ -8,254 +8,103 @@ module Sisimai
|
|
8
8
|
# Imported from p5-Sisimail/lib/Sisimai/Rhost/ExchangeOnline.pm
|
9
9
|
|
10
10
|
# https://technet.microsoft.com/en-us/library/bb232118
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
],
|
11
|
+
StatusList = {
|
12
|
+
'4.3.1' => [{ reason: 'systemfull', string: 'Insufficient system resources' }],
|
13
|
+
'4.3.2' => [{ reason: 'notaccept', string: 'System not accepting network messages' }],
|
14
|
+
'4.4.2' => [{ reason: 'blocked', string: 'Connection dropped' }],
|
15
|
+
'4.7.26' => [{
|
16
|
+
reason: 'securityerror',
|
17
|
+
string: 'must pass either SPF or DKIM validation, this message is not signed'
|
18
|
+
}],
|
19
|
+
'5.0.0' => [{ reason: 'blocked', string: 'HELO / EHLO requires domain address' }],
|
20
|
+
'5.1.4' => [{ reason: 'systemerror', string: 'Destination mailbox address ambiguous' }],
|
21
|
+
'5.2.1' => [{ reason: 'suspend', string: 'Mailbox cannot be accessed' }],
|
22
|
+
'5.2.2' => [{ reason: 'mailboxfull', string: 'Mailbox full' }],
|
23
|
+
'5.2.3' => [{ reason: 'exceedlimit', string: 'Message too large' }],
|
24
|
+
'5.2.4' => [{ reason: 'systemerror', string: 'Mailing list expansion problem' }],
|
25
|
+
'5.3.3' => [{ reason: 'systemfull', string: 'Unrecognized command' }],
|
26
|
+
'5.3.4' => [{ reason: 'mesgtoobig', string: 'Message too big for system' }],
|
27
|
+
'5.3.5' => [{ reason: 'systemerror', string: 'System incorrectly configured' }],
|
28
|
+
'5.4.1' => [{ reason: 'userunknown', string: 'Recipient address rejected: Access denied' }],
|
29
|
+
'5.4.14' => [{ reason: 'networkerror',string: 'Hop count exceeded' }],
|
30
|
+
'5.5.2' => [{ reason: 'syntaxerror', string: 'Send hello first' }],
|
31
|
+
'5.5.3' => [{ reason: 'syntaxerror', string: 'Too many recipients' }],
|
32
|
+
'5.5.4' => [{ reason: 'filtered', string: 'Invalid domain name' }],
|
33
|
+
'5.5.6' => [{ reason: 'contenterror',string: 'Invalid message content' }],
|
34
|
+
'5.7.1' => [
|
35
|
+
{ reason: 'securityerror', string: 'Delivery not authorized' },
|
36
|
+
{ reason: 'securityerror', string: 'Client was not authenticated' },
|
37
|
+
{ reason: 'norelaying', string: 'Unable to relay' },
|
38
|
+
],
|
39
|
+
'5.7.25' => [{ reason: 'blocked', string: 'must have a reverse DNS record' }],
|
40
|
+
'5.7.506' => [{ reason: 'blocked', string: 'Bad HELO' }],
|
41
|
+
'5.7.508' => [{ reason: 'toomanyconn', string: 'has exceeded permitted limits within ' }],
|
42
|
+
'5.7.509' => [{ reason: 'rejected', string: 'does not pass DMARC verification' }],
|
43
|
+
'5.7.510' => [{ reason: 'notaccept', string: 'does not accept email over IPv6' }],
|
44
|
+
'5.7.511' => [{ reason: 'blocked', string: 'banned sender' }],
|
45
|
+
'5.7.512' => [{ reason: 'contenterror', string: 'message must be RFC 5322' }],
|
46
|
+
}.freeze
|
47
|
+
ReStatuses = {
|
24
48
|
%r/\A4[.]4[.][17]\z/ => [
|
25
|
-
|
26
|
-
:reason => 'expired',
|
27
|
-
:regexp => %r/(?:Connection[ ]timed[ ]out|Message[ ]expired)/x,
|
28
|
-
},
|
29
|
-
],
|
30
|
-
%r/\A4[.]4[.]2\z/ => [
|
31
|
-
{
|
32
|
-
:reason => 'blocked',
|
33
|
-
:regexp => %r/Connection dropped/,
|
34
|
-
},
|
35
|
-
],
|
36
|
-
%r/\A4[.]7[.]26\z/ => [
|
37
|
-
{
|
38
|
-
:reason => 'securityerror',
|
39
|
-
:regexp => %r/Access denied, a message sent over IPv6 .+ must pass either SPF or DKIM validation, this message is not signed/,
|
40
|
-
},
|
49
|
+
{ reason: 'expired', string: ['Connection timed out', 'Message expired'] }
|
41
50
|
],
|
42
|
-
%r/\A4[.]7[.][568]\d
|
43
|
-
|
44
|
-
:reason => 'securityerror',
|
45
|
-
:regexp => %r/Access denied, please try again later/,
|
46
|
-
},
|
47
|
-
],
|
48
|
-
%r/\A5[.]0[.]0\z/ => [
|
49
|
-
{
|
50
|
-
:reason => 'blocked',
|
51
|
-
:regexp => %r|HELO / EHLO requires domain address|,
|
52
|
-
},
|
51
|
+
%r/\A4[.]7[.][568]\d\d\z/ => [
|
52
|
+
{ reason: 'securityerror', string: ['Access denied, please try again later'] }
|
53
53
|
],
|
54
54
|
%r/\A5[.]1[.][07]\z/ => [
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
:
|
75
|
-
|
76
|
-
],
|
77
|
-
%r/\A5[.]
|
78
|
-
|
79
|
-
:
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
:
|
87
|
-
|
88
|
-
]
|
89
|
-
|
90
|
-
{
|
91
|
-
:reason => 'exceedlimit',
|
92
|
-
:regexp => %r/Message too large/,
|
93
|
-
},
|
94
|
-
],
|
95
|
-
%r/\A5[.]2[.]4\z/ => [
|
96
|
-
{
|
97
|
-
:reason => 'systemerror',
|
98
|
-
:regexp => %r/Mailing list expansion problem/,
|
99
|
-
},
|
100
|
-
],
|
101
|
-
%r/\A5[.]3[.]3\z/ => [
|
102
|
-
{
|
103
|
-
:reason => 'systemfull',
|
104
|
-
:regexp => %r/Unrecognized command/,
|
105
|
-
},
|
106
|
-
],
|
107
|
-
%r/\A5[.]3[.]4\z/ => [
|
108
|
-
{
|
109
|
-
:reason => 'mesgtoobig',
|
110
|
-
:regexp => %r/Message too big for system/,
|
111
|
-
},
|
112
|
-
],
|
113
|
-
%r/\A5[.]3[.]5\z/ => [
|
114
|
-
{
|
115
|
-
:reason => 'systemerror',
|
116
|
-
:regexp => %r/System incorrectly configured/,
|
117
|
-
},
|
118
|
-
],
|
119
|
-
%r/\A5[.]4[.]1\z/ => [
|
120
|
-
{
|
121
|
-
:reason => 'userunknown',
|
122
|
-
:regexp => %r/Recipient address rejected: Access denied/,
|
123
|
-
},
|
124
|
-
],
|
125
|
-
%r/\A5[.]4[.][46]\z/ => [
|
126
|
-
{
|
127
|
-
:reason => 'networkerror',
|
128
|
-
:regexp => %r/(?:Invalid[ ]arguments|Routing[ ]loop[ ]detected)/x,
|
129
|
-
},
|
130
|
-
],
|
131
|
-
%r/\A5[.]4[.]14\z/ => [
|
132
|
-
{
|
133
|
-
:reason => 'networkerror',
|
134
|
-
:regexp => %r/Hop[ ]count[ ]exceeded/x
|
135
|
-
},
|
136
|
-
],
|
137
|
-
%r/\A5[.]5[.]2\z/ => [
|
138
|
-
{
|
139
|
-
:reason => 'syntaxerror',
|
140
|
-
:regexp => %r/Send hello first/,
|
141
|
-
},
|
142
|
-
],
|
143
|
-
%r/\A5[.]5[.]3\z/ => [
|
144
|
-
{
|
145
|
-
:reason => 'syntaxerror',
|
146
|
-
:regexp => %r/Too many recipients/,
|
147
|
-
},
|
148
|
-
],
|
149
|
-
%r/\A5[.]5[.]4\z/ => [
|
150
|
-
{
|
151
|
-
:reason => 'filtered',
|
152
|
-
:regexp => %r/Invalid domain name/,
|
153
|
-
},
|
154
|
-
],
|
155
|
-
%r/\A5[.]5[.]6\z/ => [
|
156
|
-
{
|
157
|
-
:reason => 'contenterror',
|
158
|
-
:regexp => %r/Invalid message content/,
|
159
|
-
},
|
160
|
-
],
|
161
|
-
%r/\A5[.]7[.][13]\z/ => [
|
162
|
-
{
|
163
|
-
:reason => 'securityerror',
|
164
|
-
:regexp => %r/(?:Delivery[ ]not[ ]authorized|Not[ ]Authorized)/x,
|
165
|
-
},
|
166
|
-
],
|
167
|
-
%r/\A5[.]7[.]1\z/ => [
|
168
|
-
{
|
169
|
-
:reason => 'securityerror',
|
170
|
-
:regexp => %r/(?:Delivery[ ]not[ ]authorized|Client[ ]was[ ]not[ ]authenticated)/x,
|
171
|
-
},
|
172
|
-
{
|
173
|
-
:reason => 'norelaying',
|
174
|
-
:regexp => %r/Unable to relay/,
|
175
|
-
},
|
176
|
-
],
|
177
|
-
%r/\A5[.]7[.]25\z/ => [
|
178
|
-
{
|
179
|
-
:reason => 'securityerror',
|
180
|
-
:regexp => %r/Access denied, the sending IPv6 address .+ must have a reverse DNS record/,
|
181
|
-
},
|
182
|
-
],
|
183
|
-
%r/\A5[.]7[.]50[1-3]\z/ => [
|
184
|
-
{
|
185
|
-
:reason => 'spamdetected',
|
186
|
-
:regexp => %r/Access[ ]denied,[ ](?:spam[ ]abuse[ ]detected|banned[ ]sender)/x,
|
187
|
-
},
|
188
|
-
],
|
189
|
-
%r/\A5[.]7[.]50[457]\z/ => [
|
190
|
-
{
|
191
|
-
:reason => 'filtered',
|
192
|
-
:regexp => %r{(?>
|
193
|
-
Recipient[ ]address[ ]rejected:[ ]Access[ ]denied
|
194
|
-
|Access[ ]denied,[ ](?:banned[ ]recipient|rejected[ ]by[ ]recipient)
|
195
|
-
)
|
196
|
-
},
|
197
|
-
},
|
198
|
-
],
|
199
|
-
%r/\A5[.]7[.]506\z/ => [
|
200
|
-
{
|
201
|
-
:reason => 'blocked',
|
202
|
-
:regexp => %r/Access Denied, Bad HELO/,
|
203
|
-
},
|
204
|
-
],
|
205
|
-
%r/\A5[.]7[.]508\z/ => [
|
206
|
-
{
|
207
|
-
:reason => 'toomanyconn',
|
208
|
-
:regexp => %r/Access denied, .+ has exceeded permitted limits within .+ range/,
|
209
|
-
},
|
210
|
-
],
|
211
|
-
%r/\A5[.]7[.]509\z/ => [
|
212
|
-
{
|
213
|
-
:reason => 'securityerror',
|
214
|
-
:regexp => %r/Access denied, sending domain .+ does not pass DMARC verification/,
|
215
|
-
},
|
216
|
-
],
|
217
|
-
%r/\A5[.]7[.]510\z/ => [
|
218
|
-
{
|
219
|
-
:reason => 'notaccept',
|
220
|
-
:regexp => %r/Access denied, .+ does not accept email over IPv6/,
|
221
|
-
},
|
222
|
-
],
|
223
|
-
%r/\A5[.]7[.]511\z/ => [
|
224
|
-
{
|
225
|
-
:reason => 'blocked',
|
226
|
-
:regexp => %r/Access denied, banned sender/,
|
227
|
-
},
|
228
|
-
],
|
229
|
-
%r/\A5[.]7[.]512\z/ => [
|
230
|
-
{
|
231
|
-
:reason => 'contenterror',
|
232
|
-
:regexp => %r/Access denied, message must be RFC 5322 section 3[.]6[.]2 compliant/,
|
233
|
-
},
|
234
|
-
],
|
235
|
-
%r/\A5[.]7[.]6\d{2}\z/ => [
|
236
|
-
{
|
237
|
-
:reason => 'blocked',
|
238
|
-
:regexp => %r/Access[ ]denied,[ ]banned[ ]sending[ ]IP[ ].+/,
|
239
|
-
},
|
240
|
-
],
|
241
|
-
%r/\A5[.]7[.]7\d{2}\z/ => [
|
242
|
-
{
|
243
|
-
:reason => 'toomanyconn',
|
244
|
-
:regexp => %r/Access denied, tenant has exceeded threshold/,
|
245
|
-
},
|
55
|
+
{ reason: 'rejected', string: ['Sender denied', 'Invalid address'] }
|
56
|
+
],
|
57
|
+
%r/\A5[.]1[.][123]\z/ => [{
|
58
|
+
reason: 'userunknown',
|
59
|
+
string: [
|
60
|
+
'Bad destination mailbox address',
|
61
|
+
'Invalid X.400 address',
|
62
|
+
'Invalid recipient address',
|
63
|
+
]
|
64
|
+
}],
|
65
|
+
%r/\A5[.]4[.][46]\z/ => [{
|
66
|
+
reason: 'networkerror',
|
67
|
+
string: ['Invalid arguments', 'Routing loop detected'],
|
68
|
+
}],
|
69
|
+
%r/\A5[.]7[.][13]\z/ => [{
|
70
|
+
reason: 'securityerror',
|
71
|
+
string: ['Delivery not authorized', 'Not Authorized'],
|
72
|
+
}],
|
73
|
+
%r/\A5[.]7[.]50[1-3]\z/ => [{
|
74
|
+
reason: 'spamdetected',
|
75
|
+
string: ['Access denied, spam abuse detected', 'Access denied, banned sender'],
|
76
|
+
}],
|
77
|
+
%r/\A5[.]7[.]50[457]\z/ => [{
|
78
|
+
reason: 'filtered',
|
79
|
+
string: [
|
80
|
+
'Recipient address rejected: Access denied',
|
81
|
+
'Access denied, banned recipient',
|
82
|
+
'Access denied, rejected by recipient'
|
83
|
+
]
|
84
|
+
}],
|
85
|
+
%r/\A5[.]7[.]6\d\d\z/ => [
|
86
|
+
{ reason: 'blocked', string: ['Access denied, banned sending IP '] }
|
87
|
+
],
|
88
|
+
%r/\A5[.]7[.]7\d\d\z/ => [
|
89
|
+
{ reason: 'toomanyconn', string: ['Access denied, tenant has exceeded threshold'] }
|
246
90
|
],
|
247
91
|
}.freeze
|
248
|
-
|
92
|
+
MessagesOf = {
|
249
93
|
# Copied and converted from Sisimai::Bite::Email::Exchange2007
|
250
|
-
:
|
251
|
-
:
|
252
|
-
:
|
253
|
-
:
|
254
|
-
:
|
255
|
-
:
|
256
|
-
:
|
257
|
-
:
|
258
|
-
:
|
94
|
+
expired: ['QUEUE.Expired'],
|
95
|
+
hostunknown: ['SMTPSEND.DNS.NonExistentDomain'],
|
96
|
+
mesgtoobig: ['RESOLVER.RST.RecipSizeLimit', 'RESOLVER.RST.RecipientSizeLimit'],
|
97
|
+
networkerror: ['SMTPSEND.DNS.MxLoopback'],
|
98
|
+
rejected: ['RESOLVER.RST.NotAuthorized'],
|
99
|
+
securityerror: ['RESOLVER.RST.AuthRequired'],
|
100
|
+
systemerror: ['RESOLVER.ADR.Ambiguous', 'RESOLVER.ADR.BadPrimary', 'RESOLVER.ADR.InvalidInSmtp'],
|
101
|
+
toomanyconn: ['RESOLVER.ADR.RecipLimit', 'RESOLVER.ADR.RecipientLimit'],
|
102
|
+
userunknown: [
|
103
|
+
'RESOLVER.ADR.RecipNotFound',
|
104
|
+
'RESOLVER.ADR.RecipientNotFound',
|
105
|
+
'RESOLVER.ADR.ExRecipNotFound',
|
106
|
+
'RESOLVER.ADR.ExRecipientNotFound',
|
107
|
+
],
|
259
108
|
}.freeze
|
260
109
|
|
261
110
|
# Detect bounce reason from Exchange Online
|
@@ -270,28 +119,48 @@ module Sisimai
|
|
270
119
|
statusmesg = argvs.diagnosticcode
|
271
120
|
reasontext = ''
|
272
121
|
|
273
|
-
|
274
|
-
# Try to
|
275
|
-
next unless statuscode
|
276
|
-
|
277
|
-
# Try to
|
278
|
-
next unless statusmesg
|
122
|
+
StatusList.each_key do |e|
|
123
|
+
# Try to compare with each status code as a key
|
124
|
+
next unless statuscode == e
|
125
|
+
StatusList[e].each do |f|
|
126
|
+
# Try to compare with each string of error messages
|
127
|
+
next unless statusmesg.include?(f[:string])
|
279
128
|
reasontext = f[:reason]
|
280
129
|
break
|
281
130
|
end
|
131
|
+
break if reasontext.size > 0
|
282
132
|
end
|
283
133
|
|
284
134
|
if reasontext.empty?
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
135
|
+
ReStatuses.each_key do |e|
|
136
|
+
# Try to compare with each string of delivery status codes
|
137
|
+
next unless statuscode =~ e
|
138
|
+
ReStatuses[e].each do |f|
|
139
|
+
# Try to compare with each string of error messages
|
140
|
+
f[:string].each do |g|
|
141
|
+
next unless statusmesg.include?(g)
|
142
|
+
reasontext = f[:reason]
|
143
|
+
break
|
144
|
+
end
|
145
|
+
break if reasontext.size > 0
|
146
|
+
end
|
147
|
+
break if reasontext.size > 0
|
292
148
|
end
|
293
|
-
end
|
294
149
|
|
150
|
+
if reasontext.empty?
|
151
|
+
# D.S.N. included in the error message did not matched with any
|
152
|
+
# key in ReStatuses
|
153
|
+
MessagesOf.each_key do |e|
|
154
|
+
# Try to compare with error messages defined in MessagesOf
|
155
|
+
MessagesOf[e].each do |f|
|
156
|
+
next unless statusmesg.include?(f)
|
157
|
+
reasontext = e.to_s
|
158
|
+
break
|
159
|
+
end
|
160
|
+
break if reasontext.size > 0
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
295
164
|
return reasontext
|
296
165
|
end
|
297
166
|
|