sisimai 5.4.1-java → 5.6.0-java

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (150) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/codecovio.yml +1 -1
  3. data/.github/workflows/rake-test.yml +1 -1
  4. data/ChangeLog.md +56 -0
  5. data/LICENSE +1 -1
  6. data/Makefile +2 -4
  7. data/README-JA.md +29 -23
  8. data/README.md +30 -24
  9. data/lib/sisimai/address.rb +92 -44
  10. data/lib/sisimai/arf.rb +7 -8
  11. data/lib/sisimai/datetime.rb +2 -2
  12. data/lib/sisimai/fact/json.rb +1 -2
  13. data/lib/sisimai/fact/yaml.rb +1 -2
  14. data/lib/sisimai/fact.rb +76 -36
  15. data/lib/sisimai/lda.rb +2 -2
  16. data/lib/sisimai/lhost/activehunter.rb +4 -5
  17. data/lib/sisimai/lhost/amazonses.rb +4 -5
  18. data/lib/sisimai/lhost/apachejames.rb +2 -2
  19. data/lib/sisimai/lhost/biglobe.rb +6 -6
  20. data/lib/sisimai/lhost/courier.rb +7 -7
  21. data/lib/sisimai/lhost/domino.rb +6 -6
  22. data/lib/sisimai/lhost/dragonfly.rb +5 -5
  23. data/lib/sisimai/lhost/einsundeins.rb +5 -5
  24. data/lib/sisimai/lhost/exchange2003.rb +7 -7
  25. data/lib/sisimai/lhost/exchange2007.rb +5 -5
  26. data/lib/sisimai/lhost/exim.rb +13 -15
  27. data/lib/sisimai/lhost/ezweb.rb +3 -2
  28. data/lib/sisimai/lhost/fml.rb +9 -9
  29. data/lib/sisimai/lhost/gmail.rb +9 -9
  30. data/lib/sisimai/lhost/gmx.rb +3 -3
  31. data/lib/sisimai/lhost/googlegroups.rb +6 -7
  32. data/lib/sisimai/lhost/googleworkspace.rb +5 -6
  33. data/lib/sisimai/lhost/imailserver.rb +4 -4
  34. data/lib/sisimai/lhost/kddi.rb +4 -4
  35. data/lib/sisimai/lhost/mailfoundry.rb +3 -3
  36. data/lib/sisimai/lhost/{mailmarshalsmtp.rb → mailmarshal.rb} +5 -5
  37. data/lib/sisimai/lhost/messagingserver.rb +8 -8
  38. data/lib/sisimai/lhost/mfilter.rb +8 -4
  39. data/lib/sisimai/lhost/mimecast.rb +105 -0
  40. data/lib/sisimai/lhost/notes.rb +5 -5
  41. data/lib/sisimai/lhost/opensmtpd.rb +5 -5
  42. data/lib/sisimai/lhost/postfix.rb +38 -32
  43. data/lib/sisimai/lhost/qmail.rb +11 -11
  44. data/lib/sisimai/lhost/sendmail.rb +13 -13
  45. data/lib/sisimai/lhost/{interscanmss.rb → trendmicro.rb} +8 -9
  46. data/lib/sisimai/lhost/v5sendmail.rb +7 -7
  47. data/lib/sisimai/lhost/verizon.rb +3 -3
  48. data/lib/sisimai/lhost/x1.rb +7 -4
  49. data/lib/sisimai/lhost/x2.rb +40 -12
  50. data/lib/sisimai/lhost/x3.rb +3 -3
  51. data/lib/sisimai/lhost/x6.rb +2 -2
  52. data/lib/sisimai/lhost/zoho.rb +5 -5
  53. data/lib/sisimai/lhost.rb +18 -17
  54. data/lib/sisimai/mail/maildir.rb +4 -4
  55. data/lib/sisimai/mail/mbox.rb +4 -4
  56. data/lib/sisimai/mail/memory.rb +1 -1
  57. data/lib/sisimai/mail/stdin.rb +2 -2
  58. data/lib/sisimai/message.rb +36 -34
  59. data/lib/sisimai/order.rb +5 -4
  60. data/lib/sisimai/reason/authfailure.rb +10 -14
  61. data/lib/sisimai/reason/badreputation.rb +8 -8
  62. data/lib/sisimai/reason/blocked.rb +58 -83
  63. data/lib/sisimai/reason/contenterror.rb +15 -10
  64. data/lib/sisimai/reason/{mesgtoobig.rb → emailtoolarge.rb} +23 -26
  65. data/lib/sisimai/reason/expired.rb +17 -24
  66. data/lib/sisimai/reason/failedstarttls.rb +1 -1
  67. data/lib/sisimai/reason/filtered.rb +14 -18
  68. data/lib/sisimai/reason/hasmoved.rb +3 -2
  69. data/lib/sisimai/reason/hostunknown.rb +18 -21
  70. data/lib/sisimai/reason/mailboxfull.rb +28 -50
  71. data/lib/sisimai/reason/mailererror.rb +1 -1
  72. data/lib/sisimai/reason/networkerror.rb +17 -17
  73. data/lib/sisimai/reason/norelaying.rb +20 -20
  74. data/lib/sisimai/reason/notaccept.rb +7 -10
  75. data/lib/sisimai/reason/notcompliantrfc.rb +6 -10
  76. data/lib/sisimai/reason/policyviolation.rb +12 -28
  77. data/lib/sisimai/reason/ratelimited.rb +62 -0
  78. data/lib/sisimai/reason/rejected.rb +46 -58
  79. data/lib/sisimai/reason/requireptr.rb +14 -26
  80. data/lib/sisimai/reason/securityerror.rb +14 -20
  81. data/lib/sisimai/reason/spamdetected.rb +52 -102
  82. data/lib/sisimai/reason/suspend.rb +27 -24
  83. data/lib/sisimai/reason/systemerror.rb +20 -24
  84. data/lib/sisimai/reason/systemfull.rb +2 -2
  85. data/lib/sisimai/reason/userunknown.rb +82 -114
  86. data/lib/sisimai/reason/vacation.rb +1 -1
  87. data/lib/sisimai/reason/virusdetected.rb +7 -9
  88. data/lib/sisimai/reason.rb +26 -26
  89. data/lib/sisimai/rfc1123.rb +58 -18
  90. data/lib/sisimai/rfc1894.rb +6 -8
  91. data/lib/sisimai/rfc2045.rb +25 -13
  92. data/lib/sisimai/rfc3464/thirdparty.rb +2 -3
  93. data/lib/sisimai/rfc3464.rb +6 -6
  94. data/lib/sisimai/rfc3834.rb +18 -8
  95. data/lib/sisimai/rfc5322.rb +9 -9
  96. data/lib/sisimai/rfc791.rb +2 -2
  97. data/lib/sisimai/rhost/aol.rb +4 -1
  98. data/lib/sisimai/rhost/apple.rb +15 -11
  99. data/lib/sisimai/rhost/cloudflare.rb +2 -0
  100. data/lib/sisimai/rhost/cox.rb +31 -25
  101. data/lib/sisimai/rhost/facebook.rb +24 -18
  102. data/lib/sisimai/rhost/franceptt.rb +92 -38
  103. data/lib/sisimai/rhost/godaddy.rb +34 -7
  104. data/lib/sisimai/rhost/google.rb +69 -70
  105. data/lib/sisimai/rhost/gsuite.rb +1 -1
  106. data/lib/sisimai/rhost/iua.rb +1 -1
  107. data/lib/sisimai/rhost/kddi.rb +1 -1
  108. data/lib/sisimai/rhost/messagelabs.rb +160 -2
  109. data/lib/sisimai/rhost/microsoft.rb +154 -107
  110. data/lib/sisimai/rhost/mimecast.rb +64 -55
  111. data/lib/sisimai/rhost/nttdocomo.rb +70 -90
  112. data/lib/sisimai/rhost/outlook.rb +1 -1
  113. data/lib/sisimai/rhost/spectrum.rb +8 -8
  114. data/lib/sisimai/rhost/tencent.rb +12 -13
  115. data/lib/sisimai/rhost/yahooinc.rb +9 -10
  116. data/lib/sisimai/rhost/zoho.rb +72 -0
  117. data/lib/sisimai/rhost.rb +4 -3
  118. data/lib/sisimai/smtp/command.rb +4 -2
  119. data/lib/sisimai/smtp/reply.rb +11 -4
  120. data/lib/sisimai/smtp/status.rb +67 -98
  121. data/lib/sisimai/smtp/transcript.rb +3 -3
  122. data/lib/sisimai/string.rb +4 -23
  123. data/lib/sisimai/version.rb +1 -1
  124. data/lib/sisimai.rb +1 -1
  125. data/set-of-emails/maildir/bsd/lhost-exim-56.eml +40 -40
  126. data/set-of-emails/maildir/bsd/lhost-mfilter-05.eml +41 -0
  127. data/set-of-emails/maildir/bsd/lhost-mimecast-01.eml +46 -0
  128. data/set-of-emails/maildir/bsd/lhost-mimecast-02.eml +59 -0
  129. data/set-of-emails/maildir/bsd/lhost-postfix-79.eml +81 -0
  130. data/set-of-emails/maildir/bsd/lhost-postfix-80.eml +84 -0
  131. data/set-of-emails/maildir/bsd/lhost-x1-03.eml +26 -0
  132. data/set-of-emails/maildir/bsd/lhost-x1-04.eml +45 -0
  133. data/set-of-emails/maildir/bsd/lhost-x2-07.eml +30 -0
  134. data/set-of-emails/maildir/bsd/rfc3464-66.eml +170 -0
  135. data/set-of-emails/maildir/bsd/rfc3834-06.eml +59 -0
  136. data/set-of-emails/maildir/bsd/rhost-zoho-01.eml +88 -0
  137. data/set-of-emails/maildir/bsd/rhost-zoho-02.eml +86 -0
  138. data/set-of-emails/maildir/bsd/rhost-zoho-03.eml +87 -0
  139. data/set-of-emails/maildir/bsd/rhost-zoho-04.eml +86 -0
  140. data/set-of-emails/maildir/not/rb-issue-368-bug.eml +39 -0
  141. data/sisimai-java.gemspec +1 -1
  142. data/sisimai.gemspec +1 -1
  143. metadata +28 -13
  144. data/lib/sisimai/reason/exceedlimit.rb +0 -47
  145. data/lib/sisimai/reason/speeding.rb +0 -47
  146. data/lib/sisimai/reason/toomanyconn.rb +0 -59
  147. /data/set-of-emails/maildir/bsd/{lhost-mailmarshalsmtp-02.eml → lhost-mailmarshal-02.eml} +0 -0
  148. /data/set-of-emails/maildir/bsd/{lhost-interscanmss-01.eml → lhost-trendmicro-01.eml} +0 -0
  149. /data/set-of-emails/maildir/bsd/{lhost-interscanmss-02.eml → lhost-trendmicro-02.eml} +0 -0
  150. /data/set-of-emails/maildir/bsd/{lhost-interscanmss-03.eml → lhost-trendmicro-03.eml} +0 -0
@@ -36,10 +36,10 @@ module Sisimai::Lhost
36
36
  # @return [Nil] it failed to decode or the arguments are missing
37
37
  def inquire(mhead, mbody)
38
38
  # :from => %r/\AMail Delivery Subsystem/,
39
- return nil unless mhead['subject'].start_with?('Returned mail: ')
39
+ return nil if mhead['subject'].start_with?('Returned mail: ') == false
40
40
 
41
41
  emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
42
- return nil unless emailparts[1].size > 0
42
+ return nil if emailparts[1].size == 0
43
43
 
44
44
  require 'sisimai/rfc1123'
45
45
  require 'sisimai/smtp/command'
@@ -133,7 +133,7 @@ module Sisimai::Lhost
133
133
  # There is no recipient address in the error message
134
134
  anotherone.each_key do |e|
135
135
  # Try to pick an recipient address, a reply code, and error messages
136
- cv = Sisimai::Address.s3s4(anotherone[e]); next unless Sisimai::Address.is_emailaddress(cv)
136
+ cv = Sisimai::Address.s3s4(anotherone[e]); next if Sisimai::Address.is_emailaddress(cv) == false
137
137
  cr = Sisimai::SMTP::Reply.find(anotherone[e])
138
138
 
139
139
  dscontents[e]["recipient"] = cv
@@ -150,13 +150,13 @@ module Sisimai::Lhost
150
150
  if p1 > 0
151
151
  # Get the recipient address from "To:" header at the original message
152
152
  cv = Sisimai::Address.s3s4(emailparts[1][p1, p2 - p1 - 5])
153
- return nil unless Sisimai::Address.is_emailaddress(cv)
153
+ return nil if Sisimai::Address.is_emailaddress(cv) == false
154
154
  dscontents[0]["recipient"] = cv
155
155
  recipients += 1
156
156
  end
157
157
  end
158
158
  end
159
- return nil unless recipients > 0
159
+ return nil if recipients == 0
160
160
 
161
161
  j = 0; dscontents.each do |e|
162
162
  # Tidy up the error message in e.Diagnosis
@@ -169,8 +169,8 @@ module Sisimai::Lhost
169
169
  # @example.jp, no local part
170
170
  # Get email address from the value of Diagnostic-Code header
171
171
  next if e['recipient'].include?('@')
172
- p1 = e['diagnosis'].index('<'); next unless p1
173
- p2 = e['diagnosis'].index('>'); next unless p2
172
+ p1 = e['diagnosis'].index('<'); next if p1.nil?
173
+ p2 = e['diagnosis'].index('>'); next if p2.nil?
174
174
  e['recipient'] = Sisimai::Address.s3s4(e[p1, p2 - p1])
175
175
  end
176
176
 
@@ -16,7 +16,7 @@ module Sisimai::Lhost
16
16
  while true
17
17
  # Check the value of "From" header
18
18
  # :'subject' => %r/Undeliverable Message/,
19
- break unless mhead['received'].any? { |a| a.include?('.vtext.com (') }
19
+ break if mhead['received'].none? { |a| a.include?('.vtext.com (') }
20
20
  match = 1 if mhead['from'] == 'post_master@vtext.com'
21
21
  match = 0 if Sisimai::String.aligned(mhead['from'], ['sysadmin@', '.vzwpix.com'])
22
22
  break
@@ -130,7 +130,7 @@ module Sisimai::Lhost
130
130
  end
131
131
  end
132
132
  end
133
- return nil unless recipients > 0
133
+ return nil if recipients == 0
134
134
 
135
135
  # Set the value of "MAIL FROM:" and "From:"
136
136
  emailparts[1] += "From: #{senderaddr}\n" if emailparts[1].include?("\nFrom: ") == false
@@ -140,7 +140,7 @@ module Sisimai::Lhost
140
140
  e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'])
141
141
  messagesof.each_key do |r|
142
142
  # Verify each regular expression of session errors
143
- next unless messagesof[r].any? { |a| e['diagnosis'].include?(a) }
143
+ next if messagesof[r].none? { |a| e['diagnosis'].include?(a) }
144
144
  e['reason'] = r
145
145
  break
146
146
  end
@@ -6,7 +6,7 @@ module Sisimai::Lhost
6
6
  require 'sisimai/lhost'
7
7
 
8
8
  Indicators = Sisimai::Lhost.INDICATORS
9
- Boundaries = ['Received: from '].freeze
9
+ Boundaries = ['Content-Type: message/rfc822', 'Received: from '].freeze
10
10
  MarkingsOf = {message: ['The original message was received at ']}.freeze
11
11
 
12
12
  # @abstract Decodes the bounce message from Unknown MTA #1
@@ -15,8 +15,11 @@ module Sisimai::Lhost
15
15
  # @return [Hash] Bounce data list and message/rfc822 part
16
16
  # @return [Nil] it failed to decode or the arguments are missing
17
17
  def inquire(mhead, mbody)
18
- return nil unless mhead['subject'].start_with?('Returned Mail: ')
19
- return nil unless mhead['from'].start_with?('"Mail Deliver System" ')
18
+ proceedsto = false
19
+ proceedsto = true if mhead['subject'].start_with?('Returned Mail: ')
20
+ proceedsto = true if mhead['subject'].start_with?('Mail Delivery Failure')
21
+ proceedsto = true if Sisimai::String.aligned(mhead['from'], ['"Mail Deliver', 'System" '])
22
+ return nil if proceedsto == false
20
23
 
21
24
  dscontents = [Sisimai::Lhost.DELIVERYSTATUS]; v = nil
22
25
  emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
@@ -61,7 +64,7 @@ module Sisimai::Lhost
61
64
  datestring = e[MarkingsOf[:message][0].size, e.size]
62
65
  end
63
66
  end
64
- return nil unless recipients > 0
67
+ return nil if recipients == 0
65
68
 
66
69
  dscontents.each do |e|
67
70
  e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'])
@@ -7,7 +7,11 @@ module Sisimai::Lhost
7
7
 
8
8
  Indicators = Sisimai::Lhost.INDICATORS
9
9
  Boundaries = ['--- Original message follows.'].freeze
10
- StartingOf = {message: ['Unable to deliver message to the following address']}.freeze
10
+ StartingOf = {
11
+ message: [
12
+ "Unable to deliver message to the following address",
13
+ "This Delivery Status Notification is sent from MTA",
14
+ ]}.freeze
11
15
 
12
16
  # @abstract Decodes the bounce message from Unknown MTA #2
13
17
  # @param [Hash] mhead Message headers of a bounce email
@@ -15,12 +19,12 @@ module Sisimai::Lhost
15
19
  # @return [Hash] Bounce data list and message/rfc822 part
16
20
  # @return [Nil] it failed to decode or the arguments are missing
17
21
  def inquire(mhead, mbody)
18
- match = nil
19
- match ||= 1 if mhead['from'].include?('MAILER-DAEMON@')
20
- match ||= 1 if mhead['subject'].start_with?('Delivery failure')
21
- match ||= 1 if mhead['subject'].start_with?('failure delivery')
22
- match ||= 1 if mhead['subject'].start_with?('failed delivery')
23
- return nil unless match
22
+ match = false
23
+ match ||= true if mhead['from'].include?('MAILER-DAEMON@')
24
+ match ||= true if mhead['subject'].start_with?('Delivery failure')
25
+ match ||= true if mhead['subject'].start_with?('failure delivery')
26
+ match ||= true if mhead['subject'].start_with?('failed delivery')
27
+ return nil if match == false
24
28
 
25
29
  dscontents = [Sisimai::Lhost.DELIVERYSTATUS]; v = nil
26
30
  emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
@@ -33,7 +37,7 @@ module Sisimai::Lhost
33
37
  # line of the beginning of the original message.
34
38
  if readcursor == 0
35
39
  # Beginning of the bounce message or delivery status part
36
- readcursor |= Indicators[:deliverystatus] if e.start_with?(StartingOf[:message][0])
40
+ readcursor |= Indicators[:deliverystatus] if StartingOf[:message].any? { |a| e.start_with?(a) }
37
41
  next
38
42
  end
39
43
  next if (readcursor & Indicators[:deliverystatus]) == 0 || e.empty?
@@ -43,23 +47,47 @@ module Sisimai::Lhost
43
47
  #
44
48
  # <kijitora@example.com>:
45
49
  # This user doesn't have a example.com account (kijitora@example.com) [0]
50
+ #
51
+ # --- OR ---
52
+ #
53
+ # This Delivery Status Notification is sent from MTA...
54
+ #
55
+ # Your delivery to the following address has been failed.
56
+ # Please refer to the below for details.
57
+ # ------------------------------------------------------
58
+ #
59
+ # Delivery failed: kijitora@example.co.jp
60
+ # 192.0.2.25 does not like recipient.
61
+ # Remote host said[Response Message]: 550 5.1.1 <kijitora@example.co.jp>:
62
+ # Recipient address rejected: User unknown in local recipient table
63
+ # Giving up on 192.0.2.25.
64
+ # STEP: RCPT TO
46
65
  v = dscontents[-1]
47
66
 
48
- if e.start_with?('<') && Sisimai::String.aligned(e, ['<', '@', '>', ':'])
67
+ if e.start_with?('<') && Sisimai::String.aligned(e, ['<', '@', '>:']) ||
68
+ e.start_with?('Delivery failed: ') && Sisimai::String.aligned(e, ['failed: ', '@'])
49
69
  # <kijitora@example.com>:
70
+ # Delivery failed: kijitora@example.co.jp
50
71
  if v["recipient"] != ""
51
72
  # There are multiple recipient addresses in the message body.
52
73
  dscontents << Sisimai::Lhost.DELIVERYSTATUS
53
74
  v = dscontents[-1]
54
75
  end
55
- v['recipient'] = e[1, e.size - 3]
76
+ v['recipient'] = e[1, e.size - 3] if e.start_with?('<')
77
+ v['recipient'] = e[e.index(': ') + 2, e.size - 1] if v['recipient'].empty?
56
78
  recipients += 1
57
- else
79
+
80
+ elsif e.start_with?('STEP: ')
81
+ # STEP: RCPT TO
82
+ # STEP: DATA SEND
83
+ v['command'] = Sisimai::SMTP::Command.find(e)
84
+
85
+ elsif e.start_with?('-----') == false
58
86
  # This user doesn't have a example.com account (kijitora@example.com) [0]
59
87
  v['diagnosis'] += " #{e}"
60
88
  end
61
89
  end
62
- return nil unless recipients > 0
90
+ return nil if recipients == 0
63
91
 
64
92
  dscontents.each { |e| e['diagnosis'] = Sisimai::String.sweep(e['diagnosis']) }
65
93
  return {"ds" => dscontents, "rfc822" => emailparts[1]}
@@ -15,8 +15,8 @@ module Sisimai::Lhost
15
15
  # @return [Hash] Bounce data list and message/rfc822 part
16
16
  # @return [Nil] it failed to decode or the arguments are missing
17
17
  def inquire(mhead, mbody)
18
- return nil unless mhead['subject'].start_with?('Delivery status notification')
19
- return nil unless mhead['from'].start_with?('Mail Delivery System')
18
+ return nil if mhead['subject'].start_with?('Delivery status notification') == false
19
+ return nil if mhead['from'].start_with?('Mail Delivery System') == false
20
20
 
21
21
  require 'sisimai/smtp/command'
22
22
  dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
@@ -79,7 +79,7 @@ module Sisimai::Lhost
79
79
  end
80
80
  end
81
81
  end
82
- return nil unless recipients > 0
82
+ return nil if recipients == 0
83
83
 
84
84
  dscontents.each do |e|
85
85
  e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'])
@@ -16,7 +16,7 @@ module Sisimai::Lhost
16
16
  # @return [Nil] it failed to decode or the arguments are missing
17
17
  # @since v4.25.6
18
18
  def inquire(mhead, mbody)
19
- return nil unless mhead['subject'].start_with?('There was an error sending your mail')
19
+ return nil if mhead['subject'].start_with?('There was an error sending your mail') == false
20
20
 
21
21
  dscontents = [Sisimai::Lhost.DELIVERYSTATUS]; v = nil
22
22
  emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
@@ -76,7 +76,7 @@ module Sisimai::Lhost
76
76
  recipients += 1
77
77
  end
78
78
  end
79
- return nil unless recipients > 0
79
+ return nil if recipients == 0
80
80
 
81
81
  require 'sisimai/smtp/command'
82
82
  dscontents.each do |e|
@@ -19,7 +19,7 @@ module Sisimai::Lhost
19
19
  # X-ZohoMail: Si CHF_MF_NL SS_10 UW48 UB48 FMWL UW48 UB48 SGR3_1_09124_42
20
20
  # X-Zoho-Virus-Status: 2
21
21
  # X-Mailer: Zoho Mail
22
- return nil unless mhead['x-zohomail']
22
+ return nil if mhead['x-zohomail'].nil?
23
23
 
24
24
  dscontents = [Sisimai::Lhost.DELIVERYSTATUS]; v = nil
25
25
  emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
@@ -68,7 +68,7 @@ module Sisimai::Lhost
68
68
  end
69
69
  recipients += 1
70
70
 
71
- elsif e.start_with?('[Status: ')
71
+ elsif e.start_with?('[Status: ') && e.include?('<') && e.include?('>')
72
72
  # Expired
73
73
  # [Status: Error, Address: <kijitora@6kaku.example.co.jp>, ResponseCode 421, , Host not reachable.]
74
74
  if v["recipient"] != ""
@@ -83,17 +83,17 @@ module Sisimai::Lhost
83
83
  recipients += 1
84
84
  else
85
85
  # Continued line
86
- next unless qprintable
86
+ next if qprintable == false
87
87
  v['diagnosis'] += e
88
88
  end
89
89
  end
90
- return nil unless recipients > 0
90
+ return nil if recipients == 0
91
91
 
92
92
  dscontents.each do |e|
93
93
  e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'].tr("\n", ' '))
94
94
  MessagesOf.each_key do |r|
95
95
  # Verify each regular expression of session errors
96
- next unless MessagesOf[r].any? { |a| e['diagnosis'].include?(a) }
96
+ next if MessagesOf[r].none? { |a| e['diagnosis'].include?(a) }
97
97
  e['reason'] = r
98
98
  break
99
99
  end
data/lib/sisimai/lhost.rb CHANGED
@@ -9,20 +9,21 @@ module Sisimai
9
9
  # @private
10
10
  def DELIVERYSTATUS
11
11
  return {
12
- 'spec' => "", # Protocl specification
13
- 'date' => "", # The value of Last-Attempt-Date header
14
- 'rhost' => "", # The value of Remote-MTA header
15
- 'lhost' => "", # The value of Received-From-MTA header
16
- 'alias' => "", # The value of alias entry(RHS)
17
- 'agent' => "", # MTA module name
18
- 'action' => "", # The value of Action header
19
- 'status' => "", # The value of Status header
20
- 'reason' => "", # Temporary reason of bounce
21
- 'command' => "", # SMTP command in the message body
22
- 'replycode' => "", # SMTP Reply code
23
- 'diagnosis' => "", # The value of Diagnostic-Code header
24
- 'recipient' => "", # The value of Final-Recipient header
25
- 'feedbacktype' => "", # Feedback Type
12
+ 'spec' => "", # Protocl specification
13
+ 'date' => "", # The value of Last-Attempt-Date header
14
+ 'rhost' => "", # The value of Remote-MTA header
15
+ 'lhost' => "", # The value of Received-From-MTA header
16
+ 'alias' => "", # The value of alias entry(RHS)
17
+ 'agent' => "", # MTA module name
18
+ 'action' => "", # The value of Action header
19
+ 'status' => "", # The value of Status header
20
+ 'reason' => "", # Temporary reason of bounce
21
+ 'command' => "", # SMTP command in the message body
22
+ 'replycode' => "", # SMTP Reply code
23
+ 'diagnosis' => "", # The value of Diagnostic-Code header
24
+ 'recipient' => "", # The value of Final-Recipient header
25
+ 'feedbacktype' => "", # Feedback Type
26
+ 'toxic' => false, # EXPERIMENTAL
26
27
  }
27
28
  end
28
29
 
@@ -41,9 +42,9 @@ module Sisimai
41
42
  def index
42
43
  return %w[
43
44
  Activehunter AmazonSES ApacheJames Biglobe Courier Domino DragonFly EZweb EinsUndEins Exchange2003
44
- Exchange2007 Exim FML GMX GoogleWorkspace GoogleGroups Gmail IMailServer InterScanMSS KDDI
45
- MailFoundry MailMarshalSMTP MessagingServer Notes OpenSMTPD Postfix Sendmail V5sendmail
46
- Verizon X1 X2 X3 X6 Zoho MFILTER Qmail
45
+ Exchange2007 Exim FML GMX GoogleWorkspace GoogleGroups Gmail IMailServer KDDI MailFoundry Mimecast
46
+ MailMarshal MessagingServer Notes OpenSMTPD Postfix Sendmail TrendMicro V5sendmail Verizon
47
+ X1 X2 X3 X6 Zoho MFILTER Qmail
47
48
  ]
48
49
  end
49
50
 
@@ -16,8 +16,8 @@ module Sisimai
16
16
  # @return [Sisimai::Mail::Maildir] Object
17
17
  # [Nil] is not a directory or does not exist
18
18
  def initialize(argv1)
19
- raise Errno::ENOENT unless File.exist?(argv1)
20
- raise Errno::ENOTDIR unless File.ftype(argv1) == 'directory'
19
+ raise Errno::ENOENT if File.exist?(argv1) == false
20
+ raise Errno::ENOTDIR if File.ftype(argv1) != 'directory'
21
21
 
22
22
  @path = nil
23
23
  @size = Dir.entries(argv1).size
@@ -30,7 +30,7 @@ module Sisimai
30
30
  # Maildir reader, works as an iterator.
31
31
  # @return [String] Contents of file in Maildir/
32
32
  def read
33
- return nil unless self.offset < self.size
33
+ return nil if self.offset >= self.size
34
34
  seekhandle = self.handle
35
35
  readbuffer = ''
36
36
 
@@ -61,7 +61,7 @@ module Sisimai
61
61
  self.file = r
62
62
  break
63
63
  end
64
- seekhandle.close unless self.offset < self.size
64
+ seekhandle.close if self.offset >= self.size
65
65
  end
66
66
 
67
67
  return readbuffer
@@ -16,8 +16,8 @@ module Sisimai
16
16
  # @return [Sisimai::Mail::Mbox] Object
17
17
  # [Nil] is not specified or does not exist
18
18
  def initialize(argv1)
19
- raise Errno::ENOENT unless File.exist?(argv1)
20
- raise 'is not a file' unless File.ftype(argv1) == 'file'
19
+ raise Errno::ENOENT if File.exist?(argv1) == false
20
+ raise 'is not a file' if File.ftype(argv1) != 'file'
21
21
 
22
22
  @path = argv1
23
23
  @dir = File.dirname(argv1)
@@ -30,7 +30,7 @@ module Sisimai
30
30
  # Mbox reader, works as an iterator.
31
31
  # @return [String] Contents of mbox
32
32
  def read
33
- return nil unless self.offset < self.size
33
+ return nil if self.offset >= self.size
34
34
 
35
35
  seekoffset = self.offset || 0
36
36
  filehandle = self.handle
@@ -53,7 +53,7 @@ module Sisimai
53
53
  seekoffset = filehandle.pos - frombuffer.bytesize
54
54
  frombuffer = ''
55
55
  self.offset = seekoffset
56
- filehandle.close unless self.offset < self.size
56
+ filehandle.close if self.offset >= self.size
57
57
  end
58
58
 
59
59
  return readbuffer.to_s
@@ -14,7 +14,7 @@ module Sisimai
14
14
  # @return [Sisimai::Mail::Memory] Object
15
15
  # [Nil] is not specified or does not exist
16
16
  def initialize(argv1)
17
- raise 'is not a String' unless argv1.is_a? ::String
17
+ raise 'is not a String' if argv1.is_a?(::String) == false
18
18
  raise 'is empty' if argv1.empty?
19
19
 
20
20
  @path = '<MEMORY>'
@@ -13,7 +13,7 @@ module Sisimai
13
13
  # @param [IO::STDIN] stdin Standard-In
14
14
  # @return [Sisimai::Mail::STDIN] Object
15
15
  def initialize(stdin = $stdin)
16
- raise 'is not an IO object' unless stdin.is_a?(IO)
16
+ raise 'is not an IO object' if stdin.is_a?(IO) == false
17
17
 
18
18
  @path = '<STDIN>'
19
19
  @size = nil
@@ -32,7 +32,7 @@ module Sisimai
32
32
  end
33
33
 
34
34
  begin
35
- readhandle = STDIN unless readhandle
35
+ readhandle = STDIN if readhandle.nil?
36
36
  while r = readhandle.gets
37
37
  break if readbuffer.size > 0 && r.start_with?('From ')
38
38
  readbuffer << r
@@ -21,12 +21,15 @@ module Sisimai
21
21
  FieldIndex = [Fields1894.flatten, Fields5322.flatten, Fields5965.flatten].flatten.freeze
22
22
  FieldTable = FieldIndex.map { |e| [e.downcase, e] }.to_h.freeze
23
23
  Boundaries = ['Content-Type: message/rfc822', 'Content-Type: text/rfc822-headers'].freeze
24
- ReplacesAs = {
25
- "Content-Type" => [
26
- %w[message/xdelivery-status message/delivery-status],
27
- %w[message/disposition-notification message/delivery-status],
28
- ]
29
- }.freeze
24
+ MediaTypes = [
25
+ %w[message/xdelivery-status message/delivery-status],
26
+ %w[message/disposition-notification message/delivery-status],
27
+ %w[message/global-delivery-status message/delivery-status],
28
+ %w[message/global-disposition-notification message/delivery-status],
29
+ %w[message/global-delivery-status message/delivery-status],
30
+ %w[message/global-headers text/rfc822-headers],
31
+ %w[message/global message/rfc822],
32
+ ].freeze
30
33
 
31
34
  # Read an email message and convert to structured format
32
35
  # @param [Hash] argvs Module to be loaded
@@ -35,7 +38,7 @@ module Sisimai
35
38
  # @return [Sisimai::Message] Structured email data or nil if each
36
39
  # value of the arguments are missing
37
40
  def rise(**argvs)
38
- return nil unless argvs
41
+ return nil if argvs.nil?
39
42
  email = argvs[:data].scrub('?').gsub("\r\n", "\n")
40
43
  thing = {'from' => '','header' => {}, 'rfc822' => '', 'ds' => [], 'catch' => nil}
41
44
  param = {}
@@ -53,12 +56,12 @@ module Sisimai
53
56
  thing['header'] = Sisimai::Message.makemap(aftersplit[1])
54
57
 
55
58
  # 3. Decode and rewrite the "Subject:" header
56
- unless thing['header']['subject'].empty?
59
+ if thing['header']['subject'].empty? == false
57
60
  # Decode MIME-Encoded "Subject:" header
58
61
  cv = thing['header']['subject']
59
62
  cq = Sisimai::RFC2045.is_encoded(cv) ? Sisimai::RFC2045.decodeH(cv.split(/[ ]/)) : cv
60
63
  cl = cq.downcase
61
- p1 = cl.index('fwd:'); p1 = cl.index('fw:') unless p1
64
+ p1 = cl.index('fwd:'); p1 = cl.index('fw:') if p1.nil?
62
65
 
63
66
  # Remove "Fwd:" string from the Subject: header
64
67
  if p1
@@ -77,17 +80,16 @@ module Sisimai
77
80
  'tryonfirst' => Sisimai::Order.make(thing['header']['subject'])
78
81
  }
79
82
  break if beforefact = Sisimai::Message.sift(param)
80
- break unless Boundaries.any? { |a| aftersplit[2].include?(a) }
83
+ break if Boundaries.none? { |a| aftersplit[2].include?(a) }
81
84
 
82
85
  # 5. Try to sift again
83
86
  # There is a bounce message inside of mutipart/*, try to sift the first message/rfc822
84
87
  # part as a entire message body again.
85
88
  parseagain += 1
86
89
  email = Sisimai::RFC5322.part(aftersplit[2], Boundaries, true).pop.sub(/\A\s+/, '')
87
- break unless email.size > 128
90
+ break if email.size < 128
88
91
  end
89
- return nil unless beforefact
90
- return nil if beforefact.empty?
92
+ return nil if beforefact.nil? || beforefact.empty?
91
93
 
92
94
  # 6. Rewrite headers of the original message in the body part
93
95
  %w|ds catch rfc822|.each { |e| thing[e] = beforefact[e] }
@@ -109,8 +111,7 @@ module Sisimai
109
111
  email.gsub!(/\r\n/, "\n") if email.include?("\r\n")
110
112
 
111
113
  (parts[1], parts[2]) = email.split(/\n\n/, 2)
112
- return nil unless parts[1]
113
- return nil unless parts[2]
114
+ return nil if parts[1].nil? || parts[2].nil?
114
115
 
115
116
  if parts[1].start_with?('From ')
116
117
  # From MAILER-DAEMON Tue Feb 11 00:00:00 2014
@@ -119,7 +120,7 @@ module Sisimai
119
120
  # Set pseudo UNIX From line
120
121
  parts[0] = 'MAILER-DAEMON Tue Feb 11 00:00:00 2014'
121
122
  end
122
- parts[1] += "\n" unless parts[1].end_with?("\n")
123
+ parts[1] += "\n" if parts[1].end_with?("\n") == false
123
124
 
124
125
  %w[image/ application/ text/html].each do |e|
125
126
  # https://github.com/sisimai/p5-sisimai/issues/492, Reduce email size
@@ -128,8 +129,8 @@ module Sisimai
128
129
  ep = e == 'text/html' ? '</html>' : "--\n"
129
130
  while true
130
131
  # Remove each part from "Content-Type: image/..." to "--\n" (the end of each boundary)
131
- p0 = parts[2].index("Content-Type: #{e}", p0); break unless p0
132
- p1 = parts[2].index(ep, p0 + 32); break unless p1
132
+ p0 = parts[2].index("Content-Type: #{e}", p0); break if p0.nil?
133
+ p1 = parts[2].index(ep, p0 + 32); break if p1.nil?
133
134
  parts[2][p0, p1 - p0] = ''
134
135
  end
135
136
  end
@@ -170,8 +171,7 @@ module Sisimai
170
171
  end
171
172
  headermaps['received'] = receivedby
172
173
 
173
- return headermaps unless argv1
174
- return headermaps if headermaps['subject'].empty?
174
+ return headermaps if argv1.nil? || headermaps['subject'].empty?
175
175
 
176
176
  # Convert MIME-Encoded subject
177
177
  if Sisimai::String.is_8bit(headermaps['subject'])
@@ -209,7 +209,7 @@ module Sisimai
209
209
  # Find and tidy up fields defined in RFC5322, RFC1894, and RFC5965
210
210
  # 1. Find a field label defined in RFC5322, RFC1894, or RFC5965 from this line
211
211
  p0 = e.index(':') || -1
212
- cf = e.downcase[0, p0]
212
+ cf = e.downcase[0, p0].to_s.rstrip
213
213
  fn = FieldTable[cf] || ''
214
214
 
215
215
  index += 1
@@ -227,7 +227,7 @@ module Sisimai
227
227
  # Such as Diagnostic-Code, Remote-MTA, and so on
228
228
  # - Before: Diagnostic-Code: SMTP;550 User unknown
229
229
  # - After: Diagnostic-Code: smtp; 550 User unknown
230
- break unless ['Content-Type'].concat(Fields1894).any? { |a| a == fn }
230
+ break if ['Content-Type'].concat(Fields1894).none? { |a| a == fn }
231
231
 
232
232
  if p1
233
233
  # The field including one or more ";"
@@ -251,7 +251,8 @@ module Sisimai
251
251
  ps = f[0, p2].downcase
252
252
  f[0, p2] = ps
253
253
  end
254
- f.downcase! unless ps == 'boundary'
254
+ f.downcase! if ps != 'boundary'
255
+ f = 'rfc822' if f == 'rfc/822'
255
256
  break
256
257
  end
257
258
  ab << f
@@ -261,9 +262,9 @@ module Sisimai
261
262
  # Diagnostic-Code: x-unix;
262
263
  # /var/email/kijitora/Maildir/tmp/1000000000.A000000B00000.neko22:
263
264
  # Disk quota exceeded
264
- break unless fn == 'Diagnostic-Code'
265
- break unless ab.size == 1
266
- break unless lines[index + 1].start_with?(' ')
265
+ break if fn != 'Diagnostic-Code'
266
+ break if ab.size != 1
267
+ break if lines[index + 1].start_with?(' ') == false
267
268
 
268
269
  ab << ''
269
270
  break
@@ -281,9 +282,9 @@ module Sisimai
281
282
  end
282
283
 
283
284
  # 3. Tidy up a value, and a parameter of Content-Type: field
284
- if ReplacesAs.has_key?(fn)
285
+ if fn == "Content-Type"
285
286
  # Replace the value of "Content-Type" field
286
- ReplacesAs[fn].each do |f|
287
+ MediaTypes.each do |f|
287
288
  # - Before: Content-Type: message/xdelivery-status; ...
288
289
  # - After: Content-Type: message/delivery-status; ...
289
290
  p1 = bf.index(f[0]) || next
@@ -296,7 +297,9 @@ module Sisimai
296
297
  email += sprintf("%s: %s\n", fn, bf)
297
298
  end
298
299
 
299
- email += "\n" unless email.end_with?("\n\n")
300
+ # 5. Convert the lower-cased SMTP command to the upper-cased.
301
+ email = email.gsub("after end of data:", "after end of DATA:")
302
+ email += "\n" if email.end_with?("\n\n") == false
300
303
  return email
301
304
  end
302
305
 
@@ -311,14 +314,13 @@ module Sisimai
311
314
  # @param options argvs [Array] tryonfirst MTA module list to load on first
312
315
  # @return [Hash] Decoded and structured bounce mails
313
316
  def sift(argvs)
314
- return nil unless argvs['mail']
315
- return nil unless argvs['body']
317
+ return nil if argvs['mail'].nil? || argvs['body'].nil?
316
318
 
317
319
  mailheader = argvs['mail']['header']
318
320
  bodystring = argvs['body']
319
321
  hookmethod = argvs['hook'] || nil
320
322
  havecaught = nil
321
- return nil unless mailheader
323
+ return nil if mailheader.nil?
322
324
 
323
325
  # PRECHECK_EACH_HEADER:
324
326
  # Set empty string if the value is nil
@@ -351,7 +353,7 @@ module Sisimai
351
353
  # NOT text/plain
352
354
  # In case of Content-Type: multipart/*
353
355
  p = Sisimai::RFC2045.makeflat(mailheader['content-type'], bodystring)
354
- bodystring = p unless p.empty?
356
+ bodystring = p if p.empty? == false
355
357
  end
356
358
  bodystring = bodystring.scrub('?').delete("\r").gsub("\t", " ")
357
359
 
@@ -412,7 +414,7 @@ module Sisimai
412
414
  break # as of now, we have no sample email for coding this block
413
415
  end
414
416
  end
415
- return nil unless havesifted
417
+ return nil if havesifted.nil?
416
418
 
417
419
  havesifted['catch'] = havecaught
418
420
  modulename = modulename.sub(/\A.+::/, '')