sisimai 4.25.10 → 4.25.13

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.

Files changed (66) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +4 -3
  3. data/ChangeLog.md +44 -0
  4. data/README-JA.md +2 -2
  5. data/README.md +3 -3
  6. data/lib/sisimai/address.rb +6 -3
  7. data/lib/sisimai/data.rb +7 -1
  8. data/lib/sisimai/datetime.rb +15 -14
  9. data/lib/sisimai/lhost/amazonses.rb +1 -1
  10. data/lib/sisimai/lhost/domino.rb +29 -4
  11. data/lib/sisimai/lhost/einsundeins.rb +1 -1
  12. data/lib/sisimai/lhost/exim.rb +7 -4
  13. data/lib/sisimai/lhost/gsuite.rb +5 -0
  14. data/lib/sisimai/lhost/imailserver.rb +1 -1
  15. data/lib/sisimai/lhost/mailfoundry.rb +3 -4
  16. data/lib/sisimai/lhost/mailmarshalsmtp.rb +2 -2
  17. data/lib/sisimai/lhost/notes.rb +1 -1
  18. data/lib/sisimai/lhost/office365.rb +1 -1
  19. data/lib/sisimai/lhost/sendgrid.rb +2 -2
  20. data/lib/sisimai/lhost/verizon.rb +4 -4
  21. data/lib/sisimai/mail.rb +2 -1
  22. data/lib/sisimai/mime.rb +1 -1
  23. data/lib/sisimai/reason/blocked.rb +17 -4
  24. data/lib/sisimai/reason/exceedlimit.rb +4 -1
  25. data/lib/sisimai/reason/expired.rb +2 -0
  26. data/lib/sisimai/reason/filtered.rb +10 -9
  27. data/lib/sisimai/reason/hostunknown.rb +1 -0
  28. data/lib/sisimai/reason/norelaying.rb +8 -7
  29. data/lib/sisimai/reason/notaccept.rb +4 -3
  30. data/lib/sisimai/reason/policyviolation.rb +4 -1
  31. data/lib/sisimai/reason/rejected.rb +5 -1
  32. data/lib/sisimai/reason/spamdetected.rb +14 -4
  33. data/lib/sisimai/reason/suspend.rb +1 -0
  34. data/lib/sisimai/reason/systemerror.rb +3 -0
  35. data/lib/sisimai/reason/userunknown.rb +6 -1
  36. data/lib/sisimai/reason/virusdetected.rb +9 -3
  37. data/lib/sisimai/rfc1894.rb +24 -22
  38. data/lib/sisimai/rfc3464.rb +1 -1
  39. data/lib/sisimai/rfc3834.rb +1 -1
  40. data/lib/sisimai/rfc5322.rb +8 -3
  41. data/lib/sisimai/rhost/exchangeonline.rb +8 -1
  42. data/lib/sisimai/rhost/franceptt.rb +4 -0
  43. data/lib/sisimai/rhost.rb +1 -0
  44. data/lib/sisimai/smtp/error.rb +8 -6
  45. data/lib/sisimai/smtp/reply.rb +1 -1
  46. data/lib/sisimai/time.rb +1 -2
  47. data/lib/sisimai/version.rb +1 -1
  48. data/set-of-emails/maildir/bsd/lhost-aol-04.eml +23 -23
  49. data/set-of-emails/maildir/bsd/lhost-domino-02.eml +1 -2
  50. data/set-of-emails/maildir/bsd/lhost-sendmail-08.eml +1 -1
  51. data/set-of-emails/maildir/bsd/lhost-sendmail-11.eml +1 -1
  52. data/set-of-emails/maildir/bsd/rfc3464-41.eml +19 -0
  53. data/set-of-emails/maildir/bsd/rfc3464-42.eml +34 -0
  54. data/set-of-emails/maildir/bsd/{rhost-exchange-online-01.eml → rhost-exchangeonline-01.eml} +0 -0
  55. data/set-of-emails/maildir/bsd/{rhost-exchange-online-02.eml → rhost-exchangeonline-02.eml} +0 -0
  56. data/set-of-emails/maildir/bsd/{rhost-exchange-online-03.eml → rhost-exchangeonline-03.eml} +0 -0
  57. data/set-of-emails/maildir/bsd/rhost-franceptt-12.eml +82 -0
  58. data/set-of-emails/maildir/bsd/{rhost-google-apps-01.eml → rhost-googleapps-01.eml} +0 -0
  59. data/set-of-emails/maildir/bsd/{rhost-google-apps-02.eml → rhost-googleapps-02.eml} +0 -0
  60. data/set-of-emails/maildir/dos/{rhost-exchange-online-01.eml → rhost-exchangeonline-01.eml} +0 -0
  61. data/set-of-emails/maildir/dos/{rhost-google-apps-01.eml → rhost-googleapps-01.eml} +0 -0
  62. data/set-of-emails/maildir/mac/{rhost-exchange-online-01.eml → rhost-exchangeonline-01.eml} +0 -0
  63. data/set-of-emails/maildir/mac/{rhost-google-apps-01.eml → rhost-googleapps-01.eml} +0 -0
  64. data/sisimai-java.gemspec +4 -4
  65. data/sisimai.gemspec +4 -4
  66. metadata +23 -20
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ba874891fd9c23f0d4cde6c02241a5e956a4202cfffbcfd0768761b073381597
4
- data.tar.gz: 01cc1c85c60772b61e5d3e56917b4bf664e26d19a17a38cbb4be972475e4f295
3
+ metadata.gz: a8180c881f0465ad44be400dbcf8a79e457e97d32dfac0a3d9ab00c3753678a8
4
+ data.tar.gz: 9934a50dfd8ba8fc5fa321bd431bdc921eb842f951db23a783a5d48da89e7fbb
5
5
  SHA512:
6
- metadata.gz: fdbba88ba982e6c93e35c79a95b20a073ef3e4bcfa84b261de0347fdfbcf1f3e430e7eebc0418fd54efb639f48118512e883b63dc85ade1ec71521f728198955
7
- data.tar.gz: 616005c1de3152c7f5e501ecd8524d4eae0f7e1c95ae291849011b6c2baec01dbc29cdc4ed5a21abf306e3f29c86ca0690975daaee5b43afac860f08649620c6
6
+ metadata.gz: b2989c950b78fcbfc0e1782eca6733ac5cc35ecffb52b7b2b91337be47ab1dd32b5afe34db8f3e8aa5f05e9aa8ca268ca99df3472a7988f23769d2a3885d6ffb
7
+ data.tar.gz: 7eab0def18df498698cc9d58fcb71518d2d375d109a1108d8186370d8f39412e0bc250d108c9a5eb11fef42f05f08a35c7d7b4869fbccd2205a84253e68ea275
data/.travis.yml CHANGED
@@ -2,11 +2,12 @@ language: ruby
2
2
  rvm:
3
3
  # See http://rubies.travis-ci.org for Precompiled Ruby Versions
4
4
  - 2.1.1
5
- - 2.2.4
5
+ - 2.2.10
6
6
  # - 2.3.0
7
- # - 2.4.0
7
+ - 2.4.9
8
8
  # - 2.5.0
9
- - 2.6.0
9
+ - 2.6.6
10
+ - 2.7.0
10
11
  # - jruby-9.0.5.0
11
12
  # - jruby-9.1.9.0
12
13
  before_install:
data/ChangeLog.md CHANGED
@@ -3,6 +3,50 @@ RELEASE NOTES for Ruby version of Sisimai
3
3
  - releases: "https://github.com/sisimai/rb-sisimai/releases"
4
4
  - download: "https://rubygems.org/gems/sisimai"
5
5
 
6
+ v4.25.13
7
+ --------------------------------------------------------------------------------
8
+ - release: "Mon, 1 Aug 2022 16:05:55 +0900 (JST)"
9
+ - version: "4.25.13"
10
+ - changes:
11
+ - Nothing changed, follow the Perl version of Sisimai 4.25.13.
12
+
13
+ v4.25.12
14
+ --------------------------------------------------------------------------------
15
+ - release: "Mon, 22 Nov 2021 12:22:22 +0900 (JST)"
16
+ - version: "4.25.12"
17
+ - changes:
18
+ - Fix 2 encoding related errors:
19
+ - Fix an error with message `incompatible character encodings:ASCII-8BIT and
20
+ UTF-8` reported at issue #223. Thanks to @chahn
21
+ - Fix an error with message `invalid byte sequence in UTF-8 (ArgumentError)`
22
+ reported at issue #224. Thanks to @chahn
23
+ - Add `rfc3464-41.eml` and `rfc3464-42.eml` provided by @chahn
24
+ - Add a new error code of La Poste at `Sisimai::Rhost::FrancePTT` module and
25
+ a new sample email `rhost-franceptt-12.eml` into `set-of-emails` directory
26
+ imported from sisimai/p5-sisimai#441.
27
+ - Remove all the HTML elements from the value of `diagnosticcode`.
28
+ - Fix serious bugs:
29
+ - Both of the values of `deliverystatus` and `replycode` detected from the
30
+ message body did not use at `Sisimai::Lhost::Exim`.
31
+ - `true` method strictly checks the value of `smtpcommand` at some classes
32
+ in `Sisimai/Reason`. For example, when a detected reason is `spamdetected`
33
+ and `virusdetected` the value of `smtpcommand` should be `DATA` or an SMTP
34
+ command to be sent after `DATA`.
35
+
36
+ v4.25.11
37
+ --------------------------------------------------------------------------------
38
+ - release: "Mon, 22 Feb 2021 21:15:22 +0900 (JST)"
39
+ - version: "4.25.11"
40
+ - changes:
41
+ - Fix typo in `Sisimai::RFC3464`
42
+ - Import some commits from Sisimai version 5 preview #
43
+ - Improved code for getting an email address in `Sisimai::Address`
44
+ - Improved code for checking the day of month value, for converting a full
45
+ month name and a full day of the week at `Sisimai::DateTime`
46
+ - Improvement code for picking text blocks of message/rfc822 part in RFC5322
47
+ - Add 60+ error message patterns
48
+ - Improved code for encodings in `Sisimai::Lhost::Domino`, `Sisimai::String`
49
+
6
50
  v4.25.10
7
51
  --------------------------------------------------------------------------------
8
52
  - release: "Tue, 22 Dec 2020 13:22:22 +0900 (JST)"
data/README-JA.md CHANGED
@@ -220,8 +220,8 @@ Differences between Ruby version and Perl version
220
220
  | メール解析速度(1000通のメール) | 2.22秒[2] | 1.35秒 |
221
221
  | インストール方法 | gem install | cpanm, cpm |
222
222
  | 依存モジュール数(コアモジュールを除く) | 1モジュール | 2モジュール |
223
- | LOC:ソースコードの行数 | 10300行 | 10500行 |
224
- | テスト件数(spec/,t/,xt/ディレクトリ) | 236000件 | 265000件 |
223
+ | LOC:ソースコードの行数 | 10400行 | 10500行 |
224
+ | テスト件数(spec/,t/,xt/ディレクトリ) | 241000件 | 270000件 |
225
225
  | ライセンス | 二条項BSD | 二条項BSD |
226
226
  | 開発会社によるサポート契約 | 提供中 | 提供中 |
227
227
 
data/README.md CHANGED
@@ -225,8 +225,8 @@ and bounceHammer are available at
225
225
  | The speed of parsing email(1000 emails) | 2.22s[2] | 1.35s |
226
226
  | How to install | gem install | cpanm, cpm |
227
227
  | Dependencies (Except core modules) | 1 module | 2 modules |
228
- | LOC:Source lines of code | 10300 lines | 10500 lines |
229
- | The number of tests(spec/,t/,xt/) directory | 236000 tests | 265000 tests |
228
+ | LOC:Source lines of code | 10400 lines | 10500 lines |
229
+ | The number of tests(spec/,t/,xt/) directory | 241000 tests | 270000 tests |
230
230
  | License | BSD 2-Clause | BSD 2-Clause |
231
231
  | Support Contract provided by Developer | Available | Available |
232
232
 
@@ -283,7 +283,7 @@ Author
283
283
 
284
284
  Copyright
285
285
  ===============================================================================
286
- Copyright (C) 2015-2020 azumakuniyuki, All Rights Reserved.
286
+ Copyright (C) 2015-2021 azumakuniyuki, All Rights Reserved.
287
287
 
288
288
  License
289
289
  ===============================================================================
@@ -240,7 +240,7 @@ module Sisimai
240
240
 
241
241
  # Remove angle brackets, other brackets, and quotations: []<>{}'`
242
242
  # except a domain part is an IP address like neko@[192.0.2.222]
243
- e[:address] = e[:address].sub(/\A[\[<{('`]/, '').sub(/['`>})]\z/, '')
243
+ e[:address] = e[:address].sub(/\A[\[<{('`]/, '').sub(/[.'`>});]\z/, '')
244
244
  e[:address].chomp!(']') unless e[:address] =~ /[@]\[[0-9A-Za-z:\.]+\]\z/
245
245
  e[:address] = e[:address].sub(/\A["]/, '').chomp('"') unless e[:address] =~ /\A["].+["][@]/
246
246
 
@@ -321,13 +321,16 @@ module Sisimai
321
321
  addrs = Sisimai::Address.find(argv1)
322
322
  return nil unless addrs
323
323
  return nil if addrs.empty?
324
+
324
325
  thing = addrs.shift
326
+ heads = ['<']
327
+ tails = ['>', ',', '.', ';']
325
328
 
326
329
  if cv = thing[:address].match(/\A([^\s]+)[@]([^@]+)\z/) ||
327
330
  thing[:address].match(/\A(["].+?["])[@]([^@]+)\z/)
328
331
  # Get the local part and the domain part from the email address
329
- lpart = cv[1]
330
- dpart = cv[2]
332
+ lpart = cv[1]; heads.each { |e| lpart.gsub!(/\A#{e}/, '') if lpart.start_with?(e) }
333
+ dpart = cv[2]; tails.each { |e| dpart.gsub!(/#{e}\z/, '') if dpart.end_with?(e) }
331
334
  email = Sisimai::Address.expand_verp(thing[:address])
332
335
  aname = nil
333
336
 
data/lib/sisimai/data.rb CHANGED
@@ -262,10 +262,16 @@ module Sisimai
262
262
  # 550-5.7.1 likely unsolicited mail. To reduce the amount of spam sent to Gmail,
263
263
  # 550-5.7.1 this message has been blocked. Please visit
264
264
  # 550 5.7.1 https://support.google.com/mail/answer/188131 for more information.
265
- p['diagnosticcode'] = Sisimai::String.sweep(p['diagnosticcode'].gsub(re, ' '))
265
+ p['diagnosticcode'] = p['diagnosticcode'].gsub(re, ' ')
266
+ p['diagnosticcode'] = Sisimai::String.sweep(p['diagnosticcode'].sub(%r|<html>.+</html>|i, ''))
266
267
  end
267
268
  end
268
269
 
270
+ if Sisimai::String.is_8bit(p['diagnosticcode'])
271
+ # To avoid incompatible character encodings: ASCII-8BIT and UTF-8 (Encoding::CompatibilityError
272
+ p['diagnosticcode'] = p['diagnosticcode'].force_encoding('UTF-8').scrub('?')
273
+ end
274
+
269
275
  p['diagnostictype'] ||= 'X-UNIX' if p['reason'] == 'mailererror'
270
276
  p['diagnostictype'] ||= 'SMTP' unless %w[feedback vacation].include?(p['reason'])
271
277
 
@@ -207,24 +207,24 @@ module Sisimai
207
207
  end
208
208
 
209
209
  # Month name list
210
- # @param [Integer] argv1 Require full name or not
210
+ # @param [Boolean] argv1 Require full name or not
211
211
  # @return [Array, String] Month name list or month name
212
212
  # @example Get the names of each month
213
- # monthname() #=> [ 'Jan', 'Feb', ... ]
214
- # monthname(1) #=> [ 'January', 'February', 'March', ... ]
215
- def monthname(argv1 = 0)
216
- value = argv1 > 0 ? :full : :abbr
213
+ # monthname() #=> [ 'Jan', 'Feb', ... ]
214
+ # monthname(true) #=> [ 'January', 'February', 'March', ... ]
215
+ def monthname(argv1 = false)
216
+ value = argv1 ? :full : :abbr
217
217
  return MonthName[value]
218
218
  end
219
219
 
220
220
  # List of day of week
221
- # @param [Integer] argv1 Require full name
221
+ # @param [Boolean] argv1 Require full name
222
222
  # @return [Array, String] List of day of week or day of week
223
223
  # @example Get the names of each day of week
224
- # dayofweek() #=> [ 'Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat' ]
225
- # dayofweek(1) #=> [ 'Sunday', 'Monday', 'Tuesday', ... ]
226
- def dayofweek(argv1 = 0)
227
- value = argv1 > 0 ? :full : :abbr
224
+ # dayofweek() #=> [ 'Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat' ]
225
+ # dayofweek(true) #=> [ 'Sunday', 'Monday', 'Tuesday', ... ]
226
+ def dayofweek(argv1 = false)
227
+ value = argv1 ? :full : :abbr
228
228
  return DayOfWeek[value]
229
229
  end
230
230
 
@@ -257,9 +257,10 @@ module Sisimai
257
257
 
258
258
  while p = timetokens.shift do
259
259
  # Parse each piece of time
260
- if p =~ /\A[A-Z][a-z]{2}[,]?\z/
260
+ if p =~ /\A[A-Z][a-z]{2,}[,]?\z/
261
261
  # Day of week or Day of week; Thu, Apr, ...
262
- p.chop if p.size == 4 # Thu, -> Thu
262
+ p.gsub!(/,\z/, '') if p.end_with?(',') # "Thu," => "Thu"
263
+ p = p[0,3] if p.size > 3
263
264
 
264
265
  if DayOfWeek[:abbr].include?(p)
265
266
  # Day of week; Mon, Thu, Sun,...
@@ -273,7 +274,7 @@ module Sisimai
273
274
  # Year or Day; 2005, 31, 04, 1, ...
274
275
  if p.to_i > 31
275
276
  # The piece is the value of an year
276
- v[:Y] = p
277
+ v[:Y] = p.to_i
277
278
  else
278
279
  # The piece is the value of a day
279
280
  if v[:d]
@@ -441,7 +442,7 @@ module Sisimai
441
442
  # @example Get timezone offset string of specified seconds
442
443
  # second2tz(12345) #=> '+0325'
443
444
  def second2tz(argv1)
444
- return '+0000' unless argv1.is_a?(Number)
445
+ return '+0000' unless argv1.is_a?(::Integer)
445
446
  return nil if argv1.abs > TZ_OFFSET # UTC+14 + 1(DST?)
446
447
 
447
448
  digit = { :operator => '+' }
@@ -182,7 +182,7 @@ module Sisimai::Lhost
182
182
  v['status'] = Sisimai::SMTP::Status.find(v['diagnosis']) || ''
183
183
  v['replycode'] = Sisimai::SMTP::Reply.find(v['diagnosis']) || ''
184
184
  v['reason'] = 'delivered'
185
- v['action'] = 'deliverable'
185
+ v['action'] = 'delivered'
186
186
 
187
187
  v['date'] = o['timestamp'] || p['mail']['timestamp']
188
188
  v['date'].sub!(/[.]\d+Z\z/, '')
@@ -7,12 +7,13 @@ module Sisimai::Lhost
7
7
  require 'sisimai/lhost'
8
8
 
9
9
  Indicators = Sisimai::Lhost.INDICATORS
10
- ReBackbone = %r|^Content-Type:[ ]message/delivery-status|.freeze
10
+ ReBackbone = %r|^Content-Type:[ ]message/rfc822|.freeze
11
11
  StartingOf = { message: ['Your message'] }.freeze
12
12
  MessagesOf = {
13
13
  'userunknown' => [
14
14
  'not listed in Domino Directory',
15
15
  'not listed in public Name & Address Book',
16
+ "dans l'annuaire Domino", # TODO: "non répertorié dans l'annuaire Domino",
16
17
  'Domino ディレクトリには見つかりません',
17
18
  ],
18
19
  'filtered' => ['Cannot route mail to user'],
@@ -25,7 +26,11 @@ module Sisimai::Lhost
25
26
  # @return [Hash] Bounce data list and message/rfc822 part
26
27
  # @return [Nil] it failed to parse or the arguments are missing
27
28
  def make(mhead, mbody)
28
- return nil unless mhead['subject'].start_with?('DELIVERY FAILURE:')
29
+ return nil unless mhead['subject'].start_with?('DELIVERY FAILURE:', 'DELIVERY_FAILURE:')
30
+
31
+ require 'sisimai/rfc1894'
32
+ fieldtable = Sisimai::RFC1894.FIELDTABLE
33
+ permessage = {} # (Hash) Store values of each Per-Message field
29
34
 
30
35
  dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
31
36
  emailsteak = Sisimai::RFC5322.fillet(mbody, ReBackbone)
@@ -87,6 +92,24 @@ module Sisimai::Lhost
87
92
  elsif cv = e.match(/\A[ ][ ]Subject: (.+)\z/)
88
93
  # Subject: Nyaa
89
94
  subjecttxt = cv[1]
95
+
96
+ elsif f = Sisimai::RFC1894.match(e)
97
+ # There are some fields defined in RFC3464, try to match
98
+ o = Sisimai::RFC1894.field(e) || next
99
+ next if o[-1] == 'addr'
100
+
101
+ if o[-1] == 'code'
102
+ # Diagnostic-Code: SMTP; 550 5.1.1 <userunknown@example.jp>... User Unknown
103
+ v['spec'] = o[1] if v['spec'].to_s.empty?
104
+ v['diagnosis'] = o[2] if v['diagnosis'].to_s.empty?
105
+ else
106
+ # Other DSN fields defined in RFC3464
107
+ next unless fieldtable[o[0]]
108
+ v[fieldtable[o[0]]] = o[2]
109
+
110
+ next unless f == 1
111
+ permessage[fieldtable[o[0]]] = o[2]
112
+ end
90
113
  end
91
114
  end
92
115
  end
@@ -95,12 +118,14 @@ module Sisimai::Lhost
95
118
  dscontents.each do |e|
96
119
  e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'])
97
120
  e['recipient'] = Sisimai::Address.s3s4(e['recipient'])
121
+ e['lhost'] ||= permessage['rhost']
122
+ permessage.each_key { |a| e[a] ||= permessage[a] || '' }
98
123
 
99
124
  MessagesOf.each_key do |r|
100
125
  # Check each regular expression of Domino error messages
101
126
  next unless MessagesOf[r].any? { |a| e['diagnosis'].include?(a) }
102
- e['reason'] = r
103
- e['status'] = Sisimai::SMTP::Status.code(r.to_s, false) || ''
127
+ e['reason'] = r
128
+ e['status'] ||= Sisimai::SMTP::Status.code(r.to_s, false) || ''
104
129
  break
105
130
  end
106
131
  end
@@ -52,7 +52,7 @@ module Sisimai::Lhost
52
52
  # http://postmaster.1and1.com/en/error-messages?ip=%1s
53
53
  v = dscontents[-1]
54
54
 
55
- if cv = e.match(/\A([^ ]+[@][^ ]+)\z/)
55
+ if cv = e.match(/\A([^ ]+[@][^ ]+?)[:]?\z/)
56
56
  # general@example.eu
57
57
  if v['recipient']
58
58
  # There are multiple recipient addresses in the message body.
@@ -265,7 +265,10 @@ module Sisimai::Lhost
265
265
  # Content-type: message/delivery-status
266
266
  nextcursor = 1 if e.start_with?(StartingOf[:deliverystatus][0])
267
267
  v['alterrors'] ||= ''
268
- v['alterrors'] << e + ' ' if e.start_with?(' ')
268
+ if e.start_with?("\s", "\t")
269
+ e.sub!(/\A[\s\t]+/, '')
270
+ v['alterrors'] << e + ' ' unless v['alterrors'].include?(e)
271
+ end
269
272
  end
270
273
  else
271
274
  if dscontents.size == recipients
@@ -375,7 +378,7 @@ module Sisimai::Lhost
375
378
  rxdiagnosis = %r/e['diagnosis']/i
376
379
  # Override the value of diagnostic code message because
377
380
  # the value of alterrors includes the value of diagnosis.
378
- e['diagnosis'] = e['alterrors'] if e['alterrors'] =~ rxdiagnosis
381
+ e['diagnosis'] = e['alterrors'] if e['alterrors'].downcase.include?(e['diagnosis'].downcase)
379
382
  end
380
383
  end
381
384
  e.delete('alterrors')
@@ -437,8 +440,8 @@ module Sisimai::Lhost
437
440
  # Diagnostic-Code: smtp; 450 TEMPERROR: retry timeout exceeded
438
441
  # The value of "Status:" indicates permanent error but the value
439
442
  # of SMTP reply code in Diagnostic-Code: field is "TEMPERROR"!!!!
440
- sv = Sisimai::SMTP::Status.find(e['diagnosis'])
441
- rv = Sisimai::SMTP::Reply.find(e['diagnosis'])
443
+ sv = e['status'] || Sisimai::SMTP::Status.find(e['diagnosis'])
444
+ rv = e['replycode'] || Sisimai::SMTP::Reply.find(e['diagnosis'])
442
445
  s1 = 0 # First character of Status as integer
443
446
  r1 = 0 # First character of SMTP reply code as integer
444
447
 
@@ -82,6 +82,11 @@ module Sisimai::Lhost
82
82
  next unless fieldtable[o[0]]
83
83
  v[fieldtable[o[0]]] = o[2]
84
84
 
85
+ if fieldtable[o[0]] == 'lhost'
86
+ # Do not set an email address as a hostname in "lhost" value
87
+ v['lhost'] = '' if v['lhost'].include?('@')
88
+ end
89
+
85
90
  next unless f == 1
86
91
  permessage[fieldtable[o[0]]] = o[2]
87
92
  end
@@ -71,7 +71,7 @@ module Sisimai::Lhost
71
71
  dscontents << Sisimai::Lhost.DELIVERYSTATUS
72
72
  v = dscontents[-1]
73
73
  end
74
- v['recipient'] = cv[1]
74
+ v['recipient'] = Sisimai::Address.s3s4(cv[1])
75
75
  recipients += 1
76
76
  else
77
77
  # Other error message text
@@ -9,7 +9,7 @@ module Sisimai::Lhost
9
9
  Indicators = Sisimai::Lhost.INDICATORS
10
10
  ReBackbone = %r|^Content-Type:[ ]message/rfc822|.freeze
11
11
  StartingOf = {
12
- message: ['This is a MIME encoded message'],
12
+ message: ['Unable to deliver message to:'],
13
13
  error: ['Delivery failed for the following reason:'],
14
14
  }.freeze
15
15
 
@@ -34,8 +34,7 @@ module Sisimai::Lhost
34
34
  # to the previous line of the beginning of the original message.
35
35
  if readcursor == 0
36
36
  # Beginning of the bounce message or delivery status part
37
- readcursor |= Indicators[:deliverystatus] if e == StartingOf[:message][0]
38
- next
37
+ readcursor |= Indicators[:deliverystatus] if e.start_with?(StartingOf[:message][0])
39
38
  end
40
39
  next if (readcursor & Indicators[:deliverystatus]) == 0
41
40
  next if e.empty?
@@ -44,7 +43,7 @@ module Sisimai::Lhost
44
43
  # Delivery failed for the following reason:
45
44
  # Server mx22.example.org[192.0.2.222] failed with: 550 <kijitora@example.org> No such user here
46
45
  #
47
- # This has been a permanent failure. No further delivery attempts will be made.
46
+ # This has been a permanent failure. No further delivery attempts will be made.
48
47
  v = dscontents[-1]
49
48
 
50
49
  if cv = e.match(/\AUnable to deliver message to: [<]([^ ]+[@][^ ]+)[>]\z/)
@@ -32,10 +32,10 @@ module Sisimai::Lhost
32
32
  regularexp = nil
33
33
  v = nil
34
34
 
35
- boundary00 = Sisimai::MIME.boundary(mhead['content-type']) || ''
35
+ boundary00 = Sisimai::MIME.boundary(mhead['content-type'], 1) || ''
36
36
  regularexp = if boundary00.size > 0
37
37
  # Convert to regular expression
38
- Regexp.new('\A' << Regexp.escape('--' << boundary00 << '--') << '\z')
38
+ Regexp.new('\A' << Regexp.escape(boundary00) << '\z')
39
39
  else
40
40
  regularexp = %r/\A[ \t]*[+]+[ \t]*\z/
41
41
  end
@@ -14,7 +14,7 @@ module Sisimai::Lhost
14
14
  'User not listed in public Name & Address Book',
15
15
  'ディレクトリのリストにありません',
16
16
  ],
17
- networkerror: ['Message has exceeded maximum hop count'],
17
+ 'networkerror' => ['Message has exceeded maximum hop count'],
18
18
  }.freeze
19
19
 
20
20
  # Parse bounce messages from Lotus Notes
@@ -188,7 +188,7 @@ module Sisimai::Lhost
188
188
  e['diagnosis'] = Sisimai::String.sweep(e['diagnosis']) || ''
189
189
  if e['status'].empty? || e['status'].end_with?('.0.0')
190
190
  # There is no value of Status header or the value is 5.0.0, 4.0.0
191
- e['status'] = Sisimai::SMTP::Status.find(e['diagnosis']) || ''
191
+ e['status'] = Sisimai::SMTP::Status.find(e['diagnosis']) || e['status']
192
192
  end
193
193
 
194
194
  ReCommands.each_key do |p|
@@ -86,7 +86,7 @@ module Sisimai::Lhost
86
86
  # Arrival-Date: 2012-12-31 23-59-59
87
87
  next unless cv = e.match(/\AArrival-Date: (\d{4})[-](\d{2})[-](\d{2}) (\d{2})[-](\d{2})[-](\d{2})\z/)
88
88
  o[1] << 'Thu, ' << cv[3] + ' '
89
- o[1] << Sisimai::DateTime.monthname(0)[cv[2].to_i - 1]
89
+ o[1] << Sisimai::DateTime.monthname(false)[cv[2].to_i - 1]
90
90
  o[1] << ' ' << cv[1] + ' ' << [cv[4], cv[5], cv[6]].join(':')
91
91
  o[1] << ' ' << Sisimai::DateTime.abbr2tz('CDT')
92
92
  else
@@ -124,7 +124,7 @@ module Sisimai::Lhost
124
124
  if e['status'] == '5.0.0' || e['status'] == '4.0.0'
125
125
  # Get the value of D.S.N. from the error message or the value of
126
126
  # Diagnostic-Code header.
127
- e['status'] = Sisimai::SMTP::Status.find(e['diagnosis']) || ''
127
+ e['status'] = Sisimai::SMTP::Status.find(e['diagnosis']) || e['status']
128
128
  end
129
129
 
130
130
  if e['action'] == 'expired'
@@ -44,8 +44,8 @@ module Sisimai::Lhost
44
44
  # The attempted recipient address does not exist.
45
45
  'userunknown' => ['550 - Requested action not taken: no such user here'],
46
46
  }
47
- boundary00 = Sisimai::MIME.boundary(mhead['content-type']) || ''
48
- rebackbone = Regexp.new('^' << Regexp.escape('--' << boundary00 << '--')) unless boundary00.empty?
47
+ boundary00 = Sisimai::MIME.boundary(mhead['content-type'], 1) || ''
48
+ rebackbone = Regexp.new('^' << Regexp.escape(boundary00)) unless boundary00.empty?
49
49
  emailsteak = Sisimai::RFC5322.fillet(mbody, rebackbone)
50
50
  bodyslices = emailsteak[0].split("\n")
51
51
 
@@ -93,8 +93,8 @@ module Sisimai::Lhost
93
93
  # vzwpix.com
94
94
  startingof = { message: ['Message could not be delivered to mobile'] }
95
95
  messagesof = { 'userunknown' => ['No valid recipients for this MM'] }
96
- boundary00 = Sisimai::MIME.boundary(mhead['content-type'])
97
- rebackbone = Regexp.new('^' << Regexp.escape('--' << boundary00 << '--')) unless boundary00.empty?
96
+ boundary00 = Sisimai::MIME.boundary(mhead['content-type'], 1)
97
+ rebackbone = Regexp.new('^' << Regexp.escape(boundary00)) unless boundary00.empty?
98
98
  emailsteak = Sisimai::RFC5322.fillet(mbody, rebackbone)
99
99
  bodyslices = emailsteak[0].split("\n")
100
100
 
data/lib/sisimai/mail.rb CHANGED
@@ -24,7 +24,7 @@ module Sisimai
24
24
  # Sisimai::Mail.new('<STDIN>')
25
25
  classname = self.class.to_s << '::STDIN'
26
26
  parameter['kind'] = 'stdin'
27
- parameter['path'] = $stdin
27
+ parameter['path'] = '<STDIN>'
28
28
  else
29
29
  # The argumenet is a mailbox or a Maildir/.
30
30
  mediatype = argv1.include?("\n") ? 'memory' : File.ftype(argv1)
@@ -51,6 +51,7 @@ module Sisimai
51
51
  # The argument neither a mailbox nor a Maildir/.
52
52
  classname = self.class.to_s << '::STDIN'
53
53
  parameter['kind'] = 'stdin'
54
+ parameter['path'] = '<STDIN>'
54
55
  end
55
56
  return nil unless classname
56
57
 
data/lib/sisimai/mime.rb CHANGED
@@ -225,7 +225,7 @@ module Sisimai
225
225
 
226
226
  plain = nil
227
227
  if cv = argv1.match(%r|([+/\=0-9A-Za-z\r\n]+)|) then plain = Base64.decode64(cv[1]) end
228
- return plain.force_encoding('UTF-8')
228
+ return plain.scrub('?')
229
229
  end
230
230
 
231
231
  # Get boundary string
@@ -10,7 +10,9 @@ module Sisimai
10
10
  # Imported from p5-Sisimail/lib/Sisimai/Reason/Blocked.pm
11
11
  class << self
12
12
  Regex = %r{(?>
13
- access[ ]denied[.][ ]ip[ ]name[ ]lookup[ ]failed
13
+ [ ]said:[ ]550[ ]blocked
14
+ |[(][^ ]+[@][^ ]+:blocked[)]
15
+ |access[ ]denied[.][ ]ip[ ]name[ ]lookup[ ]failed
14
16
  |access[ ]from[ ]ip[ ]address[ ][^ ]+[ ]blocked
15
17
  |all[ ]mail[ ]servers[ ]must[ ]have[ ]a[ ]ptr[ ]record[ ]with[ ]a[ ]valid[ ]reverse[ ]dns[ ]entry
16
18
  |bad[ ](:?dns[ ]ptr[ ]resource[ ]record|sender[ ]ip[ ]address)
@@ -52,11 +54,13 @@ module Sisimai
52
54
  |dnsbl:attrbl
53
55
  |dynamic/zombied/spam[ ]ips[ ]blocked
54
56
  |email[ ]blocked[ ]by[ ](?:[^ ]+[.]barracudacentral[.]org|spamhaus)
57
+ |error:[ ]no[ ]valid[ ]recipients[ ]from[ ]
55
58
  |esmtp[ ]not[ ]accepting[ ]connections # icloud.com
56
59
  |fix[ ]reverse[ ]dns[ ]for[ ][^ ]+
57
60
  |go[ ]away
58
61
  |helo[ ]command[ ]rejected:
59
62
  |host[ ]+[^ ]refused[ ]to[ ]talk[ ]to[ ]me:[ ]\d+[ ]blocked
63
+ |host[ ]network[ ]not[ ]allowed
60
64
  |hosts[ ]with[ ]dynamic[ ]ip
61
65
  |http://(?:
62
66
  spf[.]pobox[.]com/why[.]html
@@ -66,7 +70,7 @@ module Sisimai
66
70
  |ip[ ]\d{1,3}[.]\d{1,3}[.]\d{1,3}[.]\d{1,3}[ ]is[ ]blocked[ ]by[ ]EarthLink # Earthlink
67
71
  |ip[/]domain[ ]reputation[ ]problems
68
72
  |is[ ](?:
69
- in[ ]a[ ]black[ ]list[ ]at[ ][^ ]+[.]
73
+ in[ ]a[ ]black[ ]list(?:[ ]at[ ][^ ]+[.])?
70
74
  |in[ ]an[ ][^ ]+rbl[ ]on[ ][^ ]+
71
75
  |not[ ]allowed[ ]to[ ]send[ ](?:
72
76
  mail[ ]from
@@ -76,6 +80,7 @@ module Sisimai
76
80
  |mail[ ]server[ ]at[ ][^ ]+[ ]is[ ]blocked
77
81
  |mail[ ]from[ ]\d+[.]\d+[.]\d+[.]\d[ ]refused:
78
82
  |message[ ]from[ ][^ ]+[ ]rejected[ ]based[ ]on[ ]blacklist
83
+ |message[ ]was[ ]rejected[ ]for[ ]possible[ ]spam/virus[ ]content
79
84
  |messages[ ]from[ ][^ ]+[ ]temporarily[ ]deferred[ ]due[ ]to[ ]user[ ]complaints # Yahoo!
80
85
  |no[ ](?:
81
86
  access[ ]from[ ]mail[ ]server
@@ -89,6 +94,11 @@ module Sisimai
89
94
  |use[ ]the[ ]smtp[ ]server[ ]of[ ]your[ ]isp
90
95
  )
91
96
  |ptr[ ]record[ ]setup
97
+ |rejected[ ]because[ ]the[ ]sending[ ]mta[ ]or[ ]the[ ]sender[ ]has[ ]not[ ]passed[ ]validation
98
+ |rejected[ ]due[ ]to[ ](?:
99
+ a[ ]poor[ ]email[ ]reputation[ ]score
100
+ |the[ ]sending[ ]mta's[ ]poor[ ]reputation
101
+ )
92
102
  |rejecting[ ]open[ ]proxy # Sendmail(srvrsmtp.c)
93
103
  |reverse[ ]dns[ ](?:
94
104
  failed
@@ -120,6 +130,7 @@ module Sisimai
120
130
  |temporarily[ ]deferred[ ]due[ ]to[ ]unexpected[ ]volume[ ]or[ ]user[ ]complaints
121
131
  |the[ ](?:email|domain|ip)[ ][^ ]+[ ]is[ ]blacklisted
122
132
  |this[ ]system[ ]will[ ]not[ ]accept[ ]messages[ ]from[ ]servers[/]devices[ ]with[ ]no[ ]reverse[ ]dns
133
+ |to[ ]submit[ ]messages[ ]to[ ]this[ ]e-mail[ ]system[ ]has[ ]been[ ]rejected
123
134
  |too[ ]many[ ](?:
124
135
  spams[ ]from[ ]your[ ]ip # free.fr
125
136
  |unwanted[ ]messages[ ]have[ ]been[ ]sent[ ]from[ ]the[ ]following[ ]ip[ ]address[ ]above
@@ -141,8 +152,10 @@ module Sisimai
141
152
  |sending[ ]spam
142
153
  )
143
154
  |your[ ](?:
144
- access[ ]to[ ]submit[ ]messages[ ]to[ ]this[ ]e-mail[ ]system[ ]has[ ]been[ ]rejected
145
- |message[ ]was[ ]rejected[ ]for[ ]possible[ ]spam/virus[ ]content
155
+ email[ ]address[ ]has[ ]been[ ]blacklisted
156
+ |network[ ]is[ ]temporary[ ]blacklisted
157
+ |sender's[ ]ip[ ]address[ ]is[ ]listed[ ]at[ ][^ ]+[.]abuseat[.]org
158
+ |server[ ]requires[ ]confirmation
146
159
  )
147
160
  )
148
161
  }x
@@ -9,7 +9,10 @@ module Sisimai
9
9
  module ExceedLimit
10
10
  # Imported from p5-Sisimail/lib/Sisimai/Reason/ExceedLimit.pm
11
11
  class << self
12
- Index = ['message too large']
12
+ Index = [
13
+ 'message header size exceeds limit',
14
+ 'message too large',
15
+ ]
13
16
 
14
17
  def text; return 'exceedlimit'; end
15
18
  def description; return 'Email rejected due to an email exceeded the limit'; end
@@ -12,9 +12,11 @@ module Sisimai
12
12
  Index = [
13
13
  'connection timed out',
14
14
  'could not find a gateway for',
15
+ 'delivery attempts will continue to be',
15
16
  'delivery time expired',
16
17
  'failed to deliver to domain ',
17
18
  'giving up on',
19
+ 'have been failing for a long time',
18
20
  'has been delayed',
19
21
  'it has not been collected after',
20
22
  'message expired after sitting in queue for',