sisimai 5.4.0-java → 5.5.0-java
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/codecovio.yml +1 -1
- data/.github/workflows/rake-test.yml +1 -1
- data/ChangeLog.md +45 -0
- data/Makefile +2 -4
- data/README-JA.md +23 -20
- data/README.md +23 -20
- data/lib/sisimai/address.rb +92 -44
- data/lib/sisimai/arf.rb +7 -8
- data/lib/sisimai/datetime.rb +2 -2
- data/lib/sisimai/fact/json.rb +1 -2
- data/lib/sisimai/fact/yaml.rb +1 -2
- data/lib/sisimai/fact.rb +60 -35
- data/lib/sisimai/lda.rb +2 -2
- data/lib/sisimai/lhost/activehunter.rb +4 -5
- data/lib/sisimai/lhost/amazonses.rb +3 -4
- data/lib/sisimai/lhost/apachejames.rb +2 -2
- data/lib/sisimai/lhost/biglobe.rb +6 -6
- data/lib/sisimai/lhost/courier.rb +7 -7
- data/lib/sisimai/lhost/domino.rb +6 -6
- data/lib/sisimai/lhost/dragonfly.rb +5 -5
- data/lib/sisimai/lhost/einsundeins.rb +4 -4
- data/lib/sisimai/lhost/exchange2003.rb +7 -7
- data/lib/sisimai/lhost/exchange2007.rb +3 -3
- data/lib/sisimai/lhost/exim.rb +7 -7
- data/lib/sisimai/lhost/ezweb.rb +3 -2
- data/lib/sisimai/lhost/fml.rb +9 -9
- data/lib/sisimai/lhost/gmail.rb +9 -9
- data/lib/sisimai/lhost/gmx.rb +3 -3
- data/lib/sisimai/lhost/googlegroups.rb +6 -7
- data/lib/sisimai/lhost/googleworkspace.rb +5 -6
- data/lib/sisimai/lhost/imailserver.rb +4 -4
- data/lib/sisimai/lhost/kddi.rb +4 -4
- data/lib/sisimai/lhost/mailfoundry.rb +3 -3
- data/lib/sisimai/lhost/{mailmarshalsmtp.rb → mailmarshal.rb} +5 -5
- data/lib/sisimai/lhost/messagingserver.rb +8 -8
- data/lib/sisimai/lhost/mfilter.rb +8 -4
- data/lib/sisimai/lhost/mimecast.rb +105 -0
- data/lib/sisimai/lhost/notes.rb +5 -5
- data/lib/sisimai/lhost/opensmtpd.rb +5 -5
- data/lib/sisimai/lhost/postfix.rb +38 -32
- data/lib/sisimai/lhost/qmail.rb +6 -6
- data/lib/sisimai/lhost/sendmail.rb +13 -13
- data/lib/sisimai/lhost/{interscanmss.rb → trendmicro.rb} +8 -9
- data/lib/sisimai/lhost/v5sendmail.rb +7 -7
- data/lib/sisimai/lhost/verizon.rb +3 -3
- data/lib/sisimai/lhost/x1.rb +7 -4
- data/lib/sisimai/lhost/x2.rb +40 -12
- data/lib/sisimai/lhost/x3.rb +3 -3
- data/lib/sisimai/lhost/x6.rb +2 -2
- data/lib/sisimai/lhost/zoho.rb +5 -5
- data/lib/sisimai/lhost.rb +18 -17
- data/lib/sisimai/mail/maildir.rb +4 -4
- data/lib/sisimai/mail/mbox.rb +4 -4
- data/lib/sisimai/mail/memory.rb +1 -1
- data/lib/sisimai/mail/stdin.rb +2 -2
- data/lib/sisimai/message.rb +34 -34
- data/lib/sisimai/order.rb +5 -4
- data/lib/sisimai/reason/authfailure.rb +1 -1
- data/lib/sisimai/reason/badreputation.rb +1 -1
- data/lib/sisimai/reason/blocked.rb +2 -1
- data/lib/sisimai/reason/contenterror.rb +1 -2
- data/lib/sisimai/reason/exceedlimit.rb +1 -1
- data/lib/sisimai/reason/expired.rb +1 -1
- data/lib/sisimai/reason/failedstarttls.rb +1 -1
- data/lib/sisimai/reason/filtered.rb +1 -1
- data/lib/sisimai/reason/hasmoved.rb +1 -1
- data/lib/sisimai/reason/hostunknown.rb +2 -2
- data/lib/sisimai/reason/mailboxfull.rb +1 -1
- data/lib/sisimai/reason/mailererror.rb +1 -1
- data/lib/sisimai/reason/mesgtoobig.rb +1 -1
- data/lib/sisimai/reason/networkerror.rb +1 -1
- data/lib/sisimai/reason/norelaying.rb +2 -2
- data/lib/sisimai/reason/notaccept.rb +2 -3
- data/lib/sisimai/reason/notcompliantrfc.rb +1 -1
- data/lib/sisimai/reason/policyviolation.rb +2 -4
- data/lib/sisimai/reason/rejected.rb +5 -3
- data/lib/sisimai/reason/requireptr.rb +1 -1
- data/lib/sisimai/reason/securityerror.rb +1 -1
- data/lib/sisimai/reason/spamdetected.rb +1 -1
- data/lib/sisimai/reason/speeding.rb +1 -1
- data/lib/sisimai/reason/suspend.rb +2 -1
- data/lib/sisimai/reason/systemerror.rb +1 -1
- data/lib/sisimai/reason/systemfull.rb +1 -1
- data/lib/sisimai/reason/toomanyconn.rb +1 -1
- data/lib/sisimai/reason/userunknown.rb +4 -3
- data/lib/sisimai/reason/vacation.rb +1 -1
- data/lib/sisimai/reason/virusdetected.rb +1 -1
- data/lib/sisimai/reason.rb +12 -12
- data/lib/sisimai/rfc1123.rb +58 -18
- data/lib/sisimai/rfc1894.rb +6 -8
- data/lib/sisimai/rfc2045.rb +25 -13
- data/lib/sisimai/rfc3464/thirdparty.rb +2 -3
- data/lib/sisimai/rfc3464.rb +6 -6
- data/lib/sisimai/rfc3834.rb +18 -8
- data/lib/sisimai/rfc5322.rb +9 -9
- data/lib/sisimai/rfc791.rb +2 -2
- data/lib/sisimai/rhost/aol.rb +4 -1
- data/lib/sisimai/rhost/apple.rb +11 -7
- data/lib/sisimai/rhost/cox.rb +9 -5
- data/lib/sisimai/rhost/facebook.rb +9 -3
- data/lib/sisimai/rhost/franceptt.rb +86 -37
- data/lib/sisimai/rhost/godaddy.rb +10 -1
- data/lib/sisimai/rhost/google.rb +26 -22
- data/lib/sisimai/rhost/gsuite.rb +1 -1
- data/lib/sisimai/rhost/kddi.rb +1 -1
- data/lib/sisimai/rhost/messagelabs.rb +160 -2
- data/lib/sisimai/rhost/microsoft.rb +80 -29
- data/lib/sisimai/rhost/mimecast.rb +30 -21
- data/lib/sisimai/rhost/nttdocomo.rb +69 -89
- data/lib/sisimai/rhost/outlook.rb +1 -1
- data/lib/sisimai/rhost/spectrum.rb +1 -1
- data/lib/sisimai/rhost/tencent.rb +5 -4
- data/lib/sisimai/rhost/yahooinc.rb +2 -2
- data/lib/sisimai/rhost/zoho.rb +72 -0
- data/lib/sisimai/rhost.rb +5 -4
- data/lib/sisimai/smtp/command.rb +2 -2
- data/lib/sisimai/smtp/reply.rb +11 -4
- data/lib/sisimai/smtp/status.rb +17 -8
- data/lib/sisimai/smtp/transcript.rb +3 -3
- data/lib/sisimai/string.rb +6 -10
- data/lib/sisimai/version.rb +1 -1
- data/lib/sisimai.rb +1 -1
- data/set-of-emails/maildir/bsd/lhost-exim-56.eml +40 -40
- data/set-of-emails/maildir/bsd/lhost-mfilter-05.eml +41 -0
- data/set-of-emails/maildir/bsd/lhost-mimecast-01.eml +46 -0
- data/set-of-emails/maildir/bsd/lhost-mimecast-02.eml +59 -0
- data/set-of-emails/maildir/bsd/lhost-postfix-79.eml +81 -0
- data/set-of-emails/maildir/bsd/lhost-postfix-80.eml +84 -0
- data/set-of-emails/maildir/bsd/lhost-x1-03.eml +26 -0
- data/set-of-emails/maildir/bsd/lhost-x1-04.eml +45 -0
- data/set-of-emails/maildir/bsd/lhost-x2-07.eml +30 -0
- data/set-of-emails/maildir/bsd/rfc3464-66.eml +170 -0
- data/set-of-emails/maildir/bsd/rfc3834-06.eml +59 -0
- data/set-of-emails/maildir/bsd/rhost-apple-05.eml +96 -0
- data/set-of-emails/maildir/bsd/rhost-zoho-01.eml +88 -0
- data/set-of-emails/maildir/bsd/rhost-zoho-02.eml +86 -0
- data/set-of-emails/maildir/bsd/rhost-zoho-03.eml +87 -0
- data/set-of-emails/maildir/bsd/rhost-zoho-04.eml +86 -0
- data/set-of-emails/maildir/not/rb-issue-368-bug.eml +39 -0
- data/sisimai-java.gemspec +1 -1
- data/sisimai.gemspec +1 -1
- metadata +27 -9
- /data/set-of-emails/maildir/bsd/{lhost-mailmarshalsmtp-02.eml → lhost-mailmarshal-02.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{lhost-interscanmss-01.eml → lhost-trendmicro-01.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{lhost-interscanmss-02.eml → lhost-trendmicro-02.eml} +0 -0
- /data/set-of-emails/maildir/bsd/{lhost-interscanmss-03.eml → lhost-trendmicro-03.eml} +0 -0
data/lib/sisimai/datetime.rb
CHANGED
|
@@ -203,7 +203,7 @@ module Sisimai
|
|
|
203
203
|
# The piece is the value of a day
|
|
204
204
|
if v[:d]
|
|
205
205
|
# 2-digit year?
|
|
206
|
-
altervalue[:Y] = p
|
|
206
|
+
altervalue[:Y] = p if v[:Y].nil?
|
|
207
207
|
else
|
|
208
208
|
# The value is "day"
|
|
209
209
|
v[:d] = p
|
|
@@ -361,7 +361,7 @@ module Sisimai
|
|
|
361
361
|
# @example Get timezone offset string of specified seconds
|
|
362
362
|
# second2tz(12345) #=> '+0325'
|
|
363
363
|
def second2tz(argv1)
|
|
364
|
-
return '+0000'
|
|
364
|
+
return '+0000' if argv1.is_a?(::Integer) == false
|
|
365
365
|
return "" if argv1.abs > TZ_OFFSET # UTC+14 + 1(DST?)
|
|
366
366
|
|
|
367
367
|
digit = {:operator => '+'}
|
data/lib/sisimai/fact/json.rb
CHANGED
|
@@ -8,8 +8,7 @@ module Sisimai
|
|
|
8
8
|
# @param [Sisimai::Fact] argvs Object
|
|
9
9
|
# @return [String] Dumped data or an empty string if the argument is missing
|
|
10
10
|
def dump(argvs)
|
|
11
|
-
return ""
|
|
12
|
-
return "" unless argvs.is_a? Sisimai::Fact
|
|
11
|
+
return "" if argvs.nil? || argvs.is_a?(Sisimai::Fact) == false
|
|
13
12
|
|
|
14
13
|
if RUBY_PLATFORM.start_with?('java')
|
|
15
14
|
# java-based ruby environment like JRuby.
|
data/lib/sisimai/fact/yaml.rb
CHANGED
|
@@ -10,8 +10,7 @@ module Sisimai
|
|
|
10
10
|
# @param [Sisimai::Fact] argvs Object
|
|
11
11
|
# @return [String, nil] Dumped data or nil if the argument is missing
|
|
12
12
|
def dump(argvs)
|
|
13
|
-
return ""
|
|
14
|
-
return "" unless argvs.is_a? Sisimai::Fact
|
|
13
|
+
return "" if argvs.nil? || argvs.is_a?(Sisimai::Fact) == false
|
|
15
14
|
|
|
16
15
|
damneddata = argvs.damn
|
|
17
16
|
yamlstring = nil
|
data/lib/sisimai/fact.rb
CHANGED
|
@@ -43,6 +43,7 @@ module Sisimai
|
|
|
43
43
|
:timestamp, # [Sisimai::Time] Date: header in the original message
|
|
44
44
|
:timezoneoffset, # [Integer] Time zone offset(seconds)
|
|
45
45
|
:token, # [String] Message token/MD5 Hex digest value
|
|
46
|
+
:toxic, # [Boolean] EXPERIMENTAL
|
|
46
47
|
]
|
|
47
48
|
attr_accessor(*@@rwaccessors)
|
|
48
49
|
|
|
@@ -93,6 +94,7 @@ module Sisimai
|
|
|
93
94
|
@token = argvs['token']
|
|
94
95
|
@timestamp = argvs['timestamp']
|
|
95
96
|
@timezoneoffset = argvs['timezoneoffset']
|
|
97
|
+
@toxic = argvs['toxic']
|
|
96
98
|
end
|
|
97
99
|
|
|
98
100
|
# Constructor of Sisimai::Fact
|
|
@@ -104,15 +106,12 @@ module Sisimai
|
|
|
104
106
|
# @options argvs [String] origin Path to the original email file
|
|
105
107
|
# @return [Array] Array of Sisimai::Fact objects
|
|
106
108
|
def self.rise(**argvs)
|
|
107
|
-
return nil
|
|
108
|
-
return nil unless argvs.is_a? Hash
|
|
109
|
+
return nil if argvs.is_a?(Hash) == false
|
|
109
110
|
|
|
110
|
-
email = argvs[:data]; return nil
|
|
111
|
+
email = argvs[:data]; return nil if email.nil?
|
|
111
112
|
args1 = {data: email, hook: argvs[:hook]}
|
|
112
113
|
mesg1 = Sisimai::Message.rise(**args1)
|
|
113
|
-
return nil
|
|
114
|
-
return nil unless mesg1['ds']
|
|
115
|
-
return nil unless mesg1['rfc822']
|
|
114
|
+
return nil if mesg1.nil? || mesg1['ds'].nil? || mesg1['rfc822'].nil?
|
|
116
115
|
|
|
117
116
|
deliveries = mesg1['ds'].dup
|
|
118
117
|
rfc822data = mesg1['rfc822']
|
|
@@ -142,36 +141,36 @@ module Sisimai
|
|
|
142
141
|
"replycode" => e["replycode"],
|
|
143
142
|
"rhost" => e["rhost"],
|
|
144
143
|
"decodedby" => e["agent"],
|
|
144
|
+
"toxic" => e["toxic"],
|
|
145
145
|
}
|
|
146
146
|
|
|
147
147
|
# EMAILADDRESS: Detect an email address from message/rfc822 part
|
|
148
148
|
RFC822Head[:addresser].each do |f|
|
|
149
149
|
# Check each header in message/rfc822 part
|
|
150
|
-
next
|
|
151
|
-
next if rfc822data[f].empty?
|
|
150
|
+
next if rfc822data[f].nil? || rfc822data[f].empty?
|
|
152
151
|
|
|
153
152
|
j = Sisimai::Address.find(rfc822data[f]) || next
|
|
154
153
|
piece['addresser'] = j.shift
|
|
155
154
|
break
|
|
156
155
|
end
|
|
157
156
|
|
|
158
|
-
|
|
157
|
+
if piece['addresser'].nil?
|
|
159
158
|
# Fallback: Get the sender address from the header of the bounced email if the address is
|
|
160
159
|
# not set at loop above.
|
|
161
160
|
j = Sisimai::Address.find(mesg1['header']['to']) || []
|
|
162
161
|
piece['addresser'] = j.shift
|
|
163
162
|
end
|
|
164
|
-
next
|
|
163
|
+
next if piece['addresser'].nil?
|
|
165
164
|
|
|
166
165
|
# TIMESTAMP: Convert from a time stamp or a date string to a machine time.
|
|
167
166
|
datestring = nil
|
|
168
167
|
zoneoffset = 0
|
|
169
|
-
datevalues = []; datevalues << e['date']
|
|
168
|
+
datevalues = []; datevalues << e['date'] if e['date'].to_s.empty? == false
|
|
170
169
|
|
|
171
170
|
# Date information did not exist in message/delivery-status part,...
|
|
172
171
|
RFC822Head[:date].each do |f|
|
|
173
172
|
# Get the value of Date header or other date related header.
|
|
174
|
-
next
|
|
173
|
+
next if rfc822data[f].nil?
|
|
175
174
|
datevalues << rfc822data[f]
|
|
176
175
|
end
|
|
177
176
|
|
|
@@ -197,7 +196,7 @@ module Sisimai
|
|
|
197
196
|
rescue
|
|
198
197
|
warn " ***warning: Failed to strptime #{datestring.to_s}"
|
|
199
198
|
end
|
|
200
|
-
next
|
|
199
|
+
next if piece['timestamp'].nil?
|
|
201
200
|
|
|
202
201
|
# OTHER_TEXT_HEADERS:
|
|
203
202
|
recv = mesg1["header"]["received"] || []
|
|
@@ -213,7 +212,7 @@ module Sisimai
|
|
|
213
212
|
# Check the Received: headers backwards and get a remote hostname
|
|
214
213
|
break if piece["rhost"].size > 0
|
|
215
214
|
cv = Sisimai::RFC5322.received(re)[0]
|
|
216
|
-
next
|
|
215
|
+
next if Sisimai::RFC1123.is_internethost(cv) == false
|
|
217
216
|
piece['rhost'] = cv
|
|
218
217
|
end
|
|
219
218
|
end
|
|
@@ -225,7 +224,7 @@ module Sisimai
|
|
|
225
224
|
recv.each do |le|
|
|
226
225
|
# Check the Received: headers backwards and get a local hostname
|
|
227
226
|
cv = Sisimai::RFC5322.received(le)[0]
|
|
228
|
-
next
|
|
227
|
+
next if Sisimai::RFC1123.is_internethost(cv) == false
|
|
229
228
|
piece['lhost'] = cv
|
|
230
229
|
break
|
|
231
230
|
end
|
|
@@ -241,7 +240,7 @@ module Sisimai
|
|
|
241
240
|
end
|
|
242
241
|
piece[v].delete!('[]()') # Remove square brackets and curly brackets from the host variable
|
|
243
242
|
piece[v].sub!(/\A.+=/, '') # Remove string before "="
|
|
244
|
-
piece[v].
|
|
243
|
+
piece[v].delete_suffix("\r")# Remove CR at the end of the value
|
|
245
244
|
|
|
246
245
|
if piece[v].include?(' ')
|
|
247
246
|
# Check space character in each value and get the first hostname
|
|
@@ -255,13 +254,13 @@ module Sisimai
|
|
|
255
254
|
end
|
|
256
255
|
end
|
|
257
256
|
piece[v] = ee[0] if piece[v].include?(' ')
|
|
258
|
-
piece[v].
|
|
257
|
+
piece[v].delete_suffix!('.') # Remove "." at the end of the value
|
|
259
258
|
end
|
|
260
259
|
|
|
261
260
|
# Subject: header of the original message
|
|
262
261
|
piece['subject'] = rfc822data['subject'] || ''
|
|
263
262
|
piece['subject'].scrub!('?')
|
|
264
|
-
piece['subject'].
|
|
263
|
+
piece['subject'].delete_suffix("\r")
|
|
265
264
|
|
|
266
265
|
# The value of "List-Id" header
|
|
267
266
|
if Sisimai::String.aligned(rfc822data['list-id'], ['<', '.', '>'])
|
|
@@ -290,7 +289,7 @@ module Sisimai
|
|
|
290
289
|
# CHECK_DELIVERY_STATUS_VALUE: Cleanup the value of "Diagnostic-Code:" header
|
|
291
290
|
if piece['diagnosticcode'].to_s.size > 0
|
|
292
291
|
# Get an SMTP Reply Code and an SMTP Enhanced Status Code
|
|
293
|
-
piece['diagnosticcode'].
|
|
292
|
+
piece['diagnosticcode'].delete_suffix("\r")
|
|
294
293
|
|
|
295
294
|
cs = Sisimai::SMTP::Status.find(piece['diagnosticcode'])
|
|
296
295
|
cr = Sisimai::SMTP::Reply.find(piece['diagnosticcode'], cs)
|
|
@@ -355,11 +354,11 @@ module Sisimai
|
|
|
355
354
|
|
|
356
355
|
piece["diagnostictype"] = "X-UNIX" if piece["reason"] == "mailererror"
|
|
357
356
|
if piece["diagnostictype"].empty?
|
|
358
|
-
piece["diagnostictype"] = "SMTP"
|
|
357
|
+
piece["diagnostictype"] = "SMTP" if %w[feedback vacation].include?(piece["reason"]) == false
|
|
359
358
|
end
|
|
360
359
|
|
|
361
360
|
# Check the value of SMTP command
|
|
362
|
-
piece['command'] = ''
|
|
361
|
+
piece['command'] = '' if Sisimai::SMTP::Command.test(piece['command']) == false
|
|
363
362
|
|
|
364
363
|
# Create parameters for the constructor
|
|
365
364
|
as = Sisimai::Address.new(piece['addresser']) || next; next if as.void
|
|
@@ -383,6 +382,7 @@ module Sisimai
|
|
|
383
382
|
thing['catch'] = piece['catch'] || nil
|
|
384
383
|
thing["feedbackid"] = ""
|
|
385
384
|
thing['hardbounce'] = piece['hardbounce']
|
|
385
|
+
thing['toxic'] = piece['toxic']
|
|
386
386
|
thing['replycode'] = Sisimai::SMTP::Reply.find(piece['diagnosticcode']) if thing['replycode'].empty?
|
|
387
387
|
thing['timestamp'] = TimeModule.parse(::Time.at(piece['timestamp']).to_s)
|
|
388
388
|
thing['timezoneoffset'] = piece['timezoneoffset'] || '+0000'
|
|
@@ -394,16 +394,15 @@ module Sisimai
|
|
|
394
394
|
# when the recipient address is same with the value of thing['alias'].
|
|
395
395
|
break if thing['alias'].empty?
|
|
396
396
|
break if thing['recipient'].address != thing['alias']
|
|
397
|
-
break
|
|
397
|
+
break if rfc822data.has_key?('received') == false
|
|
398
398
|
break if rfc822data['received'].empty?
|
|
399
399
|
|
|
400
400
|
rfc822data['received'].reverse.each do |er|
|
|
401
401
|
# Search for the string " for " from the Received: header
|
|
402
|
-
next
|
|
402
|
+
next if er.include?(' for ') == false
|
|
403
403
|
|
|
404
404
|
af = Sisimai::RFC5322.received(er)
|
|
405
|
-
next if af.empty? || af[5].empty?
|
|
406
|
-
next unless Sisimai::Address.is_emailaddress(af[5])
|
|
405
|
+
next if af.empty? || af[5].empty? || Sisimai::Address.is_emailaddress(af[5]) == false
|
|
407
406
|
next if thing['recipient'].address == af[5]
|
|
408
407
|
|
|
409
408
|
thing['alias'] = af[5]
|
|
@@ -430,7 +429,7 @@ module Sisimai
|
|
|
430
429
|
# HARDBOUNCE: Set the value of "hardbounce", default value of "bouncebounce" is false
|
|
431
430
|
if thing['reason'] == 'delivered' || thing['reason'] == 'feedback' || thing['reason'] == 'vacation'
|
|
432
431
|
# Delete the value of ReplyCode when the Reason is "feedback" or "vacation"
|
|
433
|
-
thing['replycode'] = ''
|
|
432
|
+
thing['replycode'] = '' if thing['reason'] != 'delivered'
|
|
434
433
|
else
|
|
435
434
|
# The reason is not "delivered", or "feedback", or "vacation"
|
|
436
435
|
smtperrors = "#{piece['deliverystatus']} #{piece['diagnosticcode']}"
|
|
@@ -456,7 +455,7 @@ module Sisimai
|
|
|
456
455
|
thing['replycode'] = cx[1].start_with?(cx[0]) ? cx[1] : ''
|
|
457
456
|
end
|
|
458
457
|
|
|
459
|
-
|
|
458
|
+
if ActionList.has_key?(thing['action']) == false
|
|
460
459
|
# There is an action value which is not described at RFC1894
|
|
461
460
|
if ox = Sisimai::RFC1894.field("Action: #{thing['action']}")
|
|
462
461
|
# Rewrite the value of "Action:" field to the valid value
|
|
@@ -484,12 +483,44 @@ module Sisimai
|
|
|
484
483
|
|
|
485
484
|
# Feedback-ID: 1.us-west-2.QHuyeCQrGtIIMGKQfVdUhP9hCQR2LglVOrRamBc+Prk=:AmazonSES
|
|
486
485
|
thing["feedbackid"] = rfc822data["feedback-id"] || ""
|
|
486
|
+
thing["toxic"] ||= is_toxic(thing)
|
|
487
487
|
|
|
488
488
|
listoffact << Sisimai::Fact.new(thing)
|
|
489
489
|
end
|
|
490
490
|
return listoffact
|
|
491
491
|
end
|
|
492
492
|
|
|
493
|
+
def self.is_toxic(thing = nil)
|
|
494
|
+
return false unless thing
|
|
495
|
+
cr = thing['reason'] || 'undefined'
|
|
496
|
+
cv = thing['replycode'] || ''
|
|
497
|
+
cw = thing['deliverystatus'] || ''
|
|
498
|
+
|
|
499
|
+
# 1. Hard bounces or some soft bounces with a permanent error.
|
|
500
|
+
# 1-1. Hard bounce: UserUnknown, HostUnknown, HasMoved, NotAccept
|
|
501
|
+
# 1-2. Almost hard bounce: Suspend, Suppressed
|
|
502
|
+
return false if cv.start_with?('4') || cw.start_with?('4')
|
|
503
|
+
return true if %w[userunknown hostunknown hasmoved notaccept suspend suppressed].any? { |a| cr == a }
|
|
504
|
+
|
|
505
|
+
if %w[mailboxfull filtered norelaying].any? { |a| cr == a }
|
|
506
|
+
# 2. Several softbounces: MailboxFull, Filtered, NoRelaying
|
|
507
|
+
# 2-1. The SMTP command is "RCPT" except "MailboxFull".
|
|
508
|
+
# 2-2. The SMTP reply code begins with "5" such as "550".
|
|
509
|
+
# 2-3. The SMTP status code is explicit code (not empty, not 5.0.9XX).
|
|
510
|
+
# 2-4. The SMTP status code begins with "5." such as "5.1.1".
|
|
511
|
+
return true if cr != 'mailboxfull' && thing['command'] == "RCPT"
|
|
512
|
+
return true if cv.start_with?('5')
|
|
513
|
+
return false if Sisimai::SMTP::Status.is_explicit(cw) == false
|
|
514
|
+
return true if cw.start_with?('5.')
|
|
515
|
+
|
|
516
|
+
elsif cr == 'feedback'
|
|
517
|
+
# 3. Feedback Loop
|
|
518
|
+
# 3-1. The Feedback Type is any of "abuse", "fraud", "opt-out"
|
|
519
|
+
return true if %w[abuse fraud opt-out].any? { |a| thing['feedbacktype'] == a }
|
|
520
|
+
end
|
|
521
|
+
return false
|
|
522
|
+
end
|
|
523
|
+
|
|
493
524
|
# Convert from Sisimai::Fact object to a Hash
|
|
494
525
|
# @return [Hash] Hashed data
|
|
495
526
|
def damn
|
|
@@ -504,13 +535,10 @@ module Sisimai
|
|
|
504
535
|
v = {}
|
|
505
536
|
stringdata.each { |e| v[e] = self.send(e.to_sym) || '' }
|
|
506
537
|
v['hardbounce'] = self.hardbounce
|
|
538
|
+
v['toxic'] = self.toxic
|
|
507
539
|
v['addresser'] = self.addresser.address
|
|
508
540
|
v['recipient'] = self.recipient.address
|
|
509
541
|
v['timestamp'] = self.timestamp.to_time.to_i
|
|
510
|
-
|
|
511
|
-
# Backward compatibility until v5.5.0
|
|
512
|
-
v["smtpagent"] = self.decodedby
|
|
513
|
-
v["smtpcommand"] = self.command
|
|
514
542
|
data = v
|
|
515
543
|
rescue
|
|
516
544
|
warn ' ***warning: Failed to execute Sisimai::Fact.damn'
|
|
@@ -524,7 +552,7 @@ module Sisimai
|
|
|
524
552
|
# @return [String] data
|
|
525
553
|
# [Nil] The value of the first argument is neither "json" nor "yaml"
|
|
526
554
|
def dump(type = 'json')
|
|
527
|
-
return nil
|
|
555
|
+
return nil if %w[json yaml].include?(type) == false
|
|
528
556
|
referclass = "Sisimai::Fact::#{type.upcase}"
|
|
529
557
|
|
|
530
558
|
begin
|
|
@@ -542,9 +570,6 @@ module Sisimai
|
|
|
542
570
|
def to_json(*)
|
|
543
571
|
return self.dump('json')
|
|
544
572
|
end
|
|
545
|
-
|
|
546
|
-
def smtpagent; warn " ***warning: Sisimai::Fact.smtpagent will be removed at v5.5.0"; return self.decodedby; end
|
|
547
|
-
def smtpcomand; warn " ***warning: Sisimai::Fact.smtpcommand will be removed at v5.5.0"; return self.command; end
|
|
548
573
|
end
|
|
549
574
|
end
|
|
550
575
|
|
data/lib/sisimai/lda.rb
CHANGED
|
@@ -78,14 +78,14 @@ module Sisimai
|
|
|
78
78
|
|
|
79
79
|
LocalAgent.each_key do |e|
|
|
80
80
|
# Find a lcoal delivery agent name from the entire message body
|
|
81
|
-
next
|
|
81
|
+
next if LocalAgent[e].none? { |a| issuedcode.include?(a) }
|
|
82
82
|
deliversby = e; break
|
|
83
83
|
end
|
|
84
84
|
return "" if deliversby.empty?
|
|
85
85
|
|
|
86
86
|
MessagesOf[deliversby].each_key do |e|
|
|
87
87
|
# The key is a bounce reason name
|
|
88
|
-
next
|
|
88
|
+
next if MessagesOf[deliversby][e].none? { |a| issuedcode.include?(a) }
|
|
89
89
|
reasontext = e; break
|
|
90
90
|
end
|
|
91
91
|
|
|
@@ -18,7 +18,7 @@ module Sisimai::Lhost
|
|
|
18
18
|
def inquire(mhead, mbody)
|
|
19
19
|
# :from => %r/\A"MAILER-DAEMON"/,
|
|
20
20
|
# :subject => %r/FAILURE NOTICE :/,
|
|
21
|
-
return nil
|
|
21
|
+
return nil if mhead['x-ahmailid'].nil?
|
|
22
22
|
|
|
23
23
|
dscontents = [Sisimai::Lhost.DELIVERYSTATUS]; v = nil
|
|
24
24
|
emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
|
|
@@ -57,13 +57,12 @@ module Sisimai::Lhost
|
|
|
57
57
|
else
|
|
58
58
|
# ----- Transcript of session follows -----
|
|
59
59
|
# 550 sorry, no mailbox here by that name (#5.1.1 - chkusr)
|
|
60
|
-
next if e[0, 1].ord < 48
|
|
61
|
-
next if
|
|
62
|
-
next unless v['diagnosis'].empty?
|
|
60
|
+
next if e[0, 1].ord < 48 || e[0, 1].ord > 122
|
|
61
|
+
next if v['diagnosis'].empty? == false
|
|
63
62
|
v['diagnosis'] = e
|
|
64
63
|
end
|
|
65
64
|
end
|
|
66
|
-
return nil
|
|
65
|
+
return nil if recipients == 0
|
|
67
66
|
|
|
68
67
|
dscontents.each { |e| e['diagnosis'] = Sisimai::String.sweep(e['diagnosis']) }
|
|
69
68
|
return {"ds" => dscontents, "rfc822" => emailparts[1]}
|
|
@@ -45,7 +45,7 @@ module Sisimai::Lhost
|
|
|
45
45
|
require 'sisimai/lhost'
|
|
46
46
|
|
|
47
47
|
ReasonPair = {
|
|
48
|
-
"
|
|
48
|
+
"Suppressed" => "suppressed",
|
|
49
49
|
"OnAccountSuppressionList" => "suppressed",
|
|
50
50
|
"General" => "onhold",
|
|
51
51
|
"MailboxFull" => "mailboxfull",
|
|
@@ -87,8 +87,7 @@ module Sisimai::Lhost
|
|
|
87
87
|
p3 = sespayload.index("{", p2 + 9)
|
|
88
88
|
p4 = sespayload.index("\n", p2 + 9)
|
|
89
89
|
sespayload = sespayload[p3, p4 - p3]
|
|
90
|
-
sespayload = sespayload.
|
|
91
|
-
sespayload = sespayload.chop if sespayload[-1, 1] == '"'
|
|
90
|
+
sespayload = sespayload.delete_suffix(',').delete_suffix('"')
|
|
92
91
|
end
|
|
93
92
|
|
|
94
93
|
break if sespayload.include?("notificationType") == false
|
|
@@ -150,7 +149,7 @@ module Sisimai::Lhost
|
|
|
150
149
|
|
|
151
150
|
ReasonPair.each_key do |f|
|
|
152
151
|
# Try to find the bounce reason by "bounceSubType"
|
|
153
|
-
next
|
|
152
|
+
next if ReasonPair[f] != p["bounceSubType"]
|
|
154
153
|
v["reason"] = f; break
|
|
155
154
|
end
|
|
156
155
|
|
|
@@ -24,7 +24,7 @@ module Sisimai::Lhost
|
|
|
24
24
|
match += 1 if mhead["subject"] == "[BOUNCE]"
|
|
25
25
|
match += 1 if mhead["message-id"].to_s.include?(".JavaMail.")
|
|
26
26
|
match += 1 if mhead["received"].any? { |a| a.include?("JAMES SMTP Server") }
|
|
27
|
-
return nil
|
|
27
|
+
return nil if match == 0
|
|
28
28
|
|
|
29
29
|
dscontents = [Sisimai::Lhost.DELIVERYSTATUS]; v = dscontents[-1]
|
|
30
30
|
emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
|
|
@@ -87,7 +87,7 @@ module Sisimai::Lhost
|
|
|
87
87
|
|
|
88
88
|
end
|
|
89
89
|
end
|
|
90
|
-
return nil
|
|
90
|
+
return nil if recipients == 0
|
|
91
91
|
|
|
92
92
|
if emailparts[1].empty?
|
|
93
93
|
# The original message is empty
|
|
@@ -22,9 +22,9 @@ module Sisimai::Lhost
|
|
|
22
22
|
# @return [Hash] Bounce data list and message/rfc822 part
|
|
23
23
|
# @return [Nil] it failed to decode or the arguments are missing
|
|
24
24
|
def inquire(mhead, mbody)
|
|
25
|
-
return nil
|
|
26
|
-
return nil
|
|
27
|
-
return nil
|
|
25
|
+
return nil if mhead['from'].include?('postmaster@') == false
|
|
26
|
+
return nil if %w[biglobe inacatv tmtv ttv].none? { |a| mhead['from'].include?('@' + a + '.ne.jp') }
|
|
27
|
+
return nil if mhead['subject'].start_with?('Returned mail:') == false
|
|
28
28
|
|
|
29
29
|
dscontents = [Sisimai::Lhost.DELIVERYSTATUS]; v = nil
|
|
30
30
|
emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
|
|
@@ -67,7 +67,7 @@ module Sisimai::Lhost
|
|
|
67
67
|
v = dscontents[-1]
|
|
68
68
|
end
|
|
69
69
|
|
|
70
|
-
next
|
|
70
|
+
next if Sisimai::Address.is_emailaddress(e) == false
|
|
71
71
|
v['recipient'] = e
|
|
72
72
|
recipients += 1
|
|
73
73
|
else
|
|
@@ -75,14 +75,14 @@ module Sisimai::Lhost
|
|
|
75
75
|
v['diagnosis'] += "#{e }"
|
|
76
76
|
end
|
|
77
77
|
end
|
|
78
|
-
return nil
|
|
78
|
+
return nil if recipients == 0
|
|
79
79
|
|
|
80
80
|
dscontents.each do |e|
|
|
81
81
|
e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'])
|
|
82
82
|
|
|
83
83
|
MessagesOf.each_key do |r|
|
|
84
84
|
# Verify each regular expression of session errors
|
|
85
|
-
next
|
|
85
|
+
next if MessagesOf[r].none? { |a| e['diagnosis'].include?(a) }
|
|
86
86
|
e['reason'] = r
|
|
87
87
|
break
|
|
88
88
|
end
|
|
@@ -36,7 +36,7 @@ module Sisimai::Lhost
|
|
|
36
36
|
# Message-ID: <courier.4D025E3A.00001792@5jo.example.org>
|
|
37
37
|
match += 1 if mhead['message-id'].start_with?('<courier.')
|
|
38
38
|
end
|
|
39
|
-
return nil
|
|
39
|
+
return nil if match == 0
|
|
40
40
|
|
|
41
41
|
require 'sisimai/rfc1123'
|
|
42
42
|
require 'sisimai/rfc1894'
|
|
@@ -94,11 +94,11 @@ module Sisimai::Lhost
|
|
|
94
94
|
v['diagnosis'] = o[2]
|
|
95
95
|
else
|
|
96
96
|
# Other DSN fields defined in RFC3464
|
|
97
|
-
next
|
|
97
|
+
next if fieldtable[o[0]].nil?
|
|
98
98
|
next if o[3] == "host" && Sisimai::RFC1123.is_internethost(o[2]) == false
|
|
99
99
|
v[fieldtable[o[0]]] = o[2]
|
|
100
100
|
|
|
101
|
-
next
|
|
101
|
+
next if f != 1
|
|
102
102
|
permessage[fieldtable[o[0]]] = o[2]
|
|
103
103
|
end
|
|
104
104
|
else
|
|
@@ -114,14 +114,14 @@ module Sisimai::Lhost
|
|
|
114
114
|
thecommand = Sisimai::SMTP::Command.find(e)
|
|
115
115
|
else
|
|
116
116
|
# Continued line of the value of Diagnostic-Code field
|
|
117
|
-
next
|
|
118
|
-
next
|
|
117
|
+
next if readslices[-2].start_with?('Diagnostic-Code:') == false
|
|
118
|
+
next if e.start_with?(' ') == false
|
|
119
119
|
v['diagnosis'] += " #{Sisimai::String.sweep(e)}"
|
|
120
120
|
readslices[-1] = "Diagnostic-Code: #{e}"
|
|
121
121
|
end
|
|
122
122
|
end
|
|
123
123
|
end
|
|
124
|
-
return nil
|
|
124
|
+
return nil if recipients == 0
|
|
125
125
|
|
|
126
126
|
dscontents.each do |e|
|
|
127
127
|
# Set default values if each value is empty.
|
|
@@ -131,7 +131,7 @@ module Sisimai::Lhost
|
|
|
131
131
|
|
|
132
132
|
MessagesOf.each_key do |r|
|
|
133
133
|
# Verify each regular expression of session errors
|
|
134
|
-
next
|
|
134
|
+
next if MessagesOf[r].none? { |a| e['diagnosis'].include?(a) }
|
|
135
135
|
e['reason'] = r
|
|
136
136
|
break
|
|
137
137
|
end
|
data/lib/sisimai/lhost/domino.rb
CHANGED
|
@@ -26,7 +26,7 @@ module Sisimai::Lhost
|
|
|
26
26
|
# @return [Hash] Bounce data list and message/rfc822 part
|
|
27
27
|
# @return [Nil] it failed to decode or the arguments are missing
|
|
28
28
|
def inquire(mhead, mbody)
|
|
29
|
-
return nil
|
|
29
|
+
return nil if mhead['subject'].start_with?('DELIVERY FAILURE:', 'DELIVERY_FAILURE:') == false
|
|
30
30
|
|
|
31
31
|
require 'sisimai/rfc1123'
|
|
32
32
|
require 'sisimai/rfc1894'
|
|
@@ -107,17 +107,17 @@ module Sisimai::Lhost
|
|
|
107
107
|
v['diagnosis'] = o[2] if v['diagnosis'].empty?
|
|
108
108
|
else
|
|
109
109
|
# Other DSN fields defined in RFC3464
|
|
110
|
-
next
|
|
110
|
+
next if fieldtable[o[0]].nil?
|
|
111
111
|
next if o[3] == "host" && Sisimai::RFC1123.is_internethost(o[2]) == false
|
|
112
112
|
v[fieldtable[o[0]]] = o[2]
|
|
113
113
|
|
|
114
|
-
next
|
|
114
|
+
next if f != 1
|
|
115
115
|
permessage[fieldtable[o[0]]] = o[2]
|
|
116
116
|
end
|
|
117
117
|
end
|
|
118
118
|
end
|
|
119
119
|
end
|
|
120
|
-
return nil
|
|
120
|
+
return nil if recipients == 0
|
|
121
121
|
|
|
122
122
|
dscontents.each do |e|
|
|
123
123
|
e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'])
|
|
@@ -126,7 +126,7 @@ module Sisimai::Lhost
|
|
|
126
126
|
|
|
127
127
|
MessagesOf.each_key do |r|
|
|
128
128
|
# Check each regular expression of Domino error messages
|
|
129
|
-
next
|
|
129
|
+
next if MessagesOf[r].none? { |a| e['diagnosis'].include?(a) }
|
|
130
130
|
e['reason'] = r
|
|
131
131
|
e['status'] = Sisimai::SMTP::Status.code(r, false) if e["status"].empty?
|
|
132
132
|
break
|
|
@@ -134,7 +134,7 @@ module Sisimai::Lhost
|
|
|
134
134
|
end
|
|
135
135
|
|
|
136
136
|
# Set the value of subjecttxt as a Subject if there is no original message in the bounce mail.
|
|
137
|
-
emailparts[1] += "Subject: #{subjecttxt}\n"
|
|
137
|
+
emailparts[1] += "Subject: #{subjecttxt}\n" if emailparts[1].include?("\nSubject:") == false
|
|
138
138
|
|
|
139
139
|
return {"ds" => dscontents, "rfc822" => emailparts[1]}
|
|
140
140
|
end
|
|
@@ -38,8 +38,8 @@ module Sisimai::Lhost
|
|
|
38
38
|
# @return [Hash] Bounce data list and message/rfc822 part
|
|
39
39
|
# @return [Nil] it failed to decode or the arguments are missing
|
|
40
40
|
def inquire(mhead, mbody)
|
|
41
|
-
return nil
|
|
42
|
-
return nil
|
|
41
|
+
return nil if mhead['subject'].start_with?('Mail delivery failed') == false
|
|
42
|
+
return nil if mhead['received'].none? { |a| a.include?(' (DragonFly Mail Agent') }
|
|
43
43
|
|
|
44
44
|
dscontents = [Sisimai::Lhost.DELIVERYSTATUS]; v = nil
|
|
45
45
|
emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
|
|
@@ -83,7 +83,7 @@ module Sisimai::Lhost
|
|
|
83
83
|
|
|
84
84
|
# Pick the remote hostname, and the SMTP command
|
|
85
85
|
# net.c:500| snprintf(errmsg, sizeof(errmsg), "%s [%s] did not like our %s:\n%s",
|
|
86
|
-
next
|
|
86
|
+
next if e.include?(' did not like our ') == false
|
|
87
87
|
next if v['rhost'] != ""
|
|
88
88
|
|
|
89
89
|
p = e.split(' ', 3)
|
|
@@ -91,13 +91,13 @@ module Sisimai::Lhost
|
|
|
91
91
|
v['command'] = Sisimai::SMTP::Command.find(e)
|
|
92
92
|
end
|
|
93
93
|
end
|
|
94
|
-
return nil
|
|
94
|
+
return nil if recipients == 0
|
|
95
95
|
|
|
96
96
|
dscontents.each do |e|
|
|
97
97
|
e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'])
|
|
98
98
|
MessagesOf.each_key do |r|
|
|
99
99
|
# Verify each regular expression of session errors
|
|
100
|
-
next
|
|
100
|
+
next if MessagesOf[r].none? { |a| e['diagnosis'].include?(a) }
|
|
101
101
|
e['reason'] = r
|
|
102
102
|
break
|
|
103
103
|
end
|
|
@@ -19,8 +19,8 @@ module Sisimai::Lhost
|
|
|
19
19
|
# @return [Hash] Bounce data list and message/rfc822 part
|
|
20
20
|
# @return [Nil] it failed to decode or the arguments are missing
|
|
21
21
|
def inquire(mhead, mbody)
|
|
22
|
-
return nil
|
|
23
|
-
return nil
|
|
22
|
+
return nil if mhead['from'].start_with?('"Mail Delivery System"') == false
|
|
23
|
+
return nil if mhead['subject'] != 'Mail delivery failed: returning message to sender'
|
|
24
24
|
|
|
25
25
|
dscontents = [Sisimai::Lhost.DELIVERYSTATUS]; v = nil
|
|
26
26
|
emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
|
|
@@ -76,7 +76,7 @@ module Sisimai::Lhost
|
|
|
76
76
|
end
|
|
77
77
|
end
|
|
78
78
|
end
|
|
79
|
-
return nil
|
|
79
|
+
return nil if recipients == 0
|
|
80
80
|
|
|
81
81
|
require 'sisimai/smtp/command'
|
|
82
82
|
dscontents.each do |e|
|
|
@@ -102,7 +102,7 @@ module Sisimai::Lhost
|
|
|
102
102
|
|
|
103
103
|
MessagesOf.each_key do |r|
|
|
104
104
|
# Verify each regular expression of session errors
|
|
105
|
-
next
|
|
105
|
+
next if MessagesOf[r].none? { |a| e['diagnosis'].include?(a) }
|
|
106
106
|
e['reason'] = r
|
|
107
107
|
break
|
|
108
108
|
end
|