sisimai 5.0.0 → 5.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/rake-test.yml +55 -0
- data/ChangeLog.md +40 -1
- data/README-JA.md +223 -111
- data/README.md +54 -31
- data/lib/sisimai/fact.rb +46 -8
- data/lib/sisimai/lhost/amazonses.rb +0 -1
- data/lib/sisimai/lhost/amazonworkmail.rb +0 -1
- data/lib/sisimai/lhost/aol.rb +0 -1
- data/lib/sisimai/lhost/bigfoot.rb +0 -1
- data/lib/sisimai/lhost/domino.rb +0 -1
- data/lib/sisimai/lhost/exchange2007.rb +1 -1
- data/lib/sisimai/lhost/exim.rb +7 -16
- data/lib/sisimai/lhost/facebook.rb +0 -1
- data/lib/sisimai/lhost/googlegroups.rb +2 -1
- data/lib/sisimai/lhost/gsuite.rb +0 -1
- data/lib/sisimai/lhost/mailru.rb +8 -17
- data/lib/sisimai/lhost/messagelabs.rb +0 -1
- data/lib/sisimai/lhost/mfilter.rb +1 -1
- data/lib/sisimai/lhost/mxlogic.rb +8 -18
- data/lib/sisimai/lhost/office365.rb +1 -1
- data/lib/sisimai/lhost/outlook.rb +0 -1
- data/lib/sisimai/lhost/postfix.rb +0 -1
- data/lib/sisimai/lhost/receivingses.rb +0 -1
- data/lib/sisimai/lhost/sendgrid.rb +1 -3
- data/lib/sisimai/lhost/sendmail.rb +0 -1
- data/lib/sisimai/lhost/yandex.rb +0 -1
- data/lib/sisimai/message.rb +13 -4
- data/lib/sisimai/reason/authfailure.rb +1 -0
- data/lib/sisimai/reason/blocked.rb +2 -0
- data/lib/sisimai/reason/expired.rb +1 -0
- data/lib/sisimai/reason/mailboxfull.rb +1 -0
- data/lib/sisimai/reason/securityerror.rb +1 -0
- data/lib/sisimai/reason/spamdetected.rb +1 -0
- data/lib/sisimai/reason/suspend.rb +1 -0
- data/lib/sisimai/rfc5322.rb +120 -64
- data/lib/sisimai/rhost/google.rb +320 -59
- data/lib/sisimai/rhost/mimecast.rb +9 -2
- data/lib/sisimai/smtp/status.rb +3 -0
- data/lib/sisimai/version.rb +1 -1
- data/lib/sisimai.rb +12 -11
- data/set-of-emails/maildir/bsd/lhost-sendmail-60.eml +85 -0
- metadata +4 -2
@@ -46,6 +46,7 @@ module Sisimai
|
|
46
46
|
'part of their network is on our block list',
|
47
47
|
'please use the smtp server of your isp',
|
48
48
|
'refused - see http',
|
49
|
+
'rejected - multi-blacklist', # junkemailfilter.com
|
49
50
|
'rejected because the sending mta or the sender has not passed validation',
|
50
51
|
'rejecting open proxy', # Sendmail(srvrsmtp.c)
|
51
52
|
'sender ip address rejected',
|
@@ -78,6 +79,7 @@ module Sisimai
|
|
78
79
|
['message from ', ' rejected based on blacklist'],
|
79
80
|
['messages from ', ' temporarily deferred due to user complaints'], # Yahoo!
|
80
81
|
['server ip ', ' listed as abusive'],
|
82
|
+
['sorry! your ip address', ' is blocked by rbl'], # junkemailfilter.com
|
81
83
|
['the domain ', ' is blacklisted'],
|
82
84
|
['the email ', ' is blacklisted'],
|
83
85
|
['the ip', ' is blacklisted'],
|
@@ -18,6 +18,7 @@ module Sisimai
|
|
18
18
|
'has been delayed',
|
19
19
|
'it has not been collected after',
|
20
20
|
'message expired after sitting in queue for',
|
21
|
+
'message expired, cannot connect to remote server',
|
21
22
|
'message expired, connection refulsed',
|
22
23
|
'message timed out',
|
23
24
|
'retry time not reached for any host after a long failure period',
|
@@ -29,6 +29,7 @@ module Sisimai
|
|
29
29
|
'insecure mail relay',
|
30
30
|
'recipient address rejected: access denied',
|
31
31
|
"sorry, you don't authenticate or the domain isn't in my list of allowed rcpthosts",
|
32
|
+
'starttls is required to send mail',
|
32
33
|
'tls required but not supported', # SendGrid:the recipient mailserver does not support TLS or have a valid certificate
|
33
34
|
'unauthenticated senders not allowed',
|
34
35
|
'verification failure',
|
@@ -76,6 +76,7 @@ module Sisimai
|
|
76
76
|
'spam score ',
|
77
77
|
'spambouncer identified spam', # SpamBouncer identified SPAM
|
78
78
|
'spamming not allowed',
|
79
|
+
'too many spam complaints',
|
79
80
|
'too much spam.', # Earthlink
|
80
81
|
'the email message was detected as spam',
|
81
82
|
'the message has been rejected by spam filtering engine',
|
@@ -21,6 +21,7 @@ module Sisimai
|
|
21
21
|
'recipient rejected: temporarily inactive',
|
22
22
|
'recipient suspend the service',
|
23
23
|
'this account has been disabled or discontinued',
|
24
|
+
'this address no longer accepts mail',
|
24
25
|
'this mailbox is disabled',
|
25
26
|
'user suspended', # http://mail.163.com/help/help_spam_16.htm
|
26
27
|
'vdelivermail: account is locked email bounced',
|
data/lib/sisimai/rfc5322.rb
CHANGED
@@ -3,6 +3,7 @@ module Sisimai
|
|
3
3
|
module RFC5322
|
4
4
|
class << self
|
5
5
|
require 'sisimai/string'
|
6
|
+
require 'sisimai/address'
|
6
7
|
HeaderTable = {
|
7
8
|
:messageid => %w[message-id],
|
8
9
|
:subject => %w[subject],
|
@@ -52,79 +53,134 @@ module Sisimai
|
|
52
53
|
# @return [Array] Received header as a structured data
|
53
54
|
def received(argv1)
|
54
55
|
return [] unless argv1.is_a?(::String)
|
56
|
+
return [] if argv1.include?(' invoked by uid')
|
57
|
+
return [] if argv1.include?(' invoked from network')
|
58
|
+
|
59
|
+
# - https://datatracker.ietf.org/doc/html/rfc5322
|
60
|
+
# received = "Received:" *received-token ";" date-time CRLF
|
61
|
+
# received-token = word / angle-addr / addr-spec / domain
|
62
|
+
#
|
63
|
+
# - Appendix A.4. Message with Trace Fields
|
64
|
+
# Received:
|
65
|
+
# from x.y.test
|
66
|
+
# by example.net
|
67
|
+
# via TCP
|
68
|
+
# with ESMTP
|
69
|
+
# id ABC12345
|
70
|
+
# for <mary@example.net>; 21 Nov 1997 10:05:43 -0600
|
71
|
+
recvd = argv1.split(' ')
|
72
|
+
label = %w[from by via with id for]
|
73
|
+
token = {}
|
74
|
+
other = []
|
75
|
+
alter = []
|
76
|
+
right = false
|
77
|
+
range = recvd.size
|
78
|
+
index = -1
|
79
|
+
|
80
|
+
recvd.each do |e|
|
81
|
+
# Look up each label defined in "label" from Received header
|
82
|
+
index += 1
|
83
|
+
break unless index < range; f = e.downcase
|
84
|
+
next unless label.any? { |a| f == a }
|
85
|
+
token[f] = recvd[index + 1] || next
|
86
|
+
token[f] = token[f].downcase.delete('();')
|
87
|
+
|
88
|
+
next unless f == 'from'
|
89
|
+
break unless index + 2 < range
|
90
|
+
next unless recvd[index + 2].start_with?('(')
|
91
|
+
|
92
|
+
# Get and keep a hostname in the comment as follows:
|
93
|
+
# from mx1.example.com (c213502.kyoto.example.ne.jp [192.0.2.135]) by mx.example.jp (V8/cf)
|
94
|
+
# [
|
95
|
+
# "from", # index + 0
|
96
|
+
# "mx1.example.com", # index + 1
|
97
|
+
# "(c213502.kyoto.example.ne.jp", # index + 2
|
98
|
+
# "[192.0.2.135])", # index + 3
|
99
|
+
# "by",
|
100
|
+
# "mx.example.jp",
|
101
|
+
# "(V8/cf)",
|
102
|
+
# ...
|
103
|
+
# ]
|
104
|
+
# The 2nd element after the current element is NOT a continuation of the current element
|
105
|
+
# such as "(c213502.kyoto.example.ne.jp)"
|
106
|
+
other << recvd[index + 2].delete('();')
|
107
|
+
|
108
|
+
# The 2nd element after the current element is a continuation of the current element.
|
109
|
+
# such as "(c213502.kyoto.example.ne.jp", "[192.0.2.135])"
|
110
|
+
break unless index + 3 < range
|
111
|
+
other << recvd[index + 3].delete('();')
|
112
|
+
end
|
55
113
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
# Wed, 26 Feb 2014 06:05:48 -0500
|
69
|
-
value['from'] = Sisimai::String.sweep(argv1[p1 + 5, p2 - p1 - 5])
|
70
|
-
value['by'] = Sisimai::String.sweep(argv1[p2 + 3, p3 - p2 - 3])
|
114
|
+
other.each do |e|
|
115
|
+
# Check alternatives in "other", and then delete uninformative values.
|
116
|
+
next if e.nil?
|
117
|
+
next if e.size < 4
|
118
|
+
next if e == 'unknown'
|
119
|
+
next if e == 'localhost'
|
120
|
+
next if e == '[127.0.0.1]'
|
121
|
+
next if e == '[IPv6:::1]'
|
122
|
+
next unless e.include?('.')
|
123
|
+
next if e.include?('=')
|
124
|
+
alter << e
|
125
|
+
end
|
71
126
|
|
72
|
-
|
73
|
-
#
|
74
|
-
|
75
|
-
|
127
|
+
%w[from by].each do |e|
|
128
|
+
# Remove square brackets from the IP address such as "[192.0.2.25]"
|
129
|
+
next if token[e].nil?
|
130
|
+
next if token[e].empty?
|
131
|
+
next unless token[e].start_with?('[')
|
132
|
+
token[e] = Sisimai::String.ipv4(token[e]).shift || ''
|
76
133
|
end
|
134
|
+
token['from'] ||= ''
|
77
135
|
|
78
|
-
|
79
|
-
#
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
hostname = ''
|
85
|
-
hostaddr = ''
|
86
|
-
|
87
|
-
while e = received.shift do
|
88
|
-
# Received: from [10.22.22.222] (smtp-gateway.kyoto.ocn.ne.jp [192.0.2.222])
|
89
|
-
cv = Sisimai::String.ipv4(e) || []
|
90
|
-
if cv.size > 0
|
91
|
-
# [192.0.2.1] or (192.0.2.1)
|
92
|
-
addrlist.append(*cv)
|
93
|
-
else
|
94
|
-
# hostname
|
95
|
-
e = e.delete('()').strip
|
96
|
-
namelist << e
|
97
|
-
end
|
98
|
-
end
|
136
|
+
while true do
|
137
|
+
# Prefer hostnames over IP addresses, except for localhost.localdomain and similar.
|
138
|
+
break if token['from'] == 'localhost'
|
139
|
+
break if token['from'] == 'localhost.localdomain'
|
140
|
+
break unless token['from'].include?('.') # A hostname without a domain name
|
141
|
+
break unless Sisimai::String.ipv4(token['from']).empty?
|
99
142
|
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
break
|
105
|
-
end
|
143
|
+
# No need to rewrite token['from']
|
144
|
+
right = true
|
145
|
+
break
|
146
|
+
end
|
106
147
|
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
148
|
+
while true do
|
149
|
+
# Try to rewrite uninformative hostnames and IP addresses in token['from']
|
150
|
+
break if right # There is no need to rewrite
|
151
|
+
break if alter.empty? # There is no alternative to rewriting
|
152
|
+
break if alter[0].include?(token['from'])
|
153
|
+
|
154
|
+
if token['from'].start_with?('localhost')
|
155
|
+
# localhost or localhost.localdomain
|
156
|
+
token['from'] = alter[0]
|
157
|
+
elsif token['from'].index('.')
|
158
|
+
# A hostname without a domain name such as "mail", "mx", or "mbox"
|
159
|
+
token['from'] = alter[0] if alter[0].include?('.')
|
160
|
+
else
|
161
|
+
# An IPv4 address
|
162
|
+
token['from'] = alter[0]
|
116
163
|
end
|
117
|
-
|
118
|
-
value['from'] = hostname || hostaddr || addrlist[-1]
|
164
|
+
break
|
119
165
|
end
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
166
|
+
token.delete('from') if token['from'].nil?
|
167
|
+
token.delete('by') if token['by'].nil?
|
168
|
+
token['for'] = Sisimai::Address.s3s4(token['for']) if token.has_key?('for')
|
169
|
+
|
170
|
+
token.keys.each do |e|
|
171
|
+
# Delete an invalid value
|
172
|
+
token[e] = '' if token[e].include?(' ')
|
173
|
+
token[e].delete!('[]') # Remove "[]" from the IP address
|
126
174
|
end
|
127
|
-
|
175
|
+
|
176
|
+
return [
|
177
|
+
token['from'] || '',
|
178
|
+
token['by'] || '',
|
179
|
+
token['via'] || '',
|
180
|
+
token['with'] || '',
|
181
|
+
token['id'] || '',
|
182
|
+
token['for'] || '',
|
183
|
+
]
|
128
184
|
end
|
129
185
|
|
130
186
|
# Split given entire message body into error message lines and the original message part only
|