sisimai 5.6.0 → 5.7.1
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 +4 -4
- data/.github/workflows/rake-test.yml +0 -4
- data/ChangeLog.md +47 -0
- data/README-JA.md +19 -16
- data/README.md +23 -21
- data/lib/sisimai/address.rb +8 -31
- data/lib/sisimai/arf.rb +5 -6
- data/lib/sisimai/eb.rb +116 -0
- data/lib/sisimai/fact.rb +33 -51
- data/lib/sisimai/lda.rb +20 -18
- data/lib/sisimai/lhost/activehunter.rb +0 -2
- data/lib/sisimai/lhost/amazonses.rb +17 -18
- data/lib/sisimai/lhost/apachejames.rb +0 -1
- data/lib/sisimai/lhost/biglobe.rb +0 -16
- data/lib/sisimai/lhost/courier.rb +9 -7
- data/lib/sisimai/lhost/deutschetelekom.rb +120 -0
- data/lib/sisimai/lhost/domino.rb +2 -4
- data/lib/sisimai/lhost/dragonfly.rb +0 -27
- data/lib/sisimai/lhost/einsundeins.rb +4 -12
- data/lib/sisimai/lhost/exchange2003.rb +12 -11
- data/lib/sisimai/lhost/exchange2007.rb +17 -17
- data/lib/sisimai/lhost/exim.rb +34 -81
- data/lib/sisimai/lhost/ezweb.rb +15 -51
- data/lib/sisimai/lhost/fml.rb +8 -32
- data/lib/sisimai/lhost/gmail.rb +10 -32
- data/lib/sisimai/lhost/gmx.rb +7 -24
- data/lib/sisimai/lhost/googlegroups.rb +6 -5
- data/lib/sisimai/lhost/googleworkspace.rb +2 -5
- data/lib/sisimai/lhost/imailserver.rb +4 -9
- data/lib/sisimai/lhost/kddi.rb +8 -21
- data/lib/sisimai/lhost/mailfoundry.rb +0 -2
- data/lib/sisimai/lhost/mailmarshal.rb +1 -3
- data/lib/sisimai/lhost/messagingserver.rb +4 -15
- data/lib/sisimai/lhost/mfilter.rb +0 -1
- data/lib/sisimai/lhost/mimecast.rb +0 -1
- data/lib/sisimai/lhost/notes.rb +3 -3
- data/lib/sisimai/lhost/opensmtpd.rb +0 -40
- data/lib/sisimai/lhost/postfix.rb +14 -14
- data/lib/sisimai/lhost/qmail.rb +23 -89
- data/lib/sisimai/lhost/sendmail.rb +8 -7
- data/lib/sisimai/lhost/trendmicro.rb +5 -4
- data/lib/sisimai/lhost/v5sendmail.rb +2 -2
- data/lib/sisimai/lhost/verizon.rb +4 -4
- data/lib/sisimai/lhost/x1.rb +1 -2
- data/lib/sisimai/lhost/x2.rb +0 -2
- data/lib/sisimai/lhost/x3.rb +4 -9
- data/lib/sisimai/lhost/x6.rb +0 -1
- data/lib/sisimai/lhost/zoho.rb +0 -12
- data/lib/sisimai/lhost.rb +38 -19
- data/lib/sisimai/message.rb +1 -1
- data/lib/sisimai/order.rb +4 -1
- data/lib/sisimai/reason/authfailure.rb +8 -7
- data/lib/sisimai/reason/badreputation.rb +5 -4
- data/lib/sisimai/reason/blocked.rb +6 -5
- data/lib/sisimai/reason/contenterror.rb +8 -5
- data/lib/sisimai/reason/delivered.rb +3 -2
- data/lib/sisimai/reason/emailtoolarge.rb +7 -6
- data/lib/sisimai/reason/expired.rb +16 -4
- data/lib/sisimai/reason/failedstarttls.rb +5 -3
- data/lib/sisimai/reason/feedback.rb +2 -1
- data/lib/sisimai/reason/filtered.rb +9 -8
- data/lib/sisimai/reason/hasmoved.rb +5 -4
- data/lib/sisimai/reason/hostunknown.rb +14 -4
- data/lib/sisimai/reason/mailboxfull.rb +10 -8
- data/lib/sisimai/reason/mailererror.rb +3 -2
- data/lib/sisimai/reason/networkerror.rb +16 -3
- data/lib/sisimai/reason/norelaying.rb +8 -6
- data/lib/sisimai/reason/notaccept.rb +15 -7
- data/lib/sisimai/reason/notcompliantrfc.rb +5 -3
- data/lib/sisimai/reason/onhold.rb +8 -7
- data/lib/sisimai/reason/policyviolation.rb +11 -5
- data/lib/sisimai/reason/ratelimited.rb +5 -4
- data/lib/sisimai/reason/rejected.rb +24 -14
- data/lib/sisimai/reason/requireptr.rb +5 -4
- data/lib/sisimai/reason/securityerror.rb +5 -3
- data/lib/sisimai/reason/spamdetected.rb +6 -5
- data/lib/sisimai/reason/suppressed.rb +4 -3
- data/lib/sisimai/reason/suspend.rb +8 -3
- data/lib/sisimai/reason/syntaxerror.rb +5 -11
- data/lib/sisimai/reason/systemerror.rb +21 -2
- data/lib/sisimai/reason/systemfull.rb +4 -3
- data/lib/sisimai/reason/undefined.rb +2 -1
- data/lib/sisimai/reason/userunknown.rb +15 -9
- data/lib/sisimai/reason/vacation.rb +2 -1
- data/lib/sisimai/reason/virusdetected.rb +6 -5
- data/lib/sisimai/reason.rb +47 -42
- data/lib/sisimai/rfc1123.rb +1 -1
- data/lib/sisimai/rfc1894.rb +15 -8
- data/lib/sisimai/rfc2045.rb +8 -5
- data/lib/sisimai/rfc3464/thirdparty.rb +11 -10
- data/lib/sisimai/rfc3464.rb +10 -14
- data/lib/sisimai/rfc3834.rb +6 -5
- data/lib/sisimai/rfc791.rb +3 -38
- data/lib/sisimai/rhost/aol.rb +3 -2
- data/lib/sisimai/rhost/apple.rb +12 -11
- data/lib/sisimai/rhost/cloudflare.rb +3 -2
- data/lib/sisimai/rhost/cox.rb +38 -37
- data/lib/sisimai/rhost/facebook.rb +17 -16
- data/lib/sisimai/rhost/franceptt.rb +39 -38
- data/lib/sisimai/rhost/godaddy.rb +35 -34
- data/lib/sisimai/rhost/google.rb +22 -21
- data/lib/sisimai/rhost/gsuite.rb +8 -7
- data/lib/sisimai/rhost/iua.rb +11 -10
- data/lib/sisimai/rhost/kddi.rb +3 -2
- data/lib/sisimai/rhost/messagelabs.rb +13 -12
- data/lib/sisimai/rhost/microsoft.rb +37 -32
- data/lib/sisimai/rhost/mimecast.rb +18 -17
- data/lib/sisimai/rhost/nttdocomo.rb +10 -9
- data/lib/sisimai/rhost/outlook.rb +3 -2
- data/lib/sisimai/rhost/spectrum.rb +19 -18
- data/lib/sisimai/rhost/tencent.rb +10 -9
- data/lib/sisimai/rhost/yahooinc.rb +11 -10
- data/lib/sisimai/rhost/zoho.rb +8 -7
- data/lib/sisimai/rhost.rb +1 -1
- data/lib/sisimai/smtp/command.rb +13 -8
- data/lib/sisimai/smtp/failure.rb +9 -8
- data/lib/sisimai/smtp/reply.rb +23 -22
- data/lib/sisimai/smtp/status.rb +164 -159
- data/lib/sisimai/smtp/transcript.rb +3 -2
- data/lib/sisimai/string.rb +0 -12
- data/lib/sisimai/version.rb +1 -1
- data/lib/sisimai.rb +2 -1
- data/set-of-emails/maildir/bsd/lhost-deutschetelekom-01.eml +66 -0
- data/set-of-emails/maildir/bsd/lhost-deutschetelekom-02.eml +68 -0
- data/set-of-emails/maildir/bsd/lhost-deutschetelekom-03.eml +50 -0
- data/set-of-emails/maildir/bsd/lhost-postfix-81.eml +130 -0
- data/set-of-emails/should-not-crash/go-423-deeply-nested-mime-parts.eml +20050 -0
- data/set-of-emails/should-not-crash/p5-664-iomart-mail-filter.eml +258 -0
- data/set-of-emails/to-be-debugged-because/sisimai-cannot-parse-yet/.gitkeep +0 -0
- metadata +11 -2
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
module Sisimai
|
|
2
2
|
module Reason
|
|
3
|
-
# Sisimai::Reason::VirusDetected checks the bounce reason is "
|
|
3
|
+
# Sisimai::Reason::VirusDetected checks the bounce reason is "VirusDetected" or not. This class
|
|
4
4
|
# is called only Sisimai::Reason class.
|
|
5
5
|
#
|
|
6
6
|
# This is an error that any virus or trojan horse detected in the message by a virus scanner program
|
|
7
|
-
# at a destination mail server. This reason has been divided from "
|
|
7
|
+
# at a destination mail server. This reason has been divided from "SecurityError" at Sisimai 4.22.0.
|
|
8
8
|
#
|
|
9
9
|
# Your message was infected with a virus. You should download a virus
|
|
10
10
|
# scanner and check your computer for viruses.
|
|
@@ -14,13 +14,14 @@ module Sisimai
|
|
|
14
14
|
#
|
|
15
15
|
module VirusDetected
|
|
16
16
|
class << self
|
|
17
|
+
require 'sisimai/eb'
|
|
17
18
|
Index = ["it has a potentially executable attachment"].freeze
|
|
18
19
|
Pairs = [
|
|
19
20
|
["message was ", "ected", " virus"],
|
|
20
21
|
["virus", " detected"],
|
|
21
22
|
].freeze
|
|
22
23
|
|
|
23
|
-
def text; return
|
|
24
|
+
def text; return Sisimai::Eb::ReEXEC; end
|
|
24
25
|
def description; return 'Email rejected due to a virus scanner on a destination host'; end
|
|
25
26
|
|
|
26
27
|
# Try to match that the given text and regular expressions
|
|
@@ -34,7 +35,7 @@ module Sisimai
|
|
|
34
35
|
return false
|
|
35
36
|
end
|
|
36
37
|
|
|
37
|
-
# The bounce reason is "
|
|
38
|
+
# The bounce reason is "VirusDetected" or not
|
|
38
39
|
# @param [Sisimai::Fact] argvs Object to be detected the reason
|
|
39
40
|
# @return [Boolean] true: virus detected
|
|
40
41
|
# false: virus was not detected
|
|
@@ -44,7 +45,7 @@ module Sisimai
|
|
|
44
45
|
# The value of "reason" isn't "visusdetected" when the value of "command" is an SMTP command
|
|
45
46
|
# to be sent before the SMTP DATA command because all the MTAs read the headers and the
|
|
46
47
|
# entire message body after the DATA command.
|
|
47
|
-
return true if argvs['reason'] ==
|
|
48
|
+
return true if argvs['reason'] == Sisimai::Eb::ReEXEC
|
|
48
49
|
return false if Sisimai::SMTP::Command::ExceptDATA.include?(argvs['command'])
|
|
49
50
|
return match(argvs['diagnosticcode'].downcase)
|
|
50
51
|
end
|
data/lib/sisimai/reason.rb
CHANGED
|
@@ -3,24 +3,28 @@ module Sisimai
|
|
|
3
3
|
# Sisimai::Fact object as an argument of find() method. This class is called only Sisimai::Fact.
|
|
4
4
|
module Reason
|
|
5
5
|
class << self
|
|
6
|
+
require 'sisimai/eb'
|
|
7
|
+
|
|
6
8
|
# All the error reason list Sisimai support
|
|
7
9
|
# @return [Array] Reason list
|
|
8
10
|
def index
|
|
9
|
-
return
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
return [
|
|
12
|
+
Sisimai::Eb::ReAUTH, Sisimai::Eb::ReFAMA, Sisimai::Eb::ReBLOC, Sisimai::Eb::ReBODY, Sisimai::Eb::ReSIZE,
|
|
13
|
+
Sisimai::Eb::ReTIME, Sisimai::Eb::ReTTLS, Sisimai::Eb::ReFILT, Sisimai::Eb::ReMOVE, Sisimai::Eb::ReHOST,
|
|
14
|
+
Sisimai::Eb::ReFULL, Sisimai::Eb::ReUNIX, Sisimai::Eb::ReINET, Sisimai::Eb::Re00MX, Sisimai::Eb::ReNRFC,
|
|
15
|
+
Sisimai::Eb::ReRATE, Sisimai::Eb::Re___1, Sisimai::Eb::ReFROM, Sisimai::Eb::RePASS, Sisimai::Eb::ReSPAM,
|
|
16
|
+
Sisimai::Eb::ReEXEC, Sisimai::Eb::ReWONT, Sisimai::Eb::ReSAFE, Sisimai::Eb::ReQUIT, Sisimai::Eb::ReQPTR,
|
|
17
|
+
Sisimai::Eb::RePROC, Sisimai::Eb::ReDISK, Sisimai::Eb::ReSTOP, Sisimai::Eb::ReUSER, Sisimai::Eb::ReCOMM,
|
|
14
18
|
]
|
|
15
19
|
end
|
|
16
20
|
|
|
17
|
-
# @abstract is_explicit() returns 0 when the argument is empty or is "
|
|
21
|
+
# @abstract is_explicit() returns 0 when the argument is empty or is "Undefined" or is "OnHold"
|
|
18
22
|
# @param string argv1 Reason name
|
|
19
23
|
# @return bool false: The reaosn is not explicit
|
|
20
24
|
def is_explicit(argv1 = '')
|
|
21
25
|
return false if argv1.nil?
|
|
22
26
|
return false if argv1.empty?
|
|
23
|
-
return false if argv1 ==
|
|
27
|
+
return false if argv1 == Sisimai::Eb::Re___0 || argv1 == Sisimai::Eb::Re___1 || argv1.empty?
|
|
24
28
|
return true
|
|
25
29
|
end
|
|
26
30
|
|
|
@@ -38,29 +42,30 @@ module Sisimai
|
|
|
38
42
|
# @return [Hash] Reason list
|
|
39
43
|
def retry
|
|
40
44
|
return {
|
|
41
|
-
|
|
42
|
-
|
|
45
|
+
Sisimai::Eb::Re___0 => true, Sisimai::Eb::Re___1 => true, Sisimai::Eb::RePROC => true,
|
|
46
|
+
Sisimai::Eb::ReSAFE => true, Sisimai::Eb::ReTIME => true, Sisimai::Eb::ReINET => true,
|
|
47
|
+
Sisimai::Eb::ReHOST => true, Sisimai::Eb::ReUSER => true,
|
|
43
48
|
}.freeze
|
|
44
49
|
end
|
|
45
50
|
ModulePath = Sisimai::Reason.path
|
|
46
51
|
GetRetried = Sisimai::Reason.retry
|
|
47
52
|
ClassOrder = [
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
53
|
+
# 0. true() meethod in the following reasons are called from Reason->find()
|
|
54
|
+
[Sisimai::Eb::ReFULL, Sisimai::Eb::ReSIZE, Sisimai::Eb::ReQUIT, Sisimai::Eb::ReMOVE, Sisimai::Eb::RePASS,
|
|
55
|
+
Sisimai::Eb::ReAUTH, Sisimai::Eb::ReUSER, Sisimai::Eb::ReFILT, Sisimai::Eb::ReQPTR, Sisimai::Eb::ReNRFC,
|
|
56
|
+
Sisimai::Eb::ReFAMA, Sisimai::Eb::ReBODY, Sisimai::Eb::ReFROM, Sisimai::Eb::ReHOST, Sisimai::Eb::ReSPAM,
|
|
57
|
+
Sisimai::Eb::ReRATE, Sisimai::Eb::ReBLOC, Sisimai::Eb::ReTTLS, Sisimai::Eb::Re00MX, Sisimai::Eb::ReEXEC,
|
|
58
|
+
Sisimai::Eb::ReWONT],
|
|
59
|
+
|
|
60
|
+
# 1. match() method in the following reasons are called from Reason->find()
|
|
61
|
+
[Sisimai::Eb::ReFULL, Sisimai::Eb::ReSPAM, Sisimai::Eb::ReEXEC, Sisimai::Eb::RePASS, Sisimai::Eb::RePROC,
|
|
62
|
+
Sisimai::Eb::ReINET, Sisimai::Eb::ReQUIT, Sisimai::Eb::ReDISK, Sisimai::Eb::ReSTOP, Sisimai::Eb::ReUNIX,
|
|
63
|
+
Sisimai::Eb::ReSAFE, Sisimai::Eb::ReWONT, Sisimai::Eb::ReCOMM, Sisimai::Eb::ReTIME],
|
|
64
|
+
[Sisimai::Eb::ReFULL, Sisimai::Eb::ReSIZE, Sisimai::Eb::ReQUIT, Sisimai::Eb::ReUSER, Sisimai::Eb::ReFILT,
|
|
65
|
+
Sisimai::Eb::ReFROM, Sisimai::Eb::ReHOST, Sisimai::Eb::ReSPAM, Sisimai::Eb::ReRATE, Sisimai::Eb::ReBLOC,
|
|
66
|
+
Sisimai::Eb::ReAUTH, Sisimai::Eb::ReTTLS, Sisimai::Eb::ReSAFE, Sisimai::Eb::RePROC, Sisimai::Eb::ReINET,
|
|
67
|
+
Sisimai::Eb::ReTIME, Sisimai::Eb::ReBODY, Sisimai::Eb::ReMOVE, Sisimai::Eb::ReDISK, Sisimai::Eb::Re00MX,
|
|
68
|
+
Sisimai::Eb::ReUNIX, Sisimai::Eb::RePASS, Sisimai::Eb::ReSTOP, Sisimai::Eb::ReCOMM, Sisimai::Eb::Re___1],
|
|
64
69
|
]
|
|
65
70
|
|
|
66
71
|
# Detect the bounce reason
|
|
@@ -74,7 +79,7 @@ module Sisimai
|
|
|
74
79
|
# retry() method.
|
|
75
80
|
return argvs['reason'] if argvs['reason'].empty? == false
|
|
76
81
|
end
|
|
77
|
-
return
|
|
82
|
+
return Sisimai::Eb::ReSENT if argvs['deliverystatus'].start_with?('2.')
|
|
78
83
|
|
|
79
84
|
reasontext = ''
|
|
80
85
|
issuedcode = argvs['diagnosticcode'] || ''
|
|
@@ -100,21 +105,21 @@ module Sisimai
|
|
|
100
105
|
end
|
|
101
106
|
end
|
|
102
107
|
|
|
103
|
-
if reasontext.empty? || reasontext ==
|
|
108
|
+
if reasontext.empty? || reasontext == Sisimai::Eb::Re___0
|
|
104
109
|
# Bounce reason is not detected yet.
|
|
105
110
|
reasontext = self.anotherone(argvs)
|
|
106
111
|
|
|
107
|
-
if reasontext ==
|
|
112
|
+
if reasontext == Sisimai::Eb::Re___0 || reasontext.empty?
|
|
108
113
|
# Action: delayed => "expired"
|
|
109
114
|
reasontext = nil
|
|
110
|
-
reasontext ||=
|
|
115
|
+
reasontext ||= Sisimai::Eb::ReTIME if argvs['action'] == Sisimai::Eb::AeSTAY
|
|
111
116
|
return reasontext if reasontext
|
|
112
117
|
|
|
113
118
|
# Try to match with message patterns in Sisimai::Reason::Vacation
|
|
114
119
|
require 'sisimai/reason/vacation'
|
|
115
|
-
reasontext =
|
|
116
|
-
reasontext ||=
|
|
117
|
-
reasontext ||=
|
|
120
|
+
reasontext = Sisimai::Eb::ReAWAY if Sisimai::Reason::Vacation.match(issuedcode.downcase)
|
|
121
|
+
reasontext ||= Sisimai::Eb::Re___1 if issuedcode.empty? == false
|
|
122
|
+
reasontext ||= Sisimai::Eb::Re___0
|
|
118
123
|
end
|
|
119
124
|
end
|
|
120
125
|
return reasontext
|
|
@@ -151,7 +156,7 @@ module Sisimai
|
|
|
151
156
|
end
|
|
152
157
|
|
|
153
158
|
next if r.match(issuedcode) == false
|
|
154
|
-
reasontext = e
|
|
159
|
+
reasontext = e
|
|
155
160
|
break
|
|
156
161
|
end
|
|
157
162
|
break if reasontext.empty? == false
|
|
@@ -160,31 +165,31 @@ module Sisimai
|
|
|
160
165
|
code2digit = statuscode[0, 3] || ''
|
|
161
166
|
if code2digit == '5.6' || code2digit == '4.6'
|
|
162
167
|
# X.6.0 Other or undefined media error
|
|
163
|
-
reasontext =
|
|
168
|
+
reasontext = Sisimai::Eb::ReBODY
|
|
164
169
|
|
|
165
170
|
elsif code2digit == '5.7' || code2digit == '4.7'
|
|
166
171
|
# X.7.0 Other or undefined security status
|
|
167
|
-
reasontext =
|
|
172
|
+
reasontext = Sisimai::Eb::ReSAFE
|
|
168
173
|
|
|
169
174
|
elsif codeformat.start_with?('X-UNIX')
|
|
170
175
|
# Diagnostic-Code: X-UNIX; ...
|
|
171
|
-
reasontext =
|
|
176
|
+
reasontext = Sisimai::Eb::ReUNIX
|
|
172
177
|
|
|
173
178
|
else
|
|
174
179
|
# 50X Syntax Error?
|
|
175
180
|
require 'sisimai/reason/syntaxerror'
|
|
176
|
-
reasontext =
|
|
181
|
+
reasontext = Sisimai::Eb::ReCOMM if Sisimai::Reason::SyntaxError.true(argvs)
|
|
177
182
|
end
|
|
178
183
|
break if reasontext.empty? == false
|
|
179
184
|
|
|
180
185
|
# Check the value of Action: field, first
|
|
181
|
-
if actiontext.start_with?(
|
|
186
|
+
if actiontext.start_with?(Sisimai::Eb::AeSTAY, 'expired')
|
|
182
187
|
# Action: delayed, expired
|
|
183
|
-
reasontext =
|
|
188
|
+
reasontext = Sisimai::Eb::ReTIME
|
|
184
189
|
else
|
|
185
190
|
# Rejected at connection or after EHLO|HELO
|
|
186
191
|
thecommand = argvs['command'] || ''
|
|
187
|
-
reasontext =
|
|
192
|
+
reasontext = Sisimai::Eb::ReBLOC if %w[HELO EHLO].index(thecommand)
|
|
188
193
|
end
|
|
189
194
|
break
|
|
190
195
|
end
|
|
@@ -222,12 +227,12 @@ module Sisimai
|
|
|
222
227
|
|
|
223
228
|
if issuedcode.upcase.include?('X-UNIX; ')
|
|
224
229
|
# X-Unix; ...
|
|
225
|
-
reasontext =
|
|
230
|
+
reasontext = Sisimai::Eb::ReUNIX
|
|
226
231
|
else
|
|
227
232
|
# Detect the bounce reason from "Status:" code
|
|
228
233
|
require 'sisimai/smtp/status'
|
|
229
234
|
reasontext = Sisimai::SMTP::Status.name(Sisimai::SMTP::Status.find(argv1))
|
|
230
|
-
reasontext =
|
|
235
|
+
reasontext = Sisimai::Eb::Re___0 if reasontext.empty?
|
|
231
236
|
end
|
|
232
237
|
return reasontext
|
|
233
238
|
end
|
data/lib/sisimai/rfc1123.rb
CHANGED
|
@@ -125,7 +125,7 @@ module Sisimai
|
|
|
125
125
|
sourcetext = sourcetext.gsub("[", " [").gsub("(", " (").gsub("<", " <") # Prefix a space character before each bracket
|
|
126
126
|
sourcetext = sourcetext.gsub("]", "] ").gsub(")", ") ").gsub(">", "> ") # Suffix a space character behind each bracket
|
|
127
127
|
sourcetext = sourcetext.gsub(":", ": ").gsub(";", "; ") # Suffix a space character behind : and ;
|
|
128
|
-
sourcetext =
|
|
128
|
+
sourcetext = sourcetext.split.join(" ")
|
|
129
129
|
|
|
130
130
|
catch :MAKELIST do
|
|
131
131
|
Sandwiched.each do |e|
|
data/lib/sisimai/rfc1894.rb
CHANGED
|
@@ -2,6 +2,7 @@ module Sisimai
|
|
|
2
2
|
# Sisimai::RFC1894 DSN field defined in RFC3464 (obsoletes RFC1894)
|
|
3
3
|
module RFC1894
|
|
4
4
|
class << self
|
|
5
|
+
require 'sisimai/eb'
|
|
5
6
|
require 'sisimai/string'
|
|
6
7
|
FieldNames = [
|
|
7
8
|
# https://tools.ietf.org/html/rfc3464#section-2.2
|
|
@@ -58,8 +59,13 @@ module Sisimai
|
|
|
58
59
|
}.freeze
|
|
59
60
|
|
|
60
61
|
SubtypeSet = {"addr" => "RFC822", "cdoe" => "SMTP", "host" => "DNS"}.freeze
|
|
61
|
-
ActionList = [
|
|
62
|
-
|
|
62
|
+
ActionList = [Sisimai::Eb::AeFAIL, Sisimai::Eb::AeSTAY, Sisimai::Eb::AeSENT,
|
|
63
|
+
Sisimai::Eb::AePASS, Sisimai::Eb::AeEXPN].freeze
|
|
64
|
+
Correction = {
|
|
65
|
+
'deliverable' => Sisimai::Eb::AeSENT,
|
|
66
|
+
'expired' => Sisimai::Eb::AeFAIL,
|
|
67
|
+
'failure' => Sisimai::Eb::AeFAIL,
|
|
68
|
+
}
|
|
63
69
|
FieldGroup = {
|
|
64
70
|
'original-recipient' => 'addr',
|
|
65
71
|
'final-recipient' => 'addr',
|
|
@@ -146,7 +152,7 @@ module Sisimai
|
|
|
146
152
|
return nil if argv0.empty?
|
|
147
153
|
label = Sisimai::RFC1894.label(argv0)
|
|
148
154
|
group = FieldGroup[label] || ''
|
|
149
|
-
parts = argv0.split(":", 2); parts[1] = parts[1].nil? ? "" :
|
|
155
|
+
parts = argv0.split(":", 2); parts[1] = parts[1].nil? ? "" : parts[1].split.join(" ")
|
|
150
156
|
return nil if group.empty? || CapturesOn[group].nil?
|
|
151
157
|
|
|
152
158
|
# Try to match with each pattern of Per-Message field, Per-Recipient field
|
|
@@ -157,24 +163,25 @@ module Sisimai
|
|
|
157
163
|
# - 4: Comment
|
|
158
164
|
table = [label, "", "", group, ""]
|
|
159
165
|
|
|
160
|
-
|
|
166
|
+
case group
|
|
167
|
+
when "addr", "code", "host"
|
|
161
168
|
# - Final-Recipient: RFC822; kijitora@nyaan.jp
|
|
162
169
|
# - Diagnostic-Code: SMTP; 550 5.1.1 <kijitora@example.jp>... User Unknown
|
|
163
170
|
# - Remote-MTA: DNS; mx.example.jp
|
|
164
171
|
if parts[1].include?(";")
|
|
165
172
|
# There is a valid sub type (including ";")
|
|
166
173
|
v = parts[1].split(";", 2)
|
|
167
|
-
table[1] =
|
|
168
|
-
table[2] =
|
|
174
|
+
table[1] = v[0].split.join(" ").upcase if v.size > 0
|
|
175
|
+
table[2] = v[1].split.join(" ") if v.size > 1
|
|
169
176
|
else
|
|
170
177
|
# There is no sub type like "Diagnostic-Code: 550 5.1.1 <kijitora@example.jp>..."
|
|
171
|
-
table[2] =
|
|
178
|
+
table[2] = parts[1]
|
|
172
179
|
table[1] = SubtypeSet[group] || ""
|
|
173
180
|
end
|
|
174
181
|
table[2] = table[2].downcase if group == "host"
|
|
175
182
|
table[2] = "" if table[2] =~ /\A\s+\z/
|
|
176
183
|
|
|
177
|
-
|
|
184
|
+
when "list"
|
|
178
185
|
# Action: failed
|
|
179
186
|
# Check that the value is an available value defined in "ActionList" or not.
|
|
180
187
|
# When the value is invalid, convert to an available value defined in "Correction"
|
data/lib/sisimai/rfc2045.rb
CHANGED
|
@@ -146,7 +146,7 @@ module Sisimai
|
|
|
146
146
|
return nil if block.empty?
|
|
147
147
|
|
|
148
148
|
(upperchunk, lowerchunk) = block.split("\n\n", 2)
|
|
149
|
-
return ['', ''] if upperchunk.nil? || upperchunk.empty?
|
|
149
|
+
return ['', ''] if upperchunk.nil? || upperchunk.empty? || lowerchunk.nil?
|
|
150
150
|
return ['', ''] if upperchunk.index('Content-Type').nil?
|
|
151
151
|
|
|
152
152
|
headerpart = ['', ''] # ["text/plain; charset=iso-2022-jp; ...", "quoted-printable"]
|
|
@@ -213,14 +213,17 @@ module Sisimai
|
|
|
213
213
|
# Split argv1: multipart/* blocks by a boundary string in argv0
|
|
214
214
|
# @param [String] argv0 The value of Content-Type header
|
|
215
215
|
# @param [String] argv1 A pointer to multipart/* message blocks
|
|
216
|
+
# @param [String] depth Depth of MIME parts
|
|
216
217
|
# @return [Array] List of each part of multipart/*
|
|
217
218
|
# @since v5.0.0
|
|
218
|
-
def levelout(argv0 = '', argv1 = '')
|
|
219
|
+
def levelout(argv0 = '', argv1 = '', depth = 0)
|
|
219
220
|
return [] if argv0.empty?
|
|
220
221
|
return [] if argv1.empty?
|
|
222
|
+
return [] if depth > 100
|
|
221
223
|
|
|
222
224
|
boundary01 = boundary(argv0, 0); return [] if boundary01.empty?
|
|
223
225
|
multiparts = argv1.split(Regexp.new(Regexp.escape(boundary01) + "\n"))
|
|
226
|
+
partsdepth = depth + 1
|
|
224
227
|
partstable = []
|
|
225
228
|
|
|
226
229
|
# Remove empty or useless preamble and epilogue of multipart/* block
|
|
@@ -237,7 +240,7 @@ module Sisimai
|
|
|
237
240
|
bodyinside = f[-1].split("\n\n", 2)[-1]
|
|
238
241
|
next if bodyinside.size < 9 || bodyinside.index(boundary02).nil?
|
|
239
242
|
|
|
240
|
-
v = levelout(f[0], bodyinside)
|
|
243
|
+
v = levelout(f[0], bodyinside, partsdepth)
|
|
241
244
|
partstable += v if v.size > 0
|
|
242
245
|
else
|
|
243
246
|
# The part is not a multipart/* block
|
|
@@ -263,7 +266,7 @@ module Sisimai
|
|
|
263
266
|
# @return [String] Message body
|
|
264
267
|
def makeflat(argv0 = '', argv1 = '')
|
|
265
268
|
return "" if argv0.nil? || argv1.nil?
|
|
266
|
-
return "" if argv0.index('multipart/') == false || argv0.index('boundary=') == false
|
|
269
|
+
return "" if argv0.downcase.index('multipart/') == false || argv0.downcase.index('boundary=') == false
|
|
267
270
|
|
|
268
271
|
# Some bounce messages include lower-cased "content-type:" field such as the followings:
|
|
269
272
|
# - content-type: message/delivery-status => Content-Type: message/delivery-status
|
|
@@ -271,7 +274,7 @@ module Sisimai
|
|
|
271
274
|
# - CHARSET=, BOUNDARY= => charset-, boundary=
|
|
272
275
|
# - message/xdelivery-status => message/delivery-status
|
|
273
276
|
iso2022set = %r/charset=["']?(iso-2022-[-a-z0-9]+)['"]?\b/
|
|
274
|
-
multiparts = levelout(argv0, argv1)
|
|
277
|
+
multiparts = levelout(argv0, argv1, 0)
|
|
275
278
|
flattenout = ''
|
|
276
279
|
delimiters = ["/delivery-status", "/rfc822", "/feedback-report", "/partial"]
|
|
277
280
|
|
|
@@ -2,6 +2,7 @@ module Sisimai
|
|
|
2
2
|
module RFC3464
|
|
3
3
|
module ThirdParty
|
|
4
4
|
class << self
|
|
5
|
+
require 'sisimai/eb'
|
|
5
6
|
ThirdParty = {
|
|
6
7
|
#"Aol" => ["X-Outbound-Mail-Relay-"], # X-Outbound-Mail-Relay-(Queue-ID|Sender)
|
|
7
8
|
"PowerMTA" => ["X-PowerMTA-"], # X-PowerMTA-(VirtualMTA|BounceCategory)
|
|
@@ -50,15 +51,15 @@ module Sisimai
|
|
|
50
51
|
"x-powermta-bouncecategory" => "text", # X-PowerMTA-BounceCategory: bad-mailbox
|
|
51
52
|
}.freeze
|
|
52
53
|
MessagesOf = {
|
|
53
|
-
"bad-domain" =>
|
|
54
|
-
"bad-mailbox" =>
|
|
55
|
-
"inactive-mailbox" =>
|
|
56
|
-
"message-expired" =>
|
|
57
|
-
"no-answer-from-host" =>
|
|
58
|
-
"policy-related" =>
|
|
59
|
-
"quota-issues" =>
|
|
60
|
-
"routing-errors" =>
|
|
61
|
-
"spam-related" =>
|
|
54
|
+
"bad-domain" => Sisimai::Eb::ReHOST,
|
|
55
|
+
"bad-mailbox" => Sisimai::Eb::ReUSER,
|
|
56
|
+
"inactive-mailbox" => Sisimai::Eb::ReQUIT,
|
|
57
|
+
"message-expired" => Sisimai::Eb::ReTIME,
|
|
58
|
+
"no-answer-from-host" => Sisimai::Eb::ReINET,
|
|
59
|
+
"policy-related" => Sisimai::Eb::ReWONT,
|
|
60
|
+
"quota-issues" => Sisimai::Eb::ReFULL,
|
|
61
|
+
"routing-errors" => Sisimai::Eb::RePROC,
|
|
62
|
+
"spam-related" => Sisimai::Eb::ReSPAM,
|
|
62
63
|
}.freeze
|
|
63
64
|
|
|
64
65
|
# Returns an array which is compatible with the value returned from Sisimai::RFC1894->field()
|
|
@@ -71,7 +72,7 @@ module Sisimai
|
|
|
71
72
|
fieldparts = argv1.split(":", 2)
|
|
72
73
|
xfieldname = fieldparts[0].downcase
|
|
73
74
|
xgroupname = FieldGroup[xfieldname]; return [] if xgroupname.nil?
|
|
74
|
-
xfieldlist = ["", "",
|
|
75
|
+
xfieldlist = ["", "", fieldparts[1].split.join(" "), xgroupname, "", "PowerMTA"]
|
|
75
76
|
|
|
76
77
|
# - 0: Field-Name
|
|
77
78
|
# - 1: Sub Type: RFC822, DNS, X-Unix, and so on)
|
data/lib/sisimai/rfc3464.rb
CHANGED
|
@@ -109,16 +109,12 @@ module Sisimai
|
|
|
109
109
|
if isboundary.any? { |a| e == a } then goestonext = false; break; end
|
|
110
110
|
if e.start_with?("Content-Type:")
|
|
111
111
|
# Content-Type: field in multipart/*
|
|
112
|
-
|
|
112
|
+
case
|
|
113
113
|
# Content-Type: multipart/alternative; boundary=aa00220022222222ffeebb
|
|
114
114
|
# Pick the boundary string and store it into "isboucdary"
|
|
115
|
-
isboundary << Sisimai::RFC2045.boundary(e, 0)
|
|
116
|
-
|
|
117
|
-
#
|
|
118
|
-
goestonext = false
|
|
119
|
-
else
|
|
120
|
-
# Other types: for example, text/html, image/jpg, and so on
|
|
121
|
-
goestonext = true
|
|
115
|
+
when e.include?("multipart/") then isboundary << Sisimai::RFC2045.boundary(e, 0)
|
|
116
|
+
when e.include?("text/plain") then goestonext = false
|
|
117
|
+
else goestonext = true # Other types: for example, text/html, image/jpg, and so on
|
|
122
118
|
end
|
|
123
119
|
break
|
|
124
120
|
end
|
|
@@ -145,7 +141,8 @@ module Sisimai
|
|
|
145
141
|
next unless o = Sisimai::RFC1894.field(e)
|
|
146
142
|
v = dscontents[-1]
|
|
147
143
|
|
|
148
|
-
|
|
144
|
+
case o[3]
|
|
145
|
+
when "addr"
|
|
149
146
|
# Final-Recipient: rfc822; kijitora@example.jp
|
|
150
147
|
# X-Actual-Recipient: rfc822; kijitora@example.co.jp
|
|
151
148
|
if o[0] == "final-recipient"
|
|
@@ -165,7 +162,7 @@ module Sisimai
|
|
|
165
162
|
# X-Actual-Recipient: rfc822; kijitora@example.co.jp
|
|
166
163
|
v["alias"] = o[2]
|
|
167
164
|
end
|
|
168
|
-
|
|
165
|
+
when "code"
|
|
169
166
|
# Diagnostic-Code: SMTP; 550 5.1.1 <userunknown@example.jp>... User Unknown
|
|
170
167
|
v["spec"] = o[1]
|
|
171
168
|
v["diagnosis"] = o[2]
|
|
@@ -212,7 +209,7 @@ module Sisimai
|
|
|
212
209
|
# Diagnostic-Code: SMTP; 550-5.7.26 The MAIL FROM domain [email.example.jp]
|
|
213
210
|
# has an SPF record with a hard fail
|
|
214
211
|
next if e.start_with?(" ") == false
|
|
215
|
-
v["diagnosis"] += "
|
|
212
|
+
v["diagnosis"] += " " + e
|
|
216
213
|
end
|
|
217
214
|
end
|
|
218
215
|
end
|
|
@@ -232,7 +229,7 @@ module Sisimai
|
|
|
232
229
|
|
|
233
230
|
if beforemesg != ""
|
|
234
231
|
# Pick some values of $dscontents from the string before StartingOf[:message]
|
|
235
|
-
beforemesg =
|
|
232
|
+
beforemesg = beforemesg.split.join(" ")
|
|
236
233
|
alternates["command"] = Sisimai::SMTP::Command.find(beforemesg)
|
|
237
234
|
alternates["replycode"] = Sisimai::SMTP::Reply.find(beforemesg, dscontents[0]["status"])
|
|
238
235
|
alternates["status"] = Sisimai::SMTP::Status.find(beforemesg, alternates["replycode"])
|
|
@@ -242,7 +239,6 @@ module Sisimai
|
|
|
242
239
|
dscontents.each do |e|
|
|
243
240
|
# Set default values stored in "permessage" if each value in "dscontents" is empty.
|
|
244
241
|
permessage.each_key { |a| e[a] ||= permessage[a] || '' }
|
|
245
|
-
e["diagnosis"] = Sisimai::String.sweep(e["diagnosis"])
|
|
246
242
|
lowercased = e["diagnosis"].downcase
|
|
247
243
|
|
|
248
244
|
if recipients == 1
|
|
@@ -254,7 +250,7 @@ module Sisimai
|
|
|
254
250
|
else
|
|
255
251
|
# The value of e["diagnosis"] is not contained in $beforemesg
|
|
256
252
|
# There may be an important error message in $beforemesg
|
|
257
|
-
e["diagnosis"] =
|
|
253
|
+
e["diagnosis"] = sprintf("%s %s", beforemesg, e["diagnosis"])
|
|
258
254
|
end
|
|
259
255
|
end
|
|
260
256
|
e["command"] = Sisimai::SMTP::Command.find(e["diagnosis"])
|
data/lib/sisimai/rfc3834.rb
CHANGED
|
@@ -3,6 +3,8 @@ module Sisimai
|
|
|
3
3
|
module RFC3834
|
|
4
4
|
class << self
|
|
5
5
|
# http://tools.ietf.org/html/rfc3834
|
|
6
|
+
require 'sisimai/eb'
|
|
7
|
+
|
|
6
8
|
MarkingsOf = {:boundary => '__SISIMAI_PSEUDO_BOUNDARY__'}
|
|
7
9
|
LowerLabel = %w[from to subject auto-submitted precedence x-apple-action].freeze
|
|
8
10
|
DoNotParse = {
|
|
@@ -116,19 +118,18 @@ module Sisimai
|
|
|
116
118
|
break if haveloaded >= maxmsgline
|
|
117
119
|
end
|
|
118
120
|
v['diagnosis'] ||= mhead['subject']
|
|
119
|
-
v['
|
|
120
|
-
v['reason'] = 'vacation'
|
|
121
|
+
v['reason'] = Sisimai::Eb::ReAWAY
|
|
121
122
|
|
|
122
123
|
cv = v['diagnosis'].downcase
|
|
123
124
|
Suspending.each do |e|
|
|
124
125
|
# Check that the auto-replied message indicates the "Suspend" reason or not.
|
|
125
126
|
next unless Sisimai::String.aligned(cv, e)
|
|
126
|
-
v['reason'] =
|
|
127
|
+
v['reason'] = Sisimai::Eb::ReQUIT
|
|
127
128
|
break
|
|
128
129
|
end
|
|
129
130
|
|
|
130
|
-
v['date']
|
|
131
|
-
v['status']
|
|
131
|
+
v['date'] = mhead['date']
|
|
132
|
+
v['status'] = ''
|
|
132
133
|
|
|
133
134
|
if cv = lower['subject'].match(SubjectSet)
|
|
134
135
|
# Get the Subject header from the original message
|
data/lib/sisimai/rfc791.rb
CHANGED
|
@@ -12,8 +12,7 @@ module Sisimai
|
|
|
12
12
|
|
|
13
13
|
octet.each do |e|
|
|
14
14
|
# Check each octet is between 0 and 255
|
|
15
|
-
return false unless e =~ /\A[0-9]{1,3}\z
|
|
16
|
-
v = e.to_i
|
|
15
|
+
return false unless e =~ /\A[0-9]{1,3}\z/; v = e.to_i
|
|
17
16
|
return false if v < 0 || v > 255
|
|
18
17
|
end
|
|
19
18
|
return true
|
|
@@ -27,42 +26,8 @@ module Sisimai
|
|
|
27
26
|
return nil if argv0.to_s.empty?
|
|
28
27
|
return [] if argv0.size < 7
|
|
29
28
|
|
|
30
|
-
given = argv0.dup
|
|
31
|
-
|
|
32
|
-
%w|( ) [ ] ,|.each do |e|
|
|
33
|
-
# Rewrite: "mx.example.jp[192.0.2.1]" => "mx.example.jp 192.0.2.1"
|
|
34
|
-
p0 = given.index(e); next if p0.nil?
|
|
35
|
-
given[p0, 1] = ' '
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
given.split(' ').each do |e|
|
|
39
|
-
# Find string including an IPv4 address
|
|
40
|
-
next if e.index('.').nil? # IPv4 address must include "." character
|
|
41
|
-
|
|
42
|
-
lx = e.size; next if lx < 7 || lx > 17 # 0.0.0.0 = 7, [255.255.255.255] = 17
|
|
43
|
-
cu = 0 # Cursor for seeking each octet of an IPv4 address
|
|
44
|
-
as = '' # ASCII Code of each character
|
|
45
|
-
eo = '' # Buffer of each octet of IPv4 Address
|
|
46
|
-
|
|
47
|
-
while cu < lx
|
|
48
|
-
# Check whether each character is a number or "." or not
|
|
49
|
-
as = e[cu, 1].ord
|
|
50
|
-
cu += 1
|
|
51
|
-
|
|
52
|
-
if as < 48 || as > 57
|
|
53
|
-
# The character is not a number(0-9)
|
|
54
|
-
break if as != 46 # The character is not "."
|
|
55
|
-
next if eo == '' # The current buffer is empty
|
|
56
|
-
break if eo.to_i > 255 # The current buffer is greater than 255
|
|
57
|
-
eo = ''
|
|
58
|
-
next
|
|
59
|
-
end
|
|
60
|
-
eo += as.chr
|
|
61
|
-
break if eo.to_i > 255
|
|
62
|
-
end
|
|
63
|
-
ipv4a << e if eo.size > 0 && eo.to_i < 256
|
|
64
|
-
end
|
|
65
|
-
return ipv4a
|
|
29
|
+
given = argv0.dup.tr('()[],', ' ').squeeze(' ')
|
|
30
|
+
return given.split(' ').select { |e| is_ipv4address(e) }
|
|
66
31
|
end
|
|
67
32
|
|
|
68
33
|
end
|
data/lib/sisimai/rhost/aol.rb
CHANGED
|
@@ -5,9 +5,10 @@ module Sisimai
|
|
|
5
5
|
# only from Sisimai::Fact class.
|
|
6
6
|
module Aol
|
|
7
7
|
class << self
|
|
8
|
+
require 'sisimai/eb'
|
|
8
9
|
MessagesOf = {
|
|
9
|
-
|
|
10
|
-
|
|
10
|
+
Sisimai::Eb::ReHOST => ["Host or domain name not found"],
|
|
11
|
+
Sisimai::Eb::Re00MX => ["type=MX: Malformed or unexpected name server reply"],
|
|
11
12
|
}.freeze
|
|
12
13
|
|
|
13
14
|
# Detect bounce reason from Aol Mail: https://www.aol.com
|
data/lib/sisimai/rhost/apple.rb
CHANGED
|
@@ -5,8 +5,9 @@ module Sisimai
|
|
|
5
5
|
# This class is called only Sisimai::Fact class.
|
|
6
6
|
module Apple
|
|
7
7
|
class << self
|
|
8
|
+
require 'sisimai/eb'
|
|
8
9
|
MessagesOf = {
|
|
9
|
-
|
|
10
|
+
Sisimai::Eb::ReAUTH => [
|
|
10
11
|
# - 554 5.7.1 Your message was rejected due to example.jp's DMARC policy.
|
|
11
12
|
# See https://support.apple.com/en-us/HT204137 for
|
|
12
13
|
# - 554 5.7.1 [HME1] This message was blocked for failing both SPF and DKIM authentication
|
|
@@ -14,7 +15,7 @@ module Sisimai
|
|
|
14
15
|
's dmarc policy',
|
|
15
16
|
'blocked for failing both spf and dkim autentication checks',
|
|
16
17
|
],
|
|
17
|
-
|
|
18
|
+
Sisimai::Eb::ReBLOC => [
|
|
18
19
|
# - 550 5.7.0 Blocked - see https://support.proofpoint.com/dnsbl-lookup.cgi?ip=192.0.1.2
|
|
19
20
|
# - 550 5.7.1 Your email was rejected due to having a domain present in the Spamhaus
|
|
20
21
|
# DBL -- see https://www.spamhaus.org/dbl/
|
|
@@ -26,39 +27,39 @@ module Sisimai
|
|
|
26
27
|
'blocked - see https://support.proofpoint.com/dnsbl-lookup',
|
|
27
28
|
'not accepting connections',
|
|
28
29
|
],
|
|
29
|
-
|
|
30
|
+
Sisimai::Eb::ReMOVE => [
|
|
30
31
|
# - 550 5.1.6 recipient no longer on server: *****@icloud.com
|
|
31
32
|
'recipient no longer on server',
|
|
32
33
|
],
|
|
33
|
-
|
|
34
|
+
Sisimai::Eb::ReFULL => [
|
|
34
35
|
# - 552 5.2.2 <****@icloud.com>: user is over quota (in reply to RCPT TO command)
|
|
35
36
|
'user is over quota',
|
|
36
37
|
],
|
|
37
|
-
|
|
38
|
+
Sisimai::Eb::RePASS => [
|
|
38
39
|
# - 554 5.7.1 <*****@icloud.com>: Relay access denied
|
|
39
40
|
'relay access denied',
|
|
40
41
|
],
|
|
41
|
-
|
|
42
|
-
|
|
42
|
+
Sisimai::Eb::Re00MX => ['host/domain does not accept mail'],
|
|
43
|
+
Sisimai::Eb::ReWONT => [
|
|
43
44
|
# - 550 5.7.1 [CS01] Message rejected due to local policy.
|
|
44
45
|
# Please visit https://support.apple.com/en-us/HT204137
|
|
45
46
|
'due to local policy',
|
|
46
47
|
],
|
|
47
|
-
|
|
48
|
+
Sisimai::Eb::ReRATE => [
|
|
48
49
|
# - 421 4.7.1 Messages to ****@icloud.com deferred due to excessive volume.
|
|
49
50
|
# Try again later - https://support.apple.com/en-us/HT204137
|
|
50
51
|
'due to excessive volume',
|
|
51
52
|
],
|
|
52
|
-
|
|
53
|
+
Sisimai::Eb::ReFROM => [
|
|
53
54
|
# - 450 4.1.8 <kijitora@example.jp>: Sender address rejected: Domain not found
|
|
54
55
|
'sender address rejected',
|
|
55
56
|
],
|
|
56
|
-
|
|
57
|
+
Sisimai::Eb::ReQUIT => [
|
|
57
58
|
# - https://support.apple.com/guide/icloud/stop-using-or-reactivate-addresses-mm3adb030cbf/icloud
|
|
58
59
|
# - 550 5.1.1 <****@icloud.com>: inactive email address (in reply to RCPT TO command)
|
|
59
60
|
"inactive email address",
|
|
60
61
|
],
|
|
61
|
-
|
|
62
|
+
Sisimai::Eb::ReUSER => [
|
|
62
63
|
# - 550 5.1.1 <****@icloud.com>: inactive email address (in reply to RCPT TO command)
|
|
63
64
|
# - 550 5.1.1 unknown or illegal alias: ****@icloud.com
|
|
64
65
|
'user does not exist',
|