sisimai 5.5.0 → 5.7.0

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.
Files changed (113) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/rake-test.yml +0 -4
  3. data/ChangeLog.md +53 -0
  4. data/LICENSE +1 -1
  5. data/README-JA.md +26 -20
  6. data/README.md +30 -25
  7. data/lib/sisimai/address.rb +8 -31
  8. data/lib/sisimai/arf.rb +3 -5
  9. data/lib/sisimai/fact.rb +26 -36
  10. data/lib/sisimai/lhost/activehunter.rb +0 -2
  11. data/lib/sisimai/lhost/amazonses.rb +7 -9
  12. data/lib/sisimai/lhost/apachejames.rb +0 -1
  13. data/lib/sisimai/lhost/biglobe.rb +0 -16
  14. data/lib/sisimai/lhost/courier.rb +5 -4
  15. data/lib/sisimai/lhost/deutschetelekom.rb +120 -0
  16. data/lib/sisimai/lhost/domino.rb +0 -3
  17. data/lib/sisimai/lhost/dragonfly.rb +0 -27
  18. data/lib/sisimai/lhost/einsundeins.rb +1 -10
  19. data/lib/sisimai/lhost/exchange2003.rb +4 -4
  20. data/lib/sisimai/lhost/exchange2007.rb +5 -6
  21. data/lib/sisimai/lhost/exim.rb +35 -85
  22. data/lib/sisimai/lhost/ezweb.rb +12 -49
  23. data/lib/sisimai/lhost/fml.rb +4 -29
  24. data/lib/sisimai/lhost/gmail.rb +0 -23
  25. data/lib/sisimai/lhost/gmx.rb +7 -24
  26. data/lib/sisimai/lhost/googlegroups.rb +3 -3
  27. data/lib/sisimai/lhost/googleworkspace.rb +0 -4
  28. data/lib/sisimai/lhost/imailserver.rb +3 -9
  29. data/lib/sisimai/lhost/kddi.rb +6 -20
  30. data/lib/sisimai/lhost/mailfoundry.rb +0 -2
  31. data/lib/sisimai/lhost/mailmarshal.rb +1 -3
  32. data/lib/sisimai/lhost/messagingserver.rb +4 -15
  33. data/lib/sisimai/lhost/mfilter.rb +0 -1
  34. data/lib/sisimai/lhost/mimecast.rb +0 -1
  35. data/lib/sisimai/lhost/notes.rb +1 -2
  36. data/lib/sisimai/lhost/opensmtpd.rb +0 -40
  37. data/lib/sisimai/lhost/postfix.rb +10 -11
  38. data/lib/sisimai/lhost/qmail.rb +14 -81
  39. data/lib/sisimai/lhost/sendmail.rb +4 -4
  40. data/lib/sisimai/lhost/trendmicro.rb +3 -3
  41. data/lib/sisimai/lhost/v5sendmail.rb +0 -1
  42. data/lib/sisimai/lhost/verizon.rb +1 -2
  43. data/lib/sisimai/lhost/x1.rb +1 -2
  44. data/lib/sisimai/lhost/x2.rb +0 -2
  45. data/lib/sisimai/lhost/x3.rb +4 -9
  46. data/lib/sisimai/lhost/x6.rb +0 -1
  47. data/lib/sisimai/lhost/zoho.rb +0 -12
  48. data/lib/sisimai/lhost.rb +38 -19
  49. data/lib/sisimai/message.rb +3 -1
  50. data/lib/sisimai/order.rb +4 -1
  51. data/lib/sisimai/reason/authfailure.rb +9 -13
  52. data/lib/sisimai/reason/badreputation.rb +7 -7
  53. data/lib/sisimai/reason/blocked.rb +57 -83
  54. data/lib/sisimai/reason/contenterror.rb +16 -8
  55. data/lib/sisimai/reason/{mesgtoobig.rb → emailtoolarge.rb} +22 -25
  56. data/lib/sisimai/reason/expired.rb +27 -23
  57. data/lib/sisimai/reason/filtered.rb +13 -17
  58. data/lib/sisimai/reason/hasmoved.rb +2 -1
  59. data/lib/sisimai/reason/hostunknown.rb +25 -19
  60. data/lib/sisimai/reason/mailboxfull.rb +28 -49
  61. data/lib/sisimai/reason/networkerror.rb +28 -16
  62. data/lib/sisimai/reason/norelaying.rb +21 -20
  63. data/lib/sisimai/reason/notaccept.rb +13 -8
  64. data/lib/sisimai/reason/notcompliantrfc.rb +6 -9
  65. data/lib/sisimai/reason/policyviolation.rb +17 -26
  66. data/lib/sisimai/reason/ratelimited.rb +62 -0
  67. data/lib/sisimai/reason/rejected.rb +51 -59
  68. data/lib/sisimai/reason/requireptr.rb +13 -25
  69. data/lib/sisimai/reason/securityerror.rb +14 -19
  70. data/lib/sisimai/reason/spamdetected.rb +51 -101
  71. data/lib/sisimai/reason/suspend.rb +30 -24
  72. data/lib/sisimai/reason/syntaxerror.rb +1 -8
  73. data/lib/sisimai/reason/systemerror.rb +37 -23
  74. data/lib/sisimai/reason/systemfull.rb +1 -1
  75. data/lib/sisimai/reason/userunknown.rb +81 -112
  76. data/lib/sisimai/reason/virusdetected.rb +6 -8
  77. data/lib/sisimai/reason.rb +15 -15
  78. data/lib/sisimai/rfc1123.rb +1 -1
  79. data/lib/sisimai/rfc1894.rb +7 -6
  80. data/lib/sisimai/rfc2045.rb +2 -2
  81. data/lib/sisimai/rfc3464/thirdparty.rb +1 -1
  82. data/lib/sisimai/rfc3464.rb +10 -14
  83. data/lib/sisimai/rfc3834.rb +3 -4
  84. data/lib/sisimai/rfc791.rb +3 -38
  85. data/lib/sisimai/rhost/apple.rb +5 -5
  86. data/lib/sisimai/rhost/cloudflare.rb +2 -0
  87. data/lib/sisimai/rhost/cox.rb +22 -20
  88. data/lib/sisimai/rhost/facebook.rb +16 -16
  89. data/lib/sisimai/rhost/franceptt.rb +8 -3
  90. data/lib/sisimai/rhost/godaddy.rb +33 -15
  91. data/lib/sisimai/rhost/google.rb +63 -64
  92. data/lib/sisimai/rhost/iua.rb +1 -1
  93. data/lib/sisimai/rhost/messagelabs.rb +12 -12
  94. data/lib/sisimai/rhost/microsoft.rb +86 -86
  95. data/lib/sisimai/rhost/mimecast.rb +34 -34
  96. data/lib/sisimai/rhost/nttdocomo.rb +2 -2
  97. data/lib/sisimai/rhost/spectrum.rb +7 -7
  98. data/lib/sisimai/rhost/tencent.rb +9 -11
  99. data/lib/sisimai/rhost/yahooinc.rb +7 -8
  100. data/lib/sisimai/rhost.rb +1 -1
  101. data/lib/sisimai/smtp/command.rb +2 -0
  102. data/lib/sisimai/smtp/status.rb +73 -109
  103. data/lib/sisimai/string.rb +0 -27
  104. data/lib/sisimai/version.rb +1 -1
  105. data/set-of-emails/maildir/bsd/lhost-deutschetelekom-01.eml +66 -0
  106. data/set-of-emails/maildir/bsd/lhost-deutschetelekom-02.eml +68 -0
  107. data/set-of-emails/maildir/bsd/lhost-deutschetelekom-03.eml +50 -0
  108. data/set-of-emails/should-not-crash/p5-664-iomart-mail-filter.eml +258 -0
  109. data/set-of-emails/to-be-debugged-because/sisimai-cannot-parse-yet/.gitkeep +0 -0
  110. metadata +10 -6
  111. data/lib/sisimai/reason/exceedlimit.rb +0 -47
  112. data/lib/sisimai/reason/speeding.rb +0 -47
  113. data/lib/sisimai/reason/toomanyconn.rb +0 -59
@@ -8,22 +8,12 @@ module Sisimai::Lhost
8
8
  Indicators = Sisimai::Lhost.INDICATORS
9
9
  Boundaries = ["--------------------------------------------------", "Content-Type: message/rfc822"].freeze
10
10
  StartingOf = {message: ['The user(s) ', 'Your message ', 'Each of the following', '<']}.freeze
11
- Messagesof = {
12
- # notaccept: ['The following recipients did not receive this message:'],
13
- 'expired' => [
14
- # Your message was not delivered within 0 days and 1 hours.
15
- # Remote host is not responding.
16
- 'Your message was not delivered within ',
17
- ],
18
- 'mailboxfull' => ['The user(s) account is temporarily over quota'],
19
- 'onhold' => ['Each of the following recipients was rejected by a remote mail server'],
20
- 'suspend' => [
21
- # http://www.naruhodo-au.kddi.com/qa3429203.html
22
- # The recipient may be unpaid user...?
23
- 'The user(s) account is disabled.',
24
- 'The user(s) account is temporarily limited.',
25
- ],
26
- }.freeze
11
+ UnpaidUser = [
12
+ # http://www.naruhodo-au.kddi.com/qa3429203.html
13
+ # The recipient may be unpaid user...?
14
+ 'The user(s) account is disabled.',
15
+ 'The user(s) account is temporarily limited.',
16
+ ].freeze
27
17
 
28
18
  # @abstract Decodes the bounce message from au EZweb
29
19
  # @param [Hash] mhead Message headers of a bounce email
@@ -48,7 +38,6 @@ module Sisimai::Lhost
48
38
  bodyslices = emailparts[0].split("\n")
49
39
  readcursor = 0 # (Integer) Points the current cursor position
50
40
  recipients = 0 # (Integer) The number of 'Final-Recipient' header
51
- substrings = []; Messagesof.each_value { |a| substrings << a }; substrings.flatten!
52
41
 
53
42
  while e = bodyslices.shift do
54
43
  # Read error messages and delivery status lines from the head of the email to the previous
@@ -94,53 +83,27 @@ module Sisimai::Lhost
94
83
 
95
84
  else
96
85
  # Other error messages
86
+ # >>> RCPT TO:<******@ezweb.ne.jp>
87
+ # <<< 550 ...
97
88
  next if Sisimai::String.is_8bit(e)
98
- if e.include?(" >>> ")
99
- # >>> RCPT TO:<******@ezweb.ne.jp>
100
- v["command"] = Sisimai::SMTP::Command.find(e)
101
- v["diagnosis"] += " #{e}"
102
-
103
- elsif e.include?(" <<< ")
104
- # <<< 550 ...
105
- v["diagnosis"] += " #{e}"
106
-
107
- else
108
- # Check error message
109
- isincluded = false
110
- if substrings.any? { |a| e.include?(a) }
111
- # Check with regular expressions of each error
112
- v["diagnosis"] += " #{e}"
113
- isincluded = true
114
- end
115
- v["diagnosis"] += " #{e}" if isincluded
116
- end
89
+ v["command"] = Sisimai::SMTP::Command.find(e) if e.include?(" >>> ")
90
+ v["diagnosis"] += " #{e}"
117
91
  end
118
92
  end
119
93
  return nil if recipients == 0
120
94
 
121
95
  dscontents.each do |e|
122
96
  # Check each value of DeliveryMatter{}, try to detect the bounce reason.
123
- e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'])
97
+ e['diagnosis'] = e['diagnosis'].split.join(" ")
124
98
  e["command"] = Sisimai::SMTP::Command.find(e["diagnosis"]) if e["command"].empty?
125
99
 
126
100
  if mhead['x-spasign'].to_s == 'NG'
127
101
  # Content-Type: text/plain; ..., X-SPASIGN: NG (spamghetti, au by EZweb)
128
102
  # Filtered recipient returns message that include 'X-SPASIGN' header
129
103
  e['reason'] = 'filtered'
130
- e['toxic'] = true
131
104
  else
132
105
  # There is no X-SPASIGN header or the value of the header is not "NG"
133
- catch :FINDREASON do
134
- Messagesof.each_key do |r|
135
- # Try to match with each session error message
136
- Messagesof[r].each do |f|
137
- # Check each error message pattern
138
- next if e['diagnosis'].include?(f) == false
139
- e['reason'] = r
140
- throw :FINDREASON
141
- end
142
- end
143
- end
106
+ e['reason'] = "suspend" if UnpaidUser.any? { |a| e['diagnosis'].include?(a) }
144
107
  end
145
108
  next if e['reason'] != ""
146
109
  next if e['recipient'].end_with?('@ezweb.ne.jp', '@au.com')
@@ -22,21 +22,6 @@ module Sisimai::Lhost
22
22
  ],
23
23
  'securityerror' => ['Security Alert'],
24
24
  }.freeze
25
- ErrorTable = {
26
- 'rejected' => [
27
- ' header may cause mail loop',
28
- 'NOT MEMBER article from ',
29
- 'reject mail from ',
30
- 'reject spammers:',
31
- 'You are not a member of this mailing list',
32
- ],
33
- 'notcompliantrfc' => ['Duplicated Message-ID'],
34
- 'securityerror' => ['Security alert:'],
35
- 'systemerror' => [
36
- ' has detected a loop condition so that',
37
- 'Loop Back Warning:',
38
- ],
39
- }.freeze
40
25
 
41
26
  # @abstract Decodes the bounce message from fml mailling list server/manager
42
27
  # @param [Hash] mhead Message headers of a bounce email
@@ -84,23 +69,13 @@ module Sisimai::Lhost
84
69
  return nil if recipients == 0
85
70
 
86
71
  dscontents.each do |e|
87
- e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'])
88
- ErrorTable.each_key do |f|
89
- # Try to match with error messages defined in ErrorTable
90
- next if ErrorTable[f].none? { |a| e['diagnosis'].include?(a) }
72
+ # Error messages in the message body did not matched
73
+ ErrorTitle.each_key do |f|
74
+ # Try to match with the Subject string
75
+ next if ErrorTitle[f].none? { |a| mhead["subject"].include?(a) }
91
76
  e['reason'] = f
92
77
  break
93
78
  end
94
-
95
- if e['reason'].nil?
96
- # Error messages in the message body did not matched
97
- ErrorTitle.each_key do |f|
98
- # Try to match with the Subject string
99
- next if ErrorTitle[f].none? { |a| mhead["subject"].include?(a) }
100
- e['reason'] = f
101
- break
102
- end
103
- end
104
79
  end
105
80
 
106
81
  return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
@@ -11,17 +11,6 @@ module Sisimai::Lhost
11
11
  message: ['Delivery to the following recipient'],
12
12
  error: ['The error that the other server returned was:'],
13
13
  }.freeze
14
- MessagesOf = {
15
- 'expired' => [
16
- 'DNS Error: Could not contact DNS servers',
17
- 'Delivery to the following recipient has been delayed',
18
- 'The recipient server did not accept our requests to connect',
19
- ],
20
- 'hostunknown' => [
21
- 'DNS Error: Domain name not found',
22
- 'DNS Error: DNS server returned answer with no data',
23
- ],
24
- }.freeze
25
14
  StateTable = {
26
15
  # Technical details of permanent failure:
27
16
  # Google tried to deliver your message, but it was rejected by the recipient domain.
@@ -205,8 +194,6 @@ module Sisimai::Lhost
205
194
  require 'sisimai/string'
206
195
  require 'sisimai/rfc1123'
207
196
  dscontents.each do |e|
208
- e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'])
209
-
210
197
  if Sisimai::String.aligned(e['diagnosis'], [' by ', '. [', ']. '])
211
198
  # Get the value of remote host
212
199
  # Google tried to deliver your message, but it was rejected by the server for the recipient
@@ -232,16 +219,6 @@ module Sisimai::Lhost
232
219
  e['command'] = StateTable[cu]['command']
233
220
  break
234
221
  end
235
-
236
- if e['reason'].empty?
237
- # There is no no state code in the error message
238
- MessagesOf.each_key do |r|
239
- # Verify each regular expression of session errors
240
- next if MessagesOf[r].none? { |a| e['diagnosis'].include?(a) }
241
- e['reason'] = r
242
- break
243
- end
244
- end
245
222
  next if e['reason'].empty?
246
223
 
247
224
  # Set pseudo status code
@@ -8,7 +8,6 @@ module Sisimai::Lhost
8
8
  Indicators = Sisimai::Lhost.INDICATORS
9
9
  Boundaries = ['--- The header of the original message is following. ---'].freeze
10
10
  StartingOf = {message: ['This message was created automatically by mail delivery software']}.freeze
11
- MessagesOf = {'expired' => ['delivery retry timeout exceeded']}.freeze
12
11
 
13
12
  # @abstract Decodes the bounce message from GMX
14
13
  # @param [Hash] mhead Message headers of a bounce email
@@ -65,33 +64,17 @@ module Sisimai::Lhost
65
64
  end
66
65
  v['recipient'] = Sisimai::Address.s3s4(e)
67
66
  recipients += 1
68
-
69
- elsif e.start_with?('SMTP error ')
70
- # SMTP error from remote server after RCPT command:
71
- v['command'] = Sisimai::SMTP::Command.find(e)
72
-
73
- elsif e.start_with?('host:')
74
- # host: mx.example.jp
75
- v['rhost'] = e[6, e.size]
76
67
  else
77
- # Get error messages
78
- next if e.empty?
79
- v['diagnosis'] += "#{e }"
68
+ # - SMTP error from remote server after RCPT command:
69
+ # - host: mx.example.jp
70
+ case
71
+ when e.start_with?('SMTP error ') then v['command'] = Sisimai::SMTP::Command.find(e)
72
+ when e.start_with?('host:') then v['rhost'] = e[6, e.size]
73
+ else v['diagnosis'] += "#{e }" if e.empty? == false
74
+ end
80
75
  end
81
76
  end
82
77
  return nil if recipients == 0
83
-
84
- dscontents.each do |e|
85
- e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'].tr("\n", ' '))
86
-
87
- MessagesOf.each_key do |r|
88
- # Verify each regular expression of session errors
89
- next if MessagesOf[r].none? { |a| e['diagnosis'].include?(a) }
90
- e['reason'] = r
91
- break
92
- end
93
- end
94
-
95
78
  return {"ds" => dscontents, "rfc822" => emailparts[1]}
96
79
  end
97
80
  def description; return 'GMX: https://www.gmx.net'; end
@@ -13,10 +13,10 @@ module Sisimai::Lhost
13
13
  # @return [Nil] it failed to decode or the arguments are missing
14
14
  # @since v4.25.6
15
15
  def inquire(mhead, mbody)
16
- return nil if mbody.include?("Google Groups") == false
16
+ return nil if mbody.include?("Google Group") == false
17
17
  return nil if mhead['from'].end_with?('<mailer-daemon@googlemail.com>') == false
18
18
  return nil if mhead['subject'].start_with?('Delivery Status Notification') == false
19
- return nil if mhead['x-failed-recipients'].nil? || mhead['x-google-smtp-source'].nil?
19
+ return nil if mhead['x-failed-recipients'].nil?
20
20
 
21
21
  # Hello kijitora@libsisimai.org,
22
22
  #
@@ -46,7 +46,7 @@ module Sisimai::Lhost
46
46
  entiremesg = emailparts[0].split(/\n\n/, 5).slice(0, 4).join(' ').tr("\n", ' ');
47
47
  receivedby = mhead['received'] || []
48
48
  recordwide = {
49
- 'diagnosis' => Sisimai::String.sweep(entiremesg),
49
+ 'diagnosis' => entiremesg,
50
50
  'reason' => 'onhold',
51
51
  'rhost' => Sisimai::RFC5322.received(receivedby[0])[1],
52
52
  }
@@ -15,8 +15,6 @@ module Sisimai::Lhost
15
15
  }.freeze
16
16
  MessagesOf = {
17
17
  "userunknown" => ["because the address couldn't be found. Check for typos or unnecessary spaces and try again."],
18
- "notaccept" => ["Null MX"],
19
- "networkerror" => [" had no relevant answers.", " responded with code NXDOMAIN"],
20
18
  }.freeze
21
19
 
22
20
  # @abstract Decodes the bounce message from Google Workspace
@@ -73,8 +71,6 @@ module Sisimai::Lhost
73
71
 
74
72
  dscontents[0]["diagnosis"] = entiremesg
75
73
  dscontents.each do |e|
76
- # Tidy up the error message in e["diagnosis"], Try to detect the bounce reason.
77
- e["diagnosis"] = Sisimai::String.sweep(e["diagnosis"])
78
74
  MessagesOf.each_key do |r|
79
75
  # Guess an reason of the bounce
80
76
  next if MessagesOf[r].none? { |a| e["diagnosis"].include?(a) }
@@ -9,12 +9,8 @@ module Sisimai::Lhost
9
9
  Boundaries = ['Original message follows.'].freeze
10
10
  StartingOf = {error: ['Body of message generated response:']}.freeze
11
11
  MessagesOf = {
12
- 'hostunknown' => ['Unknown host'],
13
- 'userunknown' => ['Unknown user', 'Invalid final delivery userid'],
14
- 'mailboxfull' => ['User mailbox exceeds allowed size'],
15
- 'virusdetected' => ['Requested action not taken: virus detected'],
16
- 'spamdetected' => ['Blacklisted URL in message'],
17
- 'expired' => ['Delivery failed '],
12
+ 'userunknown' => ['Unknown user', 'Invalid final delivery userid'],
13
+ 'expired' => ['Delivery failed '],
18
14
  }.freeze
19
15
 
20
16
  # @abstract Decodes the bounce message from Progress iMail Server
@@ -72,11 +68,9 @@ module Sisimai::Lhost
72
68
  else
73
69
  e['alterrors']
74
70
  end
75
- e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'])
76
71
  e.delete('alterrors')
77
72
  end
78
- e['diagnosis'] = Sisimai::String.sweep(e['diagnosis']) || ''
79
- e['command'] = Sisimai::SMTP::Command.find(e['diagnosis'])
73
+ e['command'] = Sisimai::SMTP::Command.find(e['diagnosis'])
80
74
 
81
75
  MessagesOf.each_key do |r|
82
76
  # Verify each regular expression of session errors
@@ -8,11 +8,6 @@ module Sisimai::Lhost
8
8
  Indicators = Sisimai::Lhost.INDICATORS
9
9
  Boundaries = ['Content-Type: message/rfc822'].freeze
10
10
  StartingOf = {message: ['Your mail sent on:', 'Your mail attempted to be delivered on:']}.freeze
11
- MessagesOf = {
12
- 'mailboxfull' => ['As their mailbox is full'],
13
- 'norelaying' => ['Due to the following SMTP relay error'],
14
- 'hostunknown' => ['As the remote domain doesnt exist'],
15
- }.freeze
16
11
 
17
12
  # @abstract Decodes the bounce message from au by KDDI
18
13
  # @param [Hash] mhead Message headers of a bounce email
@@ -45,7 +40,8 @@ module Sisimai::Lhost
45
40
  next if (readcursor & Indicators[:deliverystatus]) == 0 || e.empty?
46
41
 
47
42
  v = dscontents[-1]
48
- if e.include?(' Could not be delivered to: <')
43
+ case
44
+ when e.include?(' Could not be delivered to: <')
49
45
  # Your mail sent on: Thu, 29 Apr 2010 11:04:47 +0900
50
46
  # Could not be delivered to: <******@**.***.**>
51
47
  # As their mailbox is full.
@@ -59,7 +55,7 @@ module Sisimai::Lhost
59
55
  v['recipient'] = r
60
56
  recipients += 1
61
57
 
62
- elsif e.include?('Your mail sent on: ')
58
+ when e.include?('Your mail sent on: ')
63
59
  # Your mail sent on: Thu, 29 Apr 2010 11:04:47 +0900
64
60
  v['date'] = e[19, e.size]
65
61
  else
@@ -71,7 +67,6 @@ module Sisimai::Lhost
71
67
 
72
68
  require 'sisimai/smtp/command'
73
69
  dscontents.each do |e|
74
- e['diagnosis'] = Sisimai::String.sweep(e['diagnosis']) || ''
75
70
  e['command'] = Sisimai::SMTP::Command.find(e['diagnosis'])
76
71
 
77
72
  if mhead['x-spasign'].to_s == 'NG'
@@ -79,18 +74,9 @@ module Sisimai::Lhost
79
74
  # Filtered recipient returns message that include 'X-SPASIGN' header
80
75
  e['reason'] = 'filtered'
81
76
  else
82
- if e['command'] == 'RCPT'
83
- # set "userunknown" when the remote server rejected after RCPT command.
84
- e['reason'] = 'userunknown'
85
- else
86
- # SMTP command is not RCPT
87
- MessagesOf.each_key do |r|
88
- # Verify each regular expression of session errors
89
- next if MessagesOf[r].none? { |a| e['diagnosis'].include?(a) }
90
- e['reason'] = r
91
- break
92
- end
93
- end
77
+ # There is no X-SPASIGN: header in the bounce message
78
+ # set "userunknown" when the remote server rejected after RCPT command.
79
+ e['reason'] = 'userunknown' if e['command'] == 'RCPT'
94
80
  end
95
81
  end
96
82
 
@@ -65,8 +65,6 @@ module Sisimai::Lhost
65
65
  end
66
66
  end
67
67
  return nil if recipients == 0
68
-
69
- dscontents.each { |e| e['diagnosis'] = Sisimai::String.sweep(e['diagnosis']) }
70
68
  return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
71
69
  end
72
70
  def description; return 'MailFoundry'; end
@@ -103,15 +103,13 @@ module Sisimai::Lhost
103
103
  p1 = e.index(' From:') || e.index(' Subject:')
104
104
  p2 = e.index(':')
105
105
  cf = e[p1 + 1, p2 - p1 - 1]
106
- cv = Sisimai::String.sweep(e[p2 + 1, e.size])
106
+ cv = e[p2 + 1, e.size]
107
107
  emailparts[1] += sprintf("%s: %s\n", cf, cv)
108
108
  end
109
109
  end
110
110
  end
111
111
  end
112
112
  return nil if recipients == 0
113
-
114
- dscontents.each { |e| e['diagnosis'] = Sisimai::String.sweep(e['diagnosis']) }
115
113
  return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
116
114
  end
117
115
  def description; return 'Trustwave Secure Email Gateway'; end
@@ -9,7 +9,6 @@ module Sisimai::Lhost
9
9
  Indicators = Sisimai::Lhost.INDICATORS
10
10
  Boundaries = ['Content-Type: message/rfc822', 'Return-path: '].freeze
11
11
  StartingOf = {message: ['This report relates to a message you sent with the following header fields:']}.freeze
12
- MessagesOf = {'hostunknown' => ['Illegal host/domain name found']}.freeze
13
12
 
14
13
  # @abstract Decodes the bounce message from MessagingServer
15
14
  # @param [Hash] mhead Message headers of a bounce email
@@ -115,18 +114,19 @@ module Sisimai::Lhost
115
114
  # (6jo.example.jp ESMTP SENDMAIL-VM)
116
115
  # Diagnostic-code: smtp;550 5.1.1 <kijitora@example.jp>... User Unknown
117
116
  #
118
- if e.start_with?('Status: ')
117
+ case
118
+ when e.start_with?('Status: ')
119
119
  # Status: 5.1.1 (Remote SMTP server has rejected address)
120
120
  p1 = e.index(':')
121
121
  p2 = e.index('('); next if p2.nil?
122
122
  v['status'] = e[p1 + 2, p2 - p1 - 3]
123
123
  v['diagnosis'] = e[p2 + 1, e[e.index(')') - p2 - 1]] if v["diagnosis"].empty?
124
124
 
125
- elsif e.start_with?('Arrival-Date: ')
125
+ when e.start_with?('Arrival-Date: ')
126
126
  # Arrival-date: Thu, 29 Apr 2014 23:34:45 +0000 (GMT)
127
127
  v['date'] = e[e.index(':') + 2, e.size] if v["date"].empty?
128
128
 
129
- elsif e.start_with?('Reporting-MTA: ')
129
+ when e.start_with?('Reporting-MTA: ')
130
130
  # Reporting-MTA: dns;mr21p30im-asmtp004.me.com (tcp-daemon)
131
131
  localhost = e[e.index(';') + 1, e.size]
132
132
  v['lhost'] = localhost if v["lhost"].empty?
@@ -135,17 +135,6 @@ module Sisimai::Lhost
135
135
  end
136
136
  end
137
137
  return nil if recipients == 0
138
-
139
- dscontents.each do |e|
140
- e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'])
141
- MessagesOf.each_key do |r|
142
- # Verify each regular expression of session errors
143
- next if MessagesOf[r].none? { |a| e['diagnosis'].include?(a) }
144
- e['reason'] = r
145
- break
146
- end
147
- end
148
-
149
138
  return {"ds" => dscontents, "rfc822" => emailparts[1]}
150
139
  end
151
140
  def description; return 'Oracle Communications Messaging Server'; end
@@ -98,7 +98,6 @@ module Sisimai::Lhost
98
98
  return nil if recipients == 0
99
99
 
100
100
  dscontents.each do |e|
101
- e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'])
102
101
  e['agent'] = 'mFILTER'
103
102
 
104
103
  # Get localhost and remote host name from Received header.
@@ -93,7 +93,6 @@ module Sisimai::Lhost
93
93
  dscontents.each do |e|
94
94
  # Set default values if each value is empty.
95
95
  permessage.each_key { |a| e[a] ||= permessage[a] || '' }
96
- e['diagnosis'] = Sisimai::String.sweep(e['diagnosis']) || ''
97
96
  end
98
97
 
99
98
  return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
@@ -13,7 +13,6 @@ module Sisimai::Lhost
13
13
  'User not listed in public Name & Address Book',
14
14
  'ディレクトリのリストにありません',
15
15
  ],
16
- 'networkerror' => ['Message has exceeded maximum hop count'],
17
16
  }.freeze
18
17
 
19
18
  # @abstract Decodes the bounce messages from HCL Notes (Formerly IBM Notes (Formerly Lotus Notes))
@@ -101,7 +100,7 @@ module Sisimai::Lhost
101
100
  return nil if recipients == 0
102
101
 
103
102
  dscontents.each do |e|
104
- e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'])
103
+ e['diagnosis'] = e['diagnosis'].split.join(" ")
105
104
  e['recipient'] = Sisimai::Address.s3s4(e['recipient'])
106
105
 
107
106
  MessagesOf.each_key do |r|
@@ -35,36 +35,6 @@ module Sisimai::Lhost
35
35
  # bounce.c/339:
36
36
  message: [' This is the MAILER-DAEMON, please DO NOT REPLY to this '],
37
37
  }.freeze
38
- MessagesOf = {
39
- # smtpd/queue.c:221| envelope_set_errormsg(&evp, "Envelope expired");
40
- 'expired' => ['Envelope expired'],
41
- # smtpd/mta.c:976| relay->failstr = "Invalid domain name";
42
- # smtpd/mta.c:980| relay->failstr = "Domain does not exist";
43
- 'hostunknown' => [
44
- 'Invalid domain name',
45
- 'Domain does not exist',
46
- ],
47
- # smtp/mta.c:1085| relay->failstr = "Destination seem to reject all mails";
48
- 'notaccept' => [
49
- 'Destination seem to reject all mails',
50
- 'No MX found for domain',
51
- 'No MX found for destination',
52
- ],
53
- # smtpd/mta.c:972| relay->failstr = "Temporary failure in MX lookup";
54
- 'networkerror' => [
55
- 'Address family mismatch on destination MXs',
56
- 'All routes to destination blocked',
57
- 'bad DNS lookup error code',
58
- 'Could not retrieve source address',
59
- 'Loop detected',
60
- 'Network error on destination MXs',
61
- 'No valid route to remote MX',
62
- 'No valid route to destination',
63
- 'Temporary failure in MX lookup',
64
- ],
65
- # smtpd/mta.c:1013| relay->failstr = "Could not retrieve credentials";
66
- 'securityerror' => ['Could not retrieve credentials'],
67
- }.freeze
68
38
 
69
39
  # @abstract Decodes the bounce message from OpenSMTPD
70
40
  # @param [Hash] mhead Message headers of a bounce email
@@ -117,16 +87,6 @@ module Sisimai::Lhost
117
87
  end
118
88
  end
119
89
  return nil if recipients == 0
120
-
121
- dscontents.each do |e|
122
- e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'])
123
- MessagesOf.each_key do |r|
124
- # Verify each regular expression of session errors
125
- next if MessagesOf[r].none? { |a| e['diagnosis'].include?(a) }
126
- e['reason'] = r
127
- break
128
- end
129
- end
130
90
  return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
131
91
  end
132
92
  def description; return 'OpenSMTPD'; end
@@ -63,15 +63,14 @@ module Sisimai::Lhost
63
63
  v ||= dscontents[-1]
64
64
  p = e['response']
65
65
 
66
- if e['command'] == 'HELO' || e['command'] == 'EHLO'
67
- # Use the argument of EHLO/HELO command as a value of "lhost"
68
- v['lhost'] = e['argument']
69
-
70
- elsif e['command'] == 'MAIL'
66
+ case e["command"]
67
+ # Use the argument of EHLO/HELO command as a value of "lhost"
68
+ when "HELO", "EHLO" then v['lhost'] = e['argument']
69
+ when "MAIL"
71
70
  # Set the argument of "MAIL" command to pseudo To: header of the original message
72
71
  emailparts[1] += sprintf("To: %s\n", e['argument']) if emailparts[1].size == 0
73
72
 
74
- elsif e['command'] == 'RCPT'
73
+ when "RCPT"
75
74
  # RCPT TO: <...>
76
75
  if v["recipient"] != ""
77
76
  # There are multiple recipient addresses in the transcript of session
@@ -110,7 +109,8 @@ module Sisimai::Lhost
110
109
  next unless o = Sisimai::RFC1894.field(e)
111
110
  v = dscontents[-1]
112
111
 
113
- if o[3] == 'addr'
112
+ case o[3]
113
+ when "addr"
114
114
  # Final-Recipient: rfc822; kijitora@example.jp
115
115
  # X-Actual-Recipient: rfc822; kijitora@example.co.jp
116
116
  if Sisimai::Address.is_emailaddress(o[2])
@@ -130,7 +130,7 @@ module Sisimai::Lhost
130
130
  v['alias'] = o[2]
131
131
  end
132
132
  end
133
- elsif o[3] == 'code'
133
+ when "code"
134
134
  # Diagnostic-Code: SMTP; 550 5.1.1 <userunknown@example.jp>... User Unknown
135
135
  v['spec'] = o[1]
136
136
  v['spec'] = 'SMTP' if v['spec'].upcase == 'X-POSTFIX'
@@ -154,7 +154,7 @@ module Sisimai::Lhost
154
154
  # 5.1.1 <userunknown@example.co.jp>... User Unknown (in reply to RCPT TO command)
155
155
  if readslices[-2].start_with?('Diagnostic-Code:') && e.include?(' ')
156
156
  # Continued line of the value of Diagnostic-Code header
157
- v['diagnosis'] += " #{Sisimai::String.sweep(e)}"
157
+ v['diagnosis'] += " " + e.split.join(" ")
158
158
  readslices[-1] = "Diagnostic-Code: #{e}"
159
159
 
160
160
  elsif Sisimai::String.aligned(e, ['X-Postfix-Sender:', 'rfc822;', '@'])
@@ -238,7 +238,7 @@ module Sisimai::Lhost
238
238
 
239
239
  if anotherset['diagnosis']
240
240
  # Copy alternative error message
241
- anotherset['diagnosis'] = Sisimai::String.sweep(anotherset['diagnosis'])
241
+ anotherset['diagnosis'] = anotherset['diagnosis'].split.join(" ")
242
242
  e['diagnosis'] = anotherset['diagnosis'] if e['diagnosis'].nil? || e['diagnosis'].empty?
243
243
 
244
244
  if e['diagnosis'] =~ /\A\d+\z/
@@ -277,7 +277,6 @@ module Sisimai::Lhost
277
277
  end
278
278
  end
279
279
 
280
- e['diagnosis'] = Sisimai::String.sweep(e['diagnosis']) || ''
281
280
  e['command'] = commandset.shift || Sisimai::SMTP::Command.find(e['diagnosis'])
282
281
  e['command'] = 'HELO' if e["command"].empty? && e['diagnosis'].include?('refused to talk to me:')
283
282
  e['spec'] = 'SMTP' if e["spec"].empty? && Sisimai::String.aligned(e['diagnosis'], ['host ', ' said:'])