sisimai 5.6.0 → 5.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (130) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/rake-test.yml +0 -4
  3. data/ChangeLog.md +47 -0
  4. data/README-JA.md +19 -16
  5. data/README.md +23 -21
  6. data/lib/sisimai/address.rb +8 -31
  7. data/lib/sisimai/arf.rb +5 -6
  8. data/lib/sisimai/eb.rb +116 -0
  9. data/lib/sisimai/fact.rb +33 -51
  10. data/lib/sisimai/lda.rb +20 -18
  11. data/lib/sisimai/lhost/activehunter.rb +0 -2
  12. data/lib/sisimai/lhost/amazonses.rb +17 -18
  13. data/lib/sisimai/lhost/apachejames.rb +0 -1
  14. data/lib/sisimai/lhost/biglobe.rb +0 -16
  15. data/lib/sisimai/lhost/courier.rb +9 -7
  16. data/lib/sisimai/lhost/deutschetelekom.rb +120 -0
  17. data/lib/sisimai/lhost/domino.rb +2 -4
  18. data/lib/sisimai/lhost/dragonfly.rb +0 -27
  19. data/lib/sisimai/lhost/einsundeins.rb +4 -12
  20. data/lib/sisimai/lhost/exchange2003.rb +12 -11
  21. data/lib/sisimai/lhost/exchange2007.rb +17 -17
  22. data/lib/sisimai/lhost/exim.rb +34 -81
  23. data/lib/sisimai/lhost/ezweb.rb +15 -51
  24. data/lib/sisimai/lhost/fml.rb +8 -32
  25. data/lib/sisimai/lhost/gmail.rb +10 -32
  26. data/lib/sisimai/lhost/gmx.rb +7 -24
  27. data/lib/sisimai/lhost/googlegroups.rb +6 -5
  28. data/lib/sisimai/lhost/googleworkspace.rb +2 -5
  29. data/lib/sisimai/lhost/imailserver.rb +4 -9
  30. data/lib/sisimai/lhost/kddi.rb +8 -21
  31. data/lib/sisimai/lhost/mailfoundry.rb +0 -2
  32. data/lib/sisimai/lhost/mailmarshal.rb +1 -3
  33. data/lib/sisimai/lhost/messagingserver.rb +4 -15
  34. data/lib/sisimai/lhost/mfilter.rb +0 -1
  35. data/lib/sisimai/lhost/mimecast.rb +0 -1
  36. data/lib/sisimai/lhost/notes.rb +3 -3
  37. data/lib/sisimai/lhost/opensmtpd.rb +0 -40
  38. data/lib/sisimai/lhost/postfix.rb +14 -14
  39. data/lib/sisimai/lhost/qmail.rb +23 -89
  40. data/lib/sisimai/lhost/sendmail.rb +8 -7
  41. data/lib/sisimai/lhost/trendmicro.rb +5 -4
  42. data/lib/sisimai/lhost/v5sendmail.rb +2 -2
  43. data/lib/sisimai/lhost/verizon.rb +4 -4
  44. data/lib/sisimai/lhost/x1.rb +1 -2
  45. data/lib/sisimai/lhost/x2.rb +0 -2
  46. data/lib/sisimai/lhost/x3.rb +4 -9
  47. data/lib/sisimai/lhost/x6.rb +0 -1
  48. data/lib/sisimai/lhost/zoho.rb +0 -12
  49. data/lib/sisimai/lhost.rb +38 -19
  50. data/lib/sisimai/message.rb +1 -1
  51. data/lib/sisimai/order.rb +4 -1
  52. data/lib/sisimai/reason/authfailure.rb +8 -7
  53. data/lib/sisimai/reason/badreputation.rb +5 -4
  54. data/lib/sisimai/reason/blocked.rb +6 -5
  55. data/lib/sisimai/reason/contenterror.rb +8 -5
  56. data/lib/sisimai/reason/delivered.rb +3 -2
  57. data/lib/sisimai/reason/emailtoolarge.rb +7 -6
  58. data/lib/sisimai/reason/expired.rb +16 -4
  59. data/lib/sisimai/reason/failedstarttls.rb +5 -3
  60. data/lib/sisimai/reason/feedback.rb +2 -1
  61. data/lib/sisimai/reason/filtered.rb +9 -8
  62. data/lib/sisimai/reason/hasmoved.rb +5 -4
  63. data/lib/sisimai/reason/hostunknown.rb +14 -4
  64. data/lib/sisimai/reason/mailboxfull.rb +10 -8
  65. data/lib/sisimai/reason/mailererror.rb +3 -2
  66. data/lib/sisimai/reason/networkerror.rb +16 -3
  67. data/lib/sisimai/reason/norelaying.rb +8 -6
  68. data/lib/sisimai/reason/notaccept.rb +15 -7
  69. data/lib/sisimai/reason/notcompliantrfc.rb +5 -3
  70. data/lib/sisimai/reason/onhold.rb +8 -7
  71. data/lib/sisimai/reason/policyviolation.rb +11 -5
  72. data/lib/sisimai/reason/ratelimited.rb +5 -4
  73. data/lib/sisimai/reason/rejected.rb +24 -14
  74. data/lib/sisimai/reason/requireptr.rb +5 -4
  75. data/lib/sisimai/reason/securityerror.rb +5 -3
  76. data/lib/sisimai/reason/spamdetected.rb +6 -5
  77. data/lib/sisimai/reason/suppressed.rb +4 -3
  78. data/lib/sisimai/reason/suspend.rb +8 -3
  79. data/lib/sisimai/reason/syntaxerror.rb +5 -11
  80. data/lib/sisimai/reason/systemerror.rb +21 -2
  81. data/lib/sisimai/reason/systemfull.rb +4 -3
  82. data/lib/sisimai/reason/undefined.rb +2 -1
  83. data/lib/sisimai/reason/userunknown.rb +15 -9
  84. data/lib/sisimai/reason/vacation.rb +2 -1
  85. data/lib/sisimai/reason/virusdetected.rb +6 -5
  86. data/lib/sisimai/reason.rb +47 -42
  87. data/lib/sisimai/rfc1123.rb +1 -1
  88. data/lib/sisimai/rfc1894.rb +15 -8
  89. data/lib/sisimai/rfc2045.rb +8 -5
  90. data/lib/sisimai/rfc3464/thirdparty.rb +11 -10
  91. data/lib/sisimai/rfc3464.rb +10 -14
  92. data/lib/sisimai/rfc3834.rb +6 -5
  93. data/lib/sisimai/rfc791.rb +3 -38
  94. data/lib/sisimai/rhost/aol.rb +3 -2
  95. data/lib/sisimai/rhost/apple.rb +12 -11
  96. data/lib/sisimai/rhost/cloudflare.rb +3 -2
  97. data/lib/sisimai/rhost/cox.rb +38 -37
  98. data/lib/sisimai/rhost/facebook.rb +17 -16
  99. data/lib/sisimai/rhost/franceptt.rb +39 -38
  100. data/lib/sisimai/rhost/godaddy.rb +35 -34
  101. data/lib/sisimai/rhost/google.rb +22 -21
  102. data/lib/sisimai/rhost/gsuite.rb +8 -7
  103. data/lib/sisimai/rhost/iua.rb +11 -10
  104. data/lib/sisimai/rhost/kddi.rb +3 -2
  105. data/lib/sisimai/rhost/messagelabs.rb +13 -12
  106. data/lib/sisimai/rhost/microsoft.rb +37 -32
  107. data/lib/sisimai/rhost/mimecast.rb +18 -17
  108. data/lib/sisimai/rhost/nttdocomo.rb +10 -9
  109. data/lib/sisimai/rhost/outlook.rb +3 -2
  110. data/lib/sisimai/rhost/spectrum.rb +19 -18
  111. data/lib/sisimai/rhost/tencent.rb +10 -9
  112. data/lib/sisimai/rhost/yahooinc.rb +11 -10
  113. data/lib/sisimai/rhost/zoho.rb +8 -7
  114. data/lib/sisimai/rhost.rb +1 -1
  115. data/lib/sisimai/smtp/command.rb +13 -8
  116. data/lib/sisimai/smtp/failure.rb +9 -8
  117. data/lib/sisimai/smtp/reply.rb +23 -22
  118. data/lib/sisimai/smtp/status.rb +164 -159
  119. data/lib/sisimai/smtp/transcript.rb +3 -2
  120. data/lib/sisimai/string.rb +0 -12
  121. data/lib/sisimai/version.rb +1 -1
  122. data/lib/sisimai.rb +2 -1
  123. data/set-of-emails/maildir/bsd/lhost-deutschetelekom-01.eml +66 -0
  124. data/set-of-emails/maildir/bsd/lhost-deutschetelekom-02.eml +68 -0
  125. data/set-of-emails/maildir/bsd/lhost-deutschetelekom-03.eml +50 -0
  126. data/set-of-emails/maildir/bsd/lhost-postfix-81.eml +130 -0
  127. data/set-of-emails/should-not-crash/go-423-deeply-nested-mime-parts.eml +20050 -0
  128. data/set-of-emails/should-not-crash/p5-664-iomart-mail-filter.eml +258 -0
  129. data/set-of-emails/to-be-debugged-because/sisimai-cannot-parse-yet/.gitkeep +0 -0
  130. metadata +11 -2
@@ -3,6 +3,7 @@ module Sisimai::Lhost
3
3
  # Methods in the module are called from only Sisimai::Message.
4
4
  module Gmail
5
5
  class << self
6
+ require 'sisimai/eb'
6
7
  require 'sisimai/lhost'
7
8
 
8
9
  Indicators = Sisimai::Lhost.INDICATORS
@@ -11,24 +12,13 @@ module Sisimai::Lhost
11
12
  message: ['Delivery to the following recipient'],
12
13
  error: ['The error that the other server returned was:'],
13
14
  }.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
15
  StateTable = {
26
16
  # Technical details of permanent failure:
27
17
  # Google tried to deliver your message, but it was rejected by the recipient domain.
28
18
  # We recommend contacting the other email provider for further information about the
29
19
  # cause of this error. The error that the other server returned was:
30
20
  # 500 Remote server does not support TLS (state 6).
31
- '6' => { 'command' => 'MAIL', 'reason' => 'failedstarttls' },
21
+ '6' => { 'command' => Sisimai::Eb::CeMAIL, 'reason' => Sisimai::Eb::ReTTLS },
32
22
 
33
23
  # https://www.google.td/support/forum/p/gmail/thread?tid=08a60ebf5db24f7b&hl=en
34
24
  # Technical details of permanent failure:
@@ -36,7 +26,7 @@ module Sisimai::Lhost
36
26
  # We recommend contacting the other email provider for further information about the
37
27
  # cause of this error. The error that the other server returned was:
38
28
  # 535 SMTP AUTH failed with the remote server. (state 8).
39
- '8' => { 'command' => 'AUTH', 'reason' => 'systemerror' },
29
+ '8' => { 'command' => Sisimai::Eb::CeAUTH, 'reason' => Sisimai::Eb::RePROC },
40
30
 
41
31
  # https://www.google.co.nz/support/forum/p/gmail/thread?tid=45208164dbca9d24&hl=en
42
32
  # Technical details of temporary failure:
@@ -44,7 +34,7 @@ module Sisimai::Lhost
44
34
  # We recommend contacting the other email provider for further information about the
45
35
  # cause of this error. The error that the other server returned was:
46
36
  # 454 454 TLS missing certificate: error:0200100D:system library:fopen:Permission denied (#4.3.0) (state 9).
47
- '9' => { 'command' => 'AUTH', 'reason' => 'failedstarttls' },
37
+ '9' => { 'command' => Sisimai::Eb::CeAUTH, 'reason' => Sisimai::Eb::ReTTLS },
48
38
 
49
39
  # https://www.google.com/support/forum/p/gmail/thread?tid=5cfab8c76ec88638&hl=en
50
40
  # Technical details of permanent failure:
@@ -52,14 +42,14 @@ module Sisimai::Lhost
52
42
  # We recommend contacting the other email provider for further information about the
53
43
  # cause of this error. The error that the other server returned was:
54
44
  # 500 Remote server does not support SMTP Authenticated Relay (state 12).
55
- '12' => { 'command' => 'AUTH', 'reason' => 'norelaying' },
45
+ '12' => { 'command' => Sisimai::Eb::CeAUTH, 'reason' => Sisimai::Eb::RePASS },
56
46
 
57
47
  # Technical details of permanent failure:
58
48
  # Google tried to deliver your message, but it was rejected by the recipient domain.
59
49
  # We recommend contacting the other email provider for further information about the
60
50
  # cause of this error. The error that the other server returned was:
61
51
  # 550 550 5.7.1 <****@gmail.com>... Access denied (state 13).
62
- '13' => { 'command' => 'EHLO', 'reason' => 'blocked' },
52
+ '13' => { 'command' => Sisimai::Eb::CeEHLO, 'reason' => Sisimai::Eb::ReBLOC },
63
53
 
64
54
  # Technical details of permanent failure:
65
55
  # Google tried to deliver your message, but it was rejected by the recipient domain.
@@ -68,7 +58,7 @@ module Sisimai::Lhost
68
58
  # 550 550 5.1.1 <******@*********.**>... User Unknown (state 14).
69
59
  # 550 550 5.2.2 <*****@****.**>... Mailbox Full (state 14).
70
60
  #
71
- '14' => { 'command' => 'RCPT', 'reason' => 'userunknown' },
61
+ '14' => { 'command' => Sisimai::Eb::CeRCPT, 'reason' => Sisimai::Eb::ReUSER },
72
62
 
73
63
  # https://www.google.cz/support/forum/p/gmail/thread?tid=7090cbfd111a24f9&hl=en
74
64
  # Technical details of permanent failure:
@@ -77,7 +67,7 @@ module Sisimai::Lhost
77
67
  # cause of this error. The error that the other server returned was:
78
68
  # 550 550 5.7.1 SPF unauthorized mail is prohibited. (state 15).
79
69
  # 554 554 Error: no valid recipients (state 15).
80
- '15' => { 'command' => 'DATA', 'reason' => 'filtered' },
70
+ '15' => { 'command' => Sisimai::Eb::CeDATA, 'reason' => Sisimai::Eb::ReFILT },
81
71
 
82
72
  # https://www.google.com/support/forum/p/Google%20Apps/thread?tid=0aac163bc9c65d8e&hl=en
83
73
  # Technical details of permanent failure:
@@ -86,14 +76,14 @@ module Sisimai::Lhost
86
76
  # cause of this error. The error that the other server returned was:
87
77
  # 550 550 <****@***.**> No such user here (state 17).
88
78
  # 550 550 #5.1.0 Address rejected ***@***.*** (state 17).
89
- '17' => { 'command' => 'DATA', 'reason' => 'filtered' },
79
+ '17' => { 'command' => Sisimai::Eb::CeDATA, 'reason' => Sisimai::Eb::ReFILT },
90
80
 
91
81
  # Technical details of permanent failure:
92
82
  # Google tried to deliver your message, but it was rejected by the recipient domain.
93
83
  # We recommend contacting the other email provider for further information about the
94
84
  # cause of this error. The error that the other server returned was:
95
85
  # 550 550 Unknown user *****@***.**.*** (state 18).
96
- '18' => { 'command' => 'DATA', 'reason' => 'filtered' },
86
+ '18' => { 'command' => Sisimai::Eb::CeDATA, 'reason' => Sisimai::Eb::ReFILT },
97
87
  }.freeze
98
88
 
99
89
  # @abstract Decodes the bounce message from Gmail
@@ -205,8 +195,6 @@ module Sisimai::Lhost
205
195
  require 'sisimai/string'
206
196
  require 'sisimai/rfc1123'
207
197
  dscontents.each do |e|
208
- e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'])
209
-
210
198
  if Sisimai::String.aligned(e['diagnosis'], [' by ', '. [', ']. '])
211
199
  # Get the value of remote host
212
200
  # Google tried to deliver your message, but it was rejected by the server for the recipient
@@ -232,16 +220,6 @@ module Sisimai::Lhost
232
220
  e['command'] = StateTable[cu]['command']
233
221
  break
234
222
  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
223
  next if e['reason'].empty?
246
224
 
247
225
  # 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
@@ -3,6 +3,7 @@ module Sisimai::Lhost
3
3
  # Methods in the module are called from only Sisimai::Message.
4
4
  module GoogleGroups
5
5
  class << self
6
+ require 'sisimai/eb'
6
7
  require 'sisimai/lhost'
7
8
  Boundaries = ['----- Original message -----', 'Content-Type: message/rfc822'].freeze
8
9
 
@@ -13,10 +14,10 @@ module Sisimai::Lhost
13
14
  # @return [Nil] it failed to decode or the arguments are missing
14
15
  # @since v4.25.6
15
16
  def inquire(mhead, mbody)
16
- return nil if mbody.include?("Google Groups") == false
17
+ return nil if mbody.include?("Google Group") == false
17
18
  return nil if mhead['from'].end_with?('<mailer-daemon@googlemail.com>') == false
18
19
  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?
20
+ return nil if mhead['x-failed-recipients'].nil?
20
21
 
21
22
  # Hello kijitora@libsisimai.org,
22
23
  #
@@ -46,11 +47,11 @@ module Sisimai::Lhost
46
47
  entiremesg = emailparts[0].split(/\n\n/, 5).slice(0, 4).join(' ').tr("\n", ' ');
47
48
  receivedby = mhead['received'] || []
48
49
  recordwide = {
49
- 'diagnosis' => Sisimai::String.sweep(entiremesg),
50
- 'reason' => 'onhold',
50
+ 'diagnosis' => entiremesg,
51
+ 'reason' => Sisimai::Eb::Re___1,
51
52
  'rhost' => Sisimai::RFC5322.received(receivedby[0])[1],
52
53
  }
53
- recordwide['reason'] = 'rejected' if emailparts[0].scan(/^[ ]?[*][ ]?/).size == 4
54
+ recordwide['reason'] = Sisimai::Eb::ReFROM if emailparts[0].scan(/^[ ]?[*][ ]?/).size == 4
54
55
 
55
56
  mhead['x-failed-recipients'].split(',').each do |e|
56
57
  # X-Failed-Recipients: neko@example.jp, nyaan@example.org, ...
@@ -3,6 +3,7 @@ module Sisimai::Lhost
3
3
  # Methods in the module are called only from Sisimai::Message.
4
4
  module GoogleWorkspace
5
5
  class << self
6
+ require 'sisimai/eb'
6
7
  require 'sisimai/lhost'
7
8
  require 'sisimai/string'
8
9
  require 'sisimai/address'
@@ -14,9 +15,7 @@ module Sisimai::Lhost
14
15
  error: ["The response was:", "The response from the remote server was:"],
15
16
  }.freeze
16
17
  MessagesOf = {
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"],
18
+ Sisimai::Eb::ReUSER => ["because the address couldn't be found. Check for typos or unnecessary spaces and try again."],
20
19
  }.freeze
21
20
 
22
21
  # @abstract Decodes the bounce message from Google Workspace
@@ -73,8 +72,6 @@ module Sisimai::Lhost
73
72
 
74
73
  dscontents[0]["diagnosis"] = entiremesg
75
74
  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
75
  MessagesOf.each_key do |r|
79
76
  # Guess an reason of the bounce
80
77
  next if MessagesOf[r].none? { |a| e["diagnosis"].include?(a) }
@@ -4,17 +4,14 @@ module Sisimai::Lhost
4
4
  # Methods in the module are called from only Sisimai::Message.
5
5
  module IMailServer
6
6
  class << self
7
+ require 'sisimai/eb'
7
8
  require 'sisimai/lhost'
8
9
 
9
10
  Boundaries = ['Original message follows.'].freeze
10
11
  StartingOf = {error: ['Body of message generated response:']}.freeze
11
12
  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 '],
13
+ Sisimai::Eb::ReUSER => ['Unknown user', 'Invalid final delivery userid'],
14
+ Sisimai::Eb::ReTIME => ['Delivery failed '],
18
15
  }.freeze
19
16
 
20
17
  # @abstract Decodes the bounce message from Progress iMail Server
@@ -72,11 +69,9 @@ module Sisimai::Lhost
72
69
  else
73
70
  e['alterrors']
74
71
  end
75
- e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'])
76
72
  e.delete('alterrors')
77
73
  end
78
- e['diagnosis'] = Sisimai::String.sweep(e['diagnosis']) || ''
79
- e['command'] = Sisimai::SMTP::Command.find(e['diagnosis'])
74
+ e['command'] = Sisimai::SMTP::Command.find(e['diagnosis'])
80
75
 
81
76
  MessagesOf.each_key do |r|
82
77
  # Verify each regular expression of session errors
@@ -3,16 +3,12 @@ module Sisimai::Lhost
3
3
  # Methods in the module are called from only Sisimai::Message.
4
4
  module KDDI
5
5
  class << self
6
+ require 'sisimai/eb'
6
7
  require 'sisimai/lhost'
7
8
 
8
9
  Indicators = Sisimai::Lhost.INDICATORS
9
10
  Boundaries = ['Content-Type: message/rfc822'].freeze
10
11
  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
12
 
17
13
  # @abstract Decodes the bounce message from au by KDDI
18
14
  # @param [Hash] mhead Message headers of a bounce email
@@ -45,7 +41,8 @@ module Sisimai::Lhost
45
41
  next if (readcursor & Indicators[:deliverystatus]) == 0 || e.empty?
46
42
 
47
43
  v = dscontents[-1]
48
- if e.include?(' Could not be delivered to: <')
44
+ case
45
+ when e.include?(' Could not be delivered to: <')
49
46
  # Your mail sent on: Thu, 29 Apr 2010 11:04:47 +0900
50
47
  # Could not be delivered to: <******@**.***.**>
51
48
  # As their mailbox is full.
@@ -59,7 +56,7 @@ module Sisimai::Lhost
59
56
  v['recipient'] = r
60
57
  recipients += 1
61
58
 
62
- elsif e.include?('Your mail sent on: ')
59
+ when e.include?('Your mail sent on: ')
63
60
  # Your mail sent on: Thu, 29 Apr 2010 11:04:47 +0900
64
61
  v['date'] = e[19, e.size]
65
62
  else
@@ -71,26 +68,16 @@ module Sisimai::Lhost
71
68
 
72
69
  require 'sisimai/smtp/command'
73
70
  dscontents.each do |e|
74
- e['diagnosis'] = Sisimai::String.sweep(e['diagnosis']) || ''
75
71
  e['command'] = Sisimai::SMTP::Command.find(e['diagnosis'])
76
72
 
77
73
  if mhead['x-spasign'].to_s == 'NG'
78
74
  # Content-Type: text/plain; ..., X-SPASIGN: NG (spamghetti, au by KDDI)
79
75
  # Filtered recipient returns message that include 'X-SPASIGN' header
80
- e['reason'] = 'filtered'
76
+ e['reason'] = Sisimai::Eb::ReFILT
81
77
  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
78
+ # There is no X-SPASIGN: header in the bounce message
79
+ # set "UserUnknown" when the remote server rejected after RCPT command.
80
+ e['reason'] = Sisimai::Eb::ReUSER if e['command'] == Sisimai::Eb::CeRCPT
94
81
  end
95
82
  end
96
83
 
@@ -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] }
@@ -3,17 +3,17 @@ module Sisimai::Lhost
3
3
  # (formerly Lotus Notes Server)). Methods in the module are called from only Sisimai::Message.
4
4
  module Notes
5
5
  class << self
6
+ require 'sisimai/eb'
6
7
  require 'sisimai/lhost'
7
8
 
8
9
  Indicators = Sisimai::Lhost.INDICATORS
9
10
  Boundaries = ['------- Returned Message --------'].freeze
10
11
  StartingOf = {message: ['------- Failure Reasons ']}.freeze
11
12
  MessagesOf = {
12
- 'userunknown' => [
13
+ Sisimai::Eb::ReUSER => [
13
14
  'User not listed in public Name & Address Book',
14
15
  'ディレクトリのリストにありません',
15
16
  ],
16
- 'networkerror' => ['Message has exceeded maximum hop count'],
17
17
  }.freeze
18
18
 
19
19
  # @abstract Decodes the bounce messages from HCL Notes (Formerly IBM Notes (Formerly Lotus Notes))
@@ -101,7 +101,7 @@ module Sisimai::Lhost
101
101
  return nil if recipients == 0
102
102
 
103
103
  dscontents.each do |e|
104
- e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'])
104
+ e['diagnosis'] = e['diagnosis'].split.join(" ")
105
105
  e['recipient'] = Sisimai::Address.s3s4(e['recipient'])
106
106
 
107
107
  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
@@ -3,6 +3,7 @@ module Sisimai::Lhost
3
3
  # Methods in the module are called from only Sisimai::Message.
4
4
  module Postfix
5
5
  class << self
6
+ require 'sisimai/eb'
6
7
  require 'sisimai/lhost'
7
8
  require 'sisimai/rfc1123'
8
9
  require 'sisimai/smtp/reply'
@@ -63,15 +64,14 @@ module Sisimai::Lhost
63
64
  v ||= dscontents[-1]
64
65
  p = e['response']
65
66
 
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'
67
+ case e["command"]
68
+ # Use the argument of EHLO/HELO command as a value of "lhost"
69
+ when Sisimai::Eb::CeHELO, Sisimai::Eb::CeEHLO then v['lhost'] = e['argument']
70
+ when Sisimai::Eb::CeMAIL
71
71
  # Set the argument of "MAIL" command to pseudo To: header of the original message
72
72
  emailparts[1] += sprintf("To: %s\n", e['argument']) if emailparts[1].size == 0
73
73
 
74
- elsif e['command'] == 'RCPT'
74
+ when Sisimai::Eb::CeRCPT
75
75
  # RCPT TO: <...>
76
76
  if v["recipient"] != ""
77
77
  # There are multiple recipient addresses in the transcript of session
@@ -110,7 +110,8 @@ module Sisimai::Lhost
110
110
  next unless o = Sisimai::RFC1894.field(e)
111
111
  v = dscontents[-1]
112
112
 
113
- if o[3] == 'addr'
113
+ case o[3]
114
+ when "addr"
114
115
  # Final-Recipient: rfc822; kijitora@example.jp
115
116
  # X-Actual-Recipient: rfc822; kijitora@example.co.jp
116
117
  if Sisimai::Address.is_emailaddress(o[2])
@@ -130,7 +131,7 @@ module Sisimai::Lhost
130
131
  v['alias'] = o[2]
131
132
  end
132
133
  end
133
- elsif o[3] == 'code'
134
+ when "code"
134
135
  # Diagnostic-Code: SMTP; 550 5.1.1 <userunknown@example.jp>... User Unknown
135
136
  v['spec'] = o[1]
136
137
  v['spec'] = 'SMTP' if v['spec'].upcase == 'X-POSTFIX'
@@ -154,7 +155,7 @@ module Sisimai::Lhost
154
155
  # 5.1.1 <userunknown@example.co.jp>... User Unknown (in reply to RCPT TO command)
155
156
  if readslices[-2].start_with?('Diagnostic-Code:') && e.include?(' ')
156
157
  # Continued line of the value of Diagnostic-Code header
157
- v['diagnosis'] += " #{Sisimai::String.sweep(e)}"
158
+ v['diagnosis'] += " " + e.split.join(" ")
158
159
  readslices[-1] = "Diagnostic-Code: #{e}"
159
160
 
160
161
  elsif Sisimai::String.aligned(e, ['X-Postfix-Sender:', 'rfc822;', '@'])
@@ -238,7 +239,7 @@ module Sisimai::Lhost
238
239
 
239
240
  if anotherset['diagnosis']
240
241
  # Copy alternative error message
241
- anotherset['diagnosis'] = Sisimai::String.sweep(anotherset['diagnosis'])
242
+ anotherset['diagnosis'] = anotherset['diagnosis'].split.join(" ")
242
243
  e['diagnosis'] = anotherset['diagnosis'] if e['diagnosis'].nil? || e['diagnosis'].empty?
243
244
 
244
245
  if e['diagnosis'] =~ /\A\d+\z/
@@ -277,10 +278,9 @@ module Sisimai::Lhost
277
278
  end
278
279
  end
279
280
 
280
- e['diagnosis'] = Sisimai::String.sweep(e['diagnosis']) || ''
281
- e['command'] = commandset.shift || Sisimai::SMTP::Command.find(e['diagnosis'])
282
- e['command'] = 'HELO' if e["command"].empty? && e['diagnosis'].include?('refused to talk to me:')
283
- e['spec'] = 'SMTP' if e["spec"].empty? && Sisimai::String.aligned(e['diagnosis'], ['host ', ' said:'])
281
+ e['command'] = commandset.shift || Sisimai::SMTP::Command.find(e['diagnosis'])
282
+ e['command'] = Sisimai::Eb::CeHELO if e["command"].empty? && e['diagnosis'].include?('refused to talk to me:')
283
+ e['spec'] = 'SMTP' if e["spec"].empty? && Sisimai::String.aligned(e['diagnosis'], ['host ', ' said:'])
284
284
  end
285
285
 
286
286
  return { 'ds' => dscontents, 'rfc822' => emailparts[1] }