sisimai 4.22.3 → 4.22.4

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of sisimai might be problematic. Click here for more details.

Files changed (130) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +1 -1
  3. data/Benchmarks.mk +54 -0
  4. data/ChangeLog.md +23 -2
  5. data/Developers.mk +42 -35
  6. data/Makefile +10 -0
  7. data/README-JA.md +13 -13
  8. data/README.md +14 -14
  9. data/lib/sisimai.rb +12 -18
  10. data/lib/sisimai/address.rb +64 -82
  11. data/lib/sisimai/arf.rb +27 -42
  12. data/lib/sisimai/bite/email.rb +2 -4
  13. data/lib/sisimai/bite/email/activehunter.rb +12 -17
  14. data/lib/sisimai/bite/email/amazonses.rb +30 -48
  15. data/lib/sisimai/bite/email/amazonworkmail.rb +20 -27
  16. data/lib/sisimai/bite/email/aol.rb +27 -35
  17. data/lib/sisimai/bite/email/apachejames.rb +17 -28
  18. data/lib/sisimai/bite/email/bigfoot.rb +20 -33
  19. data/lib/sisimai/bite/email/biglobe.rb +15 -24
  20. data/lib/sisimai/bite/email/courier.rb +37 -61
  21. data/lib/sisimai/bite/email/domino.rb +19 -28
  22. data/lib/sisimai/bite/email/einsundeins.rb +20 -34
  23. data/lib/sisimai/bite/email/exchange2003.rb +25 -43
  24. data/lib/sisimai/bite/email/exchange2007.rb +15 -23
  25. data/lib/sisimai/bite/email/exim.rb +101 -120
  26. data/lib/sisimai/bite/email/ezweb.rb +28 -44
  27. data/lib/sisimai/bite/email/facebook.rb +26 -37
  28. data/lib/sisimai/bite/email/fml.rb +11 -20
  29. data/lib/sisimai/bite/email/gmx.rb +17 -27
  30. data/lib/sisimai/bite/email/google.rb +19 -29
  31. data/lib/sisimai/bite/email/gsuite.rb +39 -48
  32. data/lib/sisimai/bite/email/imailserver.rb +25 -39
  33. data/lib/sisimai/bite/email/interscanmss.rb +19 -26
  34. data/lib/sisimai/bite/email/kddi.rb +20 -33
  35. data/lib/sisimai/bite/email/mailfoundry.rb +14 -24
  36. data/lib/sisimai/bite/email/mailmarshalsmtp.rb +15 -24
  37. data/lib/sisimai/bite/email/mailru.rb +40 -59
  38. data/lib/sisimai/bite/email/mcafee.rb +21 -35
  39. data/lib/sisimai/bite/email/messagelabs.rb +23 -38
  40. data/lib/sisimai/bite/email/messagingserver.rb +15 -27
  41. data/lib/sisimai/bite/email/mfilter.rb +19 -28
  42. data/lib/sisimai/bite/email/mxlogic.rb +31 -49
  43. data/lib/sisimai/bite/email/notes.rb +16 -24
  44. data/lib/sisimai/bite/email/office365.rb +29 -38
  45. data/lib/sisimai/bite/email/opensmtpd.rb +50 -67
  46. data/lib/sisimai/bite/email/outlook.rb +24 -36
  47. data/lib/sisimai/bite/email/postfix.rb +33 -42
  48. data/lib/sisimai/bite/email/qmail.rb +44 -59
  49. data/lib/sisimai/bite/email/receivingses.rb +28 -36
  50. data/lib/sisimai/bite/email/sendgrid.rb +28 -37
  51. data/lib/sisimai/bite/email/sendmail.rb +35 -51
  52. data/lib/sisimai/bite/email/surfcontrol.rb +17 -25
  53. data/lib/sisimai/bite/email/userdefined.rb +17 -28
  54. data/lib/sisimai/bite/email/v5sendmail.rb +32 -41
  55. data/lib/sisimai/bite/email/verizon.rb +31 -56
  56. data/lib/sisimai/bite/email/x1.rb +11 -18
  57. data/lib/sisimai/bite/email/x2.rb +11 -23
  58. data/lib/sisimai/bite/email/x3.rb +10 -19
  59. data/lib/sisimai/bite/email/x4.rb +46 -65
  60. data/lib/sisimai/bite/email/x5.rb +26 -37
  61. data/lib/sisimai/bite/email/yahoo.rb +11 -19
  62. data/lib/sisimai/bite/email/yandex.rb +19 -30
  63. data/lib/sisimai/bite/email/zoho.rb +21 -30
  64. data/lib/sisimai/bite/json.rb +1 -2
  65. data/lib/sisimai/bite/json/amazonses.rb +20 -25
  66. data/lib/sisimai/bite/json/sendgrid.rb +1 -1
  67. data/lib/sisimai/data.rb +36 -55
  68. data/lib/sisimai/data/json.rb +3 -3
  69. data/lib/sisimai/data/yaml.rb +1 -1
  70. data/lib/sisimai/datetime.rb +5 -21
  71. data/lib/sisimai/mail.rb +4 -6
  72. data/lib/sisimai/mail/maildir.rb +1 -1
  73. data/lib/sisimai/mda.rb +41 -44
  74. data/lib/sisimai/message.rb +2 -3
  75. data/lib/sisimai/message/email.rb +42 -52
  76. data/lib/sisimai/message/json.rb +7 -7
  77. data/lib/sisimai/mime.rb +25 -23
  78. data/lib/sisimai/order/email.rb +2 -2
  79. data/lib/sisimai/order/json.rb +2 -7
  80. data/lib/sisimai/reason.rb +41 -46
  81. data/lib/sisimai/reason/blocked.rb +60 -71
  82. data/lib/sisimai/reason/contenterror.rb +4 -8
  83. data/lib/sisimai/reason/delivered.rb +1 -3
  84. data/lib/sisimai/reason/exceedlimit.rb +10 -20
  85. data/lib/sisimai/reason/expired.rb +5 -9
  86. data/lib/sisimai/reason/feedback.rb +1 -3
  87. data/lib/sisimai/reason/filtered.rb +19 -38
  88. data/lib/sisimai/reason/hasmoved.rb +5 -8
  89. data/lib/sisimai/reason/hostunknown.rb +11 -18
  90. data/lib/sisimai/reason/mailboxfull.rb +14 -24
  91. data/lib/sisimai/reason/mailererror.rb +3 -5
  92. data/lib/sisimai/reason/mesgtoobig.rb +15 -25
  93. data/lib/sisimai/reason/networkerror.rb +8 -10
  94. data/lib/sisimai/reason/norelaying.rb +9 -14
  95. data/lib/sisimai/reason/notaccept.rb +9 -21
  96. data/lib/sisimai/reason/onhold.rb +3 -8
  97. data/lib/sisimai/reason/policyviolation.rb +8 -10
  98. data/lib/sisimai/reason/rejected.rb +36 -49
  99. data/lib/sisimai/reason/securityerror.rb +11 -13
  100. data/lib/sisimai/reason/spamdetected.rb +23 -37
  101. data/lib/sisimai/reason/suspend.rb +9 -10
  102. data/lib/sisimai/reason/syntaxerror.rb +3 -4
  103. data/lib/sisimai/reason/systemerror.rb +7 -9
  104. data/lib/sisimai/reason/systemfull.rb +2 -4
  105. data/lib/sisimai/reason/toomanyconn.rb +17 -30
  106. data/lib/sisimai/reason/undefined.rb +1 -3
  107. data/lib/sisimai/reason/userunknown.rb +28 -38
  108. data/lib/sisimai/reason/vacation.rb +4 -6
  109. data/lib/sisimai/reason/virusdetected.rb +4 -6
  110. data/lib/sisimai/rfc2606.rb +1 -2
  111. data/lib/sisimai/rfc3464.rb +87 -101
  112. data/lib/sisimai/rfc3834.rb +29 -39
  113. data/lib/sisimai/rfc5322.rb +17 -24
  114. data/lib/sisimai/rhost.rb +10 -7
  115. data/lib/sisimai/rhost/exchangeonline.rb +124 -255
  116. data/lib/sisimai/rhost/franceptt.rb +2 -2
  117. data/lib/sisimai/rhost/godaddy.rb +12 -25
  118. data/lib/sisimai/rhost/googleapps.rb +82 -183
  119. data/lib/sisimai/smtp.rb +4 -4
  120. data/lib/sisimai/smtp/error.rb +8 -8
  121. data/lib/sisimai/smtp/reply.rb +1 -1
  122. data/lib/sisimai/smtp/status.rb +1 -0
  123. data/lib/sisimai/string.rb +5 -7
  124. data/lib/sisimai/version.rb +1 -1
  125. data/set-of-emails/README.md +1 -1
  126. data/set-of-emails/maildir/bsd/README.md +50 -50
  127. data/sisimai-java.gemspec +1 -1
  128. data/sisimai.gemspec +1 -1
  129. metadata +5 -5
  130. data/lib/sisimai/skeleton.rb +0 -43
@@ -6,15 +6,11 @@ module Sisimai::Bite::Email
6
6
  # Imported from p5-Sisimail/lib/Sisimai/Bite/Email/Yandex.pm
7
7
  require 'sisimai/bite/email'
8
8
 
9
- Re0 = {
10
- :from => %r/\Amailer-daemon[@]yandex[.]ru\z/,
11
- }.freeze
12
- Re1 = {
13
- :begin => %r/\AThis is the mail system at host yandex[.]ru[.]/,
14
- :rfc822 => %r|\AContent-Type: message/rfc822|,
15
- :endof => %r/\A__END_OF_EMAIL_MESSAGE__\z/,
16
- }.freeze
17
9
  Indicators = Sisimai::Bite::Email.INDICATORS
10
+ StartingOf = {
11
+ message: ['This is the mail system at host yandex.ru.'],
12
+ rfc822: ['Content-Type: message/rfc822'],
13
+ }.freeze
18
14
 
19
15
  def description; return 'Yandex.Mail: http://www.yandex.ru'; end
20
16
  def smtpagent; return Sisimai::Bite.smtpagent(self); end
@@ -27,7 +23,6 @@ module Sisimai::Bite::Email
27
23
  # X-Yandex-Queue-ID: 367D79E130D
28
24
  # X-Yandex-Sender: rfc822; shironeko@yandex.example.com
29
25
  def headerlist; return ['X-Yandex-Uniq']; end
30
- def pattern; return Re0; end
31
26
 
32
27
  # Parse bounce messages from Yandex.Mail
33
28
  # @param [Hash] mhead Message headers of a bounce email
@@ -44,7 +39,7 @@ module Sisimai::Bite::Email
44
39
  return nil unless mhead
45
40
  return nil unless mbody
46
41
  return nil unless mhead['x-yandex-uniq']
47
- return nil unless mhead['from'] =~ Re0[:from]
42
+ return nil unless mhead['from'] == 'mailer-daemon@yandex.ru'
48
43
 
49
44
  dscontents = [Sisimai::Bite.DELIVERYSTATUS]
50
45
  hasdivided = mbody.split("\n")
@@ -61,14 +56,14 @@ module Sisimai::Bite::Email
61
56
  }
62
57
  v = nil
63
58
 
64
- hasdivided.each do |e|
59
+ while e = hasdivided.shift do
65
60
  # Save the current line for the next loop
66
61
  havepassed << e
67
62
  p = havepassed[-2]
68
63
 
69
64
  if readcursor.zero?
70
65
  # Beginning of the bounce message or delivery status part
71
- if e =~ Re1[:begin]
66
+ if e.start_with?(StartingOf[:message][0])
72
67
  readcursor |= Indicators[:deliverystatus]
73
68
  next
74
69
  end
@@ -76,7 +71,7 @@ module Sisimai::Bite::Email
76
71
 
77
72
  if (readcursor & Indicators[:'message-rfc822']).zero?
78
73
  # Beginning of the original message part
79
- if e =~ Re1[:rfc822]
74
+ if e.start_with?(StartingOf[:rfc822][0])
80
75
  readcursor |= Indicators[:'message-rfc822']
81
76
  next
82
77
  end
@@ -90,7 +85,6 @@ module Sisimai::Bite::Email
90
85
  next
91
86
  end
92
87
  rfc822list << e
93
-
94
88
  else
95
89
  # Before "message/rfc822"
96
90
  next if (readcursor & Indicators[:deliverystatus]).zero?
@@ -109,7 +103,7 @@ module Sisimai::Bite::Email
109
103
  # Content-Type: message/rfc822
110
104
  v = dscontents[-1]
111
105
 
112
- if cv = e.match(/\A[Ff]inal-[Rr]ecipient:[ ]*(?:RFC|rfc)822;[ ]*([^ ]+)\z/)
106
+ if cv = e.match(/\AFinal-Recipient:[ ]*(?:RFC|rfc)822;[ ]*([^ ]+)\z/)
113
107
  # Final-Recipient: rfc822; kijitora@example.jp
114
108
  if v['recipient']
115
109
  # There are multiple recipient addresses in the message body.
@@ -119,33 +113,30 @@ module Sisimai::Bite::Email
119
113
  v['recipient'] = cv[1]
120
114
  recipients += 1
121
115
 
122
- elsif cv = e.match(/\A[Aa]ction:[ ]*(.+)\z/)
116
+ elsif cv = e.match(/\AAction:[ ]*(.+)\z/)
123
117
  # Action: failed
124
118
  v['action'] = cv[1]
125
119
 
126
- elsif cv = e.match(/\A[Ss]tatus:[ ]*(\d[.]\d+[.]\d+)/)
120
+ elsif cv = e.match(/\AStatus:[ ]*(\d[.]\d+[.]\d+)/)
127
121
  # Status:5.2.0
128
122
  v['status'] = cv[1]
129
123
 
130
- elsif cv = e.match(/\A[Rr]emote-MTA:[ ]*(?:DNS|dns);[ ]*(.+)\z/)
124
+ elsif cv = e.match(/\ARemote-MTA:[ ]*(?:DNS|dns);[ ]*(.+)\z/)
131
125
  # Remote-MTA: DNS; mx.example.jp
132
126
  v['rhost'] = cv[1].downcase
133
-
134
127
  else
135
128
  # Get error message
136
- if cv = e.match(/\A[Dd]iagnostic-[Cc]ode:[ ]*(.+?);[ ]*(.+)\z/)
129
+ if cv = e.match(/\ADiagnostic-Code:[ ]*(.+?);[ ]*(.+)\z/)
137
130
  # Diagnostic-Code: SMTP; 550 5.1.1 <userunknown@example.jp>... User Unknown
138
131
  v['spec'] = cv[1].upcase
139
132
  v['diagnosis'] = cv[2]
140
133
 
141
- elsif p =~ /\A[Dd]iagnostic-[Cc]ode:[ ]*/ && cv = e.match(/\A[ \t]+(.+)\z/)
134
+ elsif p.start_with?('Diagnostic-Code:') && cv = e.match(/\A[ \t]+(.+)\z/)
142
135
  # Continued line of the value of Diagnostic-Code header
143
- v['diagnosis'] ||= ''
144
- v['diagnosis'] += ' ' + cv[1]
145
- havepassed[-1] = 'Diagnostic-Code: ' + e
136
+ v['diagnosis'] << ' ' << cv[1]
137
+ havepassed[-1] = 'Diagnostic-Code: ' << e
146
138
  end
147
139
  end
148
-
149
140
  else
150
141
  # Content-Type: message/delivery-status
151
142
  #
@@ -153,18 +144,17 @@ module Sisimai::Bite::Email
153
144
  # X-Yandex-Queue-ID: 367D79E130D
154
145
  # X-Yandex-Sender: rfc822; shironeko@yandex.example.com
155
146
  # Arrival-Date: Sat, 6 Dec 2014 20:12:27 +0300 (MSK)
156
- if cv = e.match(/\A[Rr]eporting-MTA:[ ]*(?:DNS|dns);[ ]*(.+)\z/)
147
+ if cv = e.match(/\AReporting-MTA:[ ]*(?:DNS|dns);[ ]*(.+)\z/)
157
148
  # Reporting-MTA: dns; mx.example.jp
158
149
  next if connheader['lhost'].size > 0
159
150
  connheader['lhost'] = cv[1].downcase
160
151
  connvalues += 1
161
152
 
162
- elsif cv = e.match(/\A[Aa]rrival-[Dd]ate:[ ]*(.+)\z/)
153
+ elsif cv = e.match(/\AArrival-Date:[ ]*(.+)\z/)
163
154
  # Arrival-Date: Wed, 29 Apr 2009 16:03:18 +0900
164
155
  next if connheader['date'].size > 0
165
156
  connheader['date'] = cv[1]
166
157
  connvalues += 1
167
-
168
158
  else
169
159
  # <kijitora@example.jp>: host mx.example.jp[192.0.2.153] said: 550
170
160
  # 5.1.1 <kijitora@example.jp>... User Unknown (in reply to RCPT TO
@@ -179,12 +169,11 @@ module Sisimai::Bite::Email
179
169
  end
180
170
  end
181
171
  end
182
-
183
172
  end
184
173
  end
185
174
  return nil if recipients.zero?
186
- require 'sisimai/string'
187
175
 
176
+ require 'sisimai/string'
188
177
  dscontents.map do |e|
189
178
  # Set default values if each value is empty.
190
179
  connheader.each_key { |a| e[a] ||= connheader[a] || '' }
@@ -6,24 +6,12 @@ module Sisimai::Bite::Email
6
6
  # Imported from p5-Sisimail/lib/Sisimai/Bite/Email/Zoho.pm
7
7
  require 'sisimai/bite/email'
8
8
 
9
- Re0 = {
10
- :'from' => %r/mailer-daemon[@]mail[.]zoho[.]com\z/,
11
- :'subject' => %r{\A(?:
12
- Undelivered[ ]Mail[ ]Returned[ ]to[ ]Sender
13
- |Mail[ ]Delivery[ ]Status[ ]Notification
14
- )
15
- }x,
16
- :'x-mailer' => %r/\AZoho Mail\z/,
17
- }.freeze
18
- Re1 = {
19
- :begin => %r/\AThis message was created automatically by mail delivery/,
20
- :rfc822 => %r/\AReceived:[ \t]*from mail[.]zoho[.]com/,
21
- :endof => %r/\A__END_OF_EMAIL_MESSAGE__\z/,
22
- }.freeze
23
- ReFailure = {
24
- expired: %r/Host not reachable/
25
- }.freeze
26
9
  Indicators = Sisimai::Bite::Email.INDICATORS
10
+ StartingOf = {
11
+ message: ['This message was created automatically by mail delivery'],
12
+ rfc822: ['from mail.zoho.com by mx.zohomail.com'],
13
+ }.freeze
14
+ ReFailures = { expired: %r/Host not reachable/ }.freeze
27
15
 
28
16
  def description; return 'Zoho Mail: https://www.zoho.com'; end
29
17
  def smtpagent; return Sisimai::Bite.smtpagent(self); end
@@ -32,7 +20,6 @@ module Sisimai::Bite::Email
32
20
  # X-Zoho-Virus-Status: 2
33
21
  # X-Mailer: Zoho Mail
34
22
  def headerlist; return ['X-ZohoMail']; end
35
- def pattern; return Re0; end
36
23
 
37
24
  # Parse bounce messages from Zoho Mail
38
25
  # @param [Hash] mhead Message headers of a bounce email
@@ -48,6 +35,14 @@ module Sisimai::Bite::Email
48
35
  def scan(mhead, mbody)
49
36
  return nil unless mhead
50
37
  return nil unless mbody
38
+
39
+ # :'from' => %r/mailer-daemon[@]mail[.]zoho[.]com\z/,
40
+ # :'subject' => %r{\A(?:
41
+ # Undelivered[ ]Mail[ ]Returned[ ]to[ ]Sender
42
+ # |Mail[ ]Delivery[ ]Status[ ]Notification
43
+ # )
44
+ # }x,
45
+ # :'x-mailer' => %r/\AZoho Mail\z/,
51
46
  return nil unless mhead['x-zohomail']
52
47
 
53
48
  dscontents = [Sisimai::Bite.DELIVERYSTATUS]
@@ -59,10 +54,10 @@ module Sisimai::Bite::Email
59
54
  qprintable = false
60
55
  v = nil
61
56
 
62
- hasdivided.each do |e|
57
+ while e = hasdivided.shift do
63
58
  if readcursor.zero?
64
59
  # Beginning of the bounce message or delivery status part
65
- if e =~ Re1[:begin]
60
+ if e.start_with?(StartingOf[:message][0])
66
61
  readcursor |= Indicators[:deliverystatus]
67
62
  next
68
63
  end
@@ -70,7 +65,7 @@ module Sisimai::Bite::Email
70
65
 
71
66
  if (readcursor & Indicators[:'message-rfc822']).zero?
72
67
  # Beginning of the original message part
73
- if e =~ Re1[:rfc822]
68
+ if e.include?(StartingOf[:rfc822][0])
74
69
  readcursor |= Indicators[:'message-rfc822']
75
70
  next
76
71
  end
@@ -84,7 +79,6 @@ module Sisimai::Bite::Email
84
79
  next
85
80
  end
86
81
  rfc822list << e
87
-
88
82
  else
89
83
  # Before "message/rfc822"
90
84
  next if (readcursor & Indicators[:deliverystatus]).zero?
@@ -115,7 +109,7 @@ module Sisimai::Bite::Email
115
109
 
116
110
  if v['diagnosis'].end_with?('=')
117
111
  # Quoted printable
118
- v['diagnosis'] = v['diagnosis'].sub(/=\z/, '')
112
+ v['diagnosis'] = v['diagnosis'].chomp('=')
119
113
  qprintable = true
120
114
  end
121
115
  recipients += 1
@@ -131,27 +125,24 @@ module Sisimai::Bite::Email
131
125
  v['recipient'] = cv[1]
132
126
  v['diagnosis'] = e
133
127
  recipients += 1
134
-
135
128
  else
136
129
  # Continued line
137
130
  next unless qprintable
138
- v['diagnosis'] ||= ''
139
- v['diagnosis'] += e
140
-
131
+ v['diagnosis'] << e
141
132
  end
142
133
  end
143
134
  end
144
135
  return nil if recipients.zero?
145
- require 'sisimai/string'
146
136
 
137
+ require 'sisimai/string'
147
138
  dscontents.map do |e|
148
139
  e['agent'] = self.smtpagent
149
140
  e['diagnosis'] = e['diagnosis'].gsub(/\\n/, ' ')
150
141
  e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'])
151
142
 
152
- ReFailure.each_key do |r|
143
+ ReFailures.each_key do |r|
153
144
  # Verify each regular expression of session errors
154
- next unless e['diagnosis'] =~ ReFailure[r]
145
+ next unless e['diagnosis'] =~ ReFailures[r]
155
146
  e['reason'] = r.to_s
156
147
  break
157
148
  end
@@ -7,12 +7,11 @@ module Sisimai
7
7
  require 'sisimai/bite'
8
8
 
9
9
  def headerlist; return []; end
10
- def pattern; return []; end
11
10
 
12
11
  # MTA list
13
12
  # @return [Array] MTA list with order
14
13
  def index
15
- return %w|SendGrid AmazonSES|
14
+ return %w[SendGrid AmazonSES]
16
15
  end
17
16
 
18
17
  # Convert from JSON object to Sisimai::Message
@@ -49,47 +49,45 @@ module Sisimai::Bite::JSON
49
49
  jsonthings = nil
50
50
  foldedline = false
51
51
 
52
- hasdivided.each do |e|
52
+ while e = hasdivided.shift do
53
53
  # Find JSON string from the message body
54
54
  next if e.size.zero?
55
- break if e =~ /\A[-]{2}\z/
55
+ break if e == '--'
56
56
  break if e == '__END_OF_EMAIL_MESSAGE__'
57
57
 
58
58
  # The line starts with " ", continued from !\n.
59
- e = e.sub(/\A[ ]/, '') if foldedline
59
+ e = e.lstrip if foldedline
60
60
  foldedline = false
61
61
 
62
- if e =~ /[!]\z/
62
+ if e.end_with?('!')
63
63
  # ... long long line ...![\n]
64
- e = e.sub(/!\z/, '')
64
+ e = e.chomp('!')
65
65
  foldedline = true
66
66
  end
67
- jsonstring += e
67
+ jsonstring << e
68
68
  end
69
69
 
70
70
  begin
71
- if RUBY_PLATFORM =~ /java/
71
+ if RUBY_PLATFORM.include?('java')
72
72
  # java-based ruby environment like JRuby.
73
73
  require 'jrjackson'
74
74
  jsonobject = JrJackson::Json.load(jsonstring)
75
- if jsonobject['Message']
76
- # 'Message' => '{"notificationType":"Bounce",...
77
- jsonthings = JrJackson::Json.load(jsonobject['Message'])
78
- end
75
+
76
+ # 'Message' => '{"notificationType":"Bounce",...
77
+ jsonthings = JrJackson::Json.load(jsonobject['Message']) if jsonobject['Message']
79
78
  else
80
79
  # Matz' Ruby Implementation
81
80
  require 'oj'
82
81
  jsonobject = Oj.load(jsonstring)
83
- if jsonobject['Message']
84
- # 'Message' => '{"notificationType":"Bounce",...
85
- jsonthings = Oj.load(jsonobject['Message'])
86
- end
82
+
83
+ # 'Message' => '{"notificationType":"Bounce",...
84
+ jsonthings = Oj.load(jsonobject['Message']) if jsonobject['Message']
87
85
  end
88
86
  jsonthings ||= jsonobject
89
87
 
90
88
  rescue StandardError => ce
91
89
  # Something wrong in decoding JSON
92
- warn sprintf(' ***warning: Failed to decode JSON: %s', ce.to_s)
90
+ warn ' ***warning: Failed to decode JSON: ' << ce.to_s
93
91
  return nil
94
92
  end
95
93
 
@@ -117,12 +115,12 @@ module Sisimai::Bite::JSON
117
115
  }
118
116
  v = nil
119
117
 
120
- if argvs['notificationType'] =~ /\A(?:Bounce|Complaint)\z/
118
+ if %w[Bounce Complaint].index(argvs['notificationType'])
121
119
  # { "notificationType":"Bounce", "bounce": { "bounceType":"Permanent",...
122
- o = argvs[argvs['notificationType'].downcase]
120
+ o = argvs[argvs['notificationType'].downcase].dup
123
121
  r = o[labeltable[argvs['notificationType'].to_sym]] || []
124
122
 
125
- r.each do |e|
123
+ while e = r.shift do
126
124
  # 'bouncedRecipients' => [ { 'emailAddress' => 'bounce@si...' }, ... ]
127
125
  # 'complainedRecipients' => [ { 'emailAddress' => 'complaint@si...' }, ... ]
128
126
  next unless Sisimai::RFC5322.is_emailaddress(e['emailAddress'])
@@ -167,7 +165,6 @@ module Sisimai::Bite::JSON
167
165
  # },
168
166
  v['reason'] = BounceType[o['bounceType'].to_sym][o['bounceSubType'].to_sym]
169
167
  end
170
-
171
168
  else
172
169
  # 'complainedRecipients' => [ {
173
170
  # 'emailAddress' => 'complaint@simulator.amazonses.com' }, ... ],
@@ -178,16 +175,15 @@ module Sisimai::Bite::JSON
178
175
  v['date'] = o['timestamp'] || argvs['mail']['timestamp']
179
176
  v['date'] = v['date'].sub(/[.]\d+Z\z/, '')
180
177
  end
181
-
182
178
  elsif argvs['notificationType'] == 'Delivery'
183
179
  # { "notificationType":"Delivery", "delivery": { ...
184
180
  require 'sisimai/smtp/status'
185
181
  require 'sisimai/smtp/reply'
186
182
 
187
- o = argvs['delivery']
183
+ o = argvs['delivery'].dup
188
184
  r = o['recipients'] || []
189
185
 
190
- r.each do |e|
186
+ while e = r.shift do
191
187
  # 'delivery' => {
192
188
  # 'timestamp' => '2016-11-23T12:01:03.512Z',
193
189
  # 'processingTimeMillis' => 3982,
@@ -217,7 +213,6 @@ module Sisimai::Bite::JSON
217
213
  v['date'] = o['timestamp'] || argvs['mail']['timestamp']
218
214
  v['date'] = v['date'].sub(/[.]\d+Z\z/, '')
219
215
  end
220
-
221
216
  else
222
217
  # The value of "notificationType" is not any of "Bounce", "Complaint",
223
218
  # or "Delivery".
@@ -234,7 +229,7 @@ module Sisimai::Bite::JSON
234
229
  # "headers":[ { ...
235
230
  argvs['mail']['headers'].each do |e|
236
231
  # 'headers' => [ { 'name' => 'From', 'value' => 'neko@nyaan.jp' }, ... ],
237
- next unless e['name'] =~ /\A(?:From|To|Subject|Message-ID|Date)\z/
232
+ next unless %w[From To Subject Message-ID Date].index(e['name'])
238
233
  rfc822head[e['name'].downcase] = e['value']
239
234
  end
240
235
  end
@@ -46,7 +46,7 @@ module Sisimai::Bite::JSON
46
46
  # 'smtp-id' => '<201709042010.v84KAQ5T032530@example.nyaan.jp>',
47
47
  # 'status' => '5.2.2'
48
48
  # },
49
- return nil unless argvs['event'] =~ /\A(?:bounce|deferred|delivered|spamreport)\z/
49
+ return nil unless %w[bounce deferred delivered spamreport].include?(argvs['event'])
50
50
  dscontents = [Sisimai::Bite.DELIVERYSTATUS]
51
51
  diagnostic = argvs['reason'] || ''
52
52
  diagnostic = argvs['response'] || '' if diagnostic.empty?
@@ -44,15 +44,8 @@ module Sisimai
44
44
  EndOfEmail = Sisimai::String.EOM
45
45
  RetryIndex = Sisimai::Reason.retry
46
46
  RFC822Head = Sisimai::RFC5322.HEADERFIELDS(:all)
47
- AddrHeader = {
48
- addresser: RFC822Head[:addresser],
49
- recipient: RFC822Head[:recipient],
50
- }.freeze
51
- ActionList = %r/\A(?:failed|delayed|delivered|relayed|expanded)\z/
52
- ActionHead = {
53
- %r/\Afailure\z/ => 'failed',
54
- %r/\Aexpired\z/ => 'delayed',
55
- }.freeze
47
+ AddrHeader = { addresser: RFC822Head[:addresser], recipient: RFC822Head[:recipient] }.freeze
48
+ ActionHead = { failure: 'failed', expired: 'delayed' }.freeze
56
49
 
57
50
  # Constructor of Sisimai::Data
58
51
  # @param [Hash] argvs Data
@@ -64,7 +57,6 @@ module Sisimai
64
57
 
65
58
  return nil unless as.is_a? Sisimai::Address
66
59
  return nil unless ar.is_a? Sisimai::Address
67
-
68
60
  return nil if as.void
69
61
  return nil if ar.void
70
62
 
@@ -110,7 +102,6 @@ module Sisimai
110
102
  rfc822data = messageobj.rfc822
111
103
  fieldorder = { :recipient => [], :addresser => [] }
112
104
  objectlist = []
113
- rxcommands = %r/\A(?:EHLO|HELO|MAIL|RCPT|DATA|QUIT)\z/
114
105
  givenorder = argvs[:order] || {}
115
106
  delivered1 = argvs[:delivered] || false
116
107
 
@@ -133,10 +124,10 @@ module Sisimai
133
124
 
134
125
  fieldorder.each_key do |e|
135
126
  # If the order is empty, use default order.
136
- if fieldorder[e].empty?
137
- # Load default order of each accessor.
138
- fieldorder[e] = AddrHeader[e]
139
- end
127
+ next if fieldorder[e].size > 0
128
+
129
+ # Load default order of each accessor.
130
+ fieldorder[e] = AddrHeader[e]
140
131
  end
141
132
 
142
133
  messageobj.ds.each do |e|
@@ -160,7 +151,7 @@ module Sisimai
160
151
  }
161
152
  unless delivered1
162
153
  # Skip if the value of "deliverystatus" begins with "2." such as 2.1.5
163
- next if p['deliverystatus'] =~ /\A2[.]/
154
+ next if p['deliverystatus'].start_with?('2.')
164
155
  end
165
156
 
166
157
  # EMAIL_ADDRESS:
@@ -191,9 +182,7 @@ module Sisimai
191
182
  datestring = nil
192
183
  zoneoffset = 0
193
184
  datevalues = []
194
- if e['date'] && e['date'].size > 0
195
- datevalues << e['date']
196
- end
185
+ datevalues << e['date'] if e['date'].to_s.size > 0
197
186
 
198
187
  # Date information did not exist in message/delivery-status part,...
199
188
  RFC822Head[:date].each do |f|
@@ -202,12 +191,10 @@ module Sisimai
202
191
  datevalues << rfc822data[f.downcase]
203
192
  end
204
193
 
205
- if datevalues.size < 2
206
- # Set "date" getting from the value of "Date" in the bounce message
207
- datevalues << messageobj.header['date']
208
- end
194
+ # Set "date" getting from the value of "Date" in the bounce message
195
+ datevalues << messageobj.header['date'] if datevalues.size < 2
209
196
 
210
- datevalues.each do |v|
197
+ while v = datevalues.shift do
211
198
  # Parse each date value in the array
212
199
  datestring = Sisimai::DateTime.parse(v)
213
200
  break if datestring
@@ -229,7 +216,7 @@ module Sisimai
229
216
  t = Sisimai::Time.strptime(datestring, '%a, %d %b %Y %T')
230
217
  p['timestamp'] = (t.to_time.to_i - zoneoffset) || nil
231
218
  rescue
232
- warn ' ***warning: Failed to strptime ' + datestring.to_s
219
+ warn ' ***warning: Failed to strptime ' << datestring.to_s
233
220
  end
234
221
  next unless p['timestamp']
235
222
 
@@ -237,27 +224,24 @@ module Sisimai
237
224
  recvheader = mailheader['received'] || []
238
225
  if recvheader.size > 0
239
226
  # Get localhost and remote host name from Received header.
240
- %w|lhost rhost|.each { |a| e[a] ||= '' }
227
+ %w[lhost rhost].each { |a| e[a] ||= '' }
241
228
  e['lhost'] = Sisimai::RFC5322.received(recvheader[0]).shift if e['lhost'].empty?
242
229
  e['rhost'] = Sisimai::RFC5322.received(recvheader[-1]).pop if e['rhost'].empty?
243
230
  end
244
231
 
245
232
  # Remove square brackets and curly brackets from the host variable
246
- %w|rhost lhost|.each do |v|
233
+ %w[rhost lhost].each do |v|
247
234
  p[v] = p[v].delete('[]()') # Remove square brackets and curly brackets from the host variable
248
235
  p[v] = p[v].sub(/\A.+=/, '') # Remove string before "="
249
- p[v] = p[v].gsub(/\r\z/, '') # Remove CR at the end of the value
236
+ p[v] = p[v].chomp("\r") # Remove CR at the end of the value
250
237
 
251
- # Check space character in each value
252
- if p[v] =~ / /
253
- # Get the first element
254
- p[v] = p[v].split(' ', 2).shift
255
- end
238
+ # Check space character in each value and get the first element
239
+ p[v] = p[v].split(' ', 2).shift if p[v].include?(' ')
256
240
  end
257
241
 
258
242
  # Subject: header of the original message
259
243
  p['subject'] = rfc822data['subject'] || ''
260
- p['subject'] = p['subject'].scrub('?').gsub(/\r\z/, '')
244
+ p['subject'] = p['subject'].scrub('?').chomp("\r")
261
245
 
262
246
  # The value of "List-Id" header
263
247
  p['listid'] = rfc822data['list-id'] || ''
@@ -268,8 +252,8 @@ module Sisimai
268
252
  p['listid'] = cv[1]
269
253
  end
270
254
  p['listid'] = p['listid'].delete('<>')
271
- p['listid'] = p['listid'].gsub(/\r\z/, '')
272
- p['listid'] = '' if p['listid'] =~ / /
255
+ p['listid'] = p['listid'].chomp("\r")
256
+ p['listid'] = '' if p['listid'].include?(' ')
273
257
  end
274
258
 
275
259
  # The value of "Message-Id" header
@@ -280,7 +264,7 @@ module Sisimai
280
264
  p['messageid'] = cv[1]
281
265
  end
282
266
  p['messageid'] = p['messageid'].delete('<>')
283
- p['messageid'] = p['messageid'].gsub(/\r\z/, '')
267
+ p['messageid'] = p['messageid'].chomp("\r")
284
268
  end
285
269
 
286
270
  # CHECK_DELIVERY_STATUS_VALUE:
@@ -320,10 +304,10 @@ module Sisimai
320
304
  end
321
305
  end
322
306
  p['diagnostictype'] ||= 'X-UNIX' if p['reason'] == 'mailererror'
323
- p['diagnostictype'] ||= 'SMTP' unless p['reason'] =~ /\A(?:feedback|vacation)\z/
307
+ p['diagnostictype'] ||= 'SMTP' unless %w[feedback vacation].index(p['reason'])
324
308
 
325
309
  # Check the value of SMTP command
326
- p['smtpcommand'] = '' unless p['smtpcommand'] =~ rxcommands
310
+ p['smtpcommand'] = '' unless %w[EHLO HELO MAIL RCPT DATA QUIT].index(p['smtpcommand'])
327
311
 
328
312
  # Check the value of "action"
329
313
  if p['action'].size > 0
@@ -332,11 +316,11 @@ module Sisimai
332
316
  p['action'] = cv[1]
333
317
  end
334
318
 
335
- unless p['action'] =~ ActionList
319
+ unless %w[failed delayed delivered relayed expanded].index(p['action'])
336
320
  # The value of "action" is not in the following values:
337
321
  # "failed" / "delayed" / "delivered" / "relayed" / "expanded"
338
322
  ActionHead.each_key do |q|
339
- next unless p['action'] =~ q
323
+ next unless p['action'] == q.to_s
340
324
  p['action'] = ActionHead[q]
341
325
  break
342
326
  end
@@ -345,7 +329,7 @@ module Sisimai
345
329
  if p['reason'] == 'expired'
346
330
  # Action: delayed
347
331
  p['action'] = 'delayed'
348
- elsif p['deliverystatus'] =~ /\A[45]/
332
+ elsif p['deliverystatus'].start_with?('5', '4')
349
333
  # Action: failed
350
334
  p['action'] = 'failed'
351
335
  end
@@ -357,16 +341,13 @@ module Sisimai
357
341
  if o.reason.empty? || RetryIndex.index(o.reason)
358
342
  # Decide the reason of email bounce
359
343
  r = ''
360
- if Sisimai::Rhost.match(o.rhost)
361
- # Remote host dependent error
362
- r = Sisimai::Rhost.get(o)
363
- end
344
+ r = Sisimai::Rhost.get(o) if Sisimai::Rhost.match(o.rhost) # Remote host dependent error
364
345
  r = Sisimai::Reason.get(o) if r.empty?
365
346
  r = 'undefined' if r.empty?
366
347
  o.reason = r
367
348
  end
368
349
 
369
- if o.reason =~ /\A(?:delivered|feedback|vacation)\z/
350
+ if %w[delivered feedback vacation].index(o.reason)
370
351
  # The value of reason is "vacation" or "feedback"
371
352
  o.softbounce = -1
372
353
  o.replycode = '' unless o.reason == 'delivered'
@@ -377,8 +358,8 @@ module Sisimai
377
358
 
378
359
  if o.softbounce.to_s.empty?
379
360
  # The value is not set yet
380
- textasargv = sprintf('%s %s', p['deliverystatus'], p['diagnosticcode'])
381
- textasargv = textasargv.gsub(/\A[ ]/, '')
361
+ textasargv = p['deliverystatus'] + ' ' + p['diagnosticcode']
362
+ textasargv = textasargv.lstrip
382
363
  softorhard = Sisimai::SMTP::Error.soft_or_hard(o.reason, textasargv)
383
364
 
384
365
  o.softbounce = if softorhard.size > 0
@@ -392,8 +373,8 @@ module Sisimai
392
373
 
393
374
  if o.deliverystatus.empty?
394
375
  # Set pseudo status code
395
- textasargv = sprintf('%s %s', o.replycode, p['diagnosticcode'])
396
- textasargv = textasargv.gsub(/\A[ ]/, '')
376
+ textasargv = o.replycode + ' ' + p['diagnosticcode']
377
+ textasargv = textasargv.lstrip
397
378
 
398
379
  getchecked = Sisimai::SMTP::Error.is_permanent(textasargv)
399
380
  tmpfailure = getchecked.nil? ? false : (getchecked ? false : true)
@@ -435,7 +416,7 @@ module Sisimai
435
416
  def damn
436
417
  data = {}
437
418
  @@rwaccessors.each do |e|
438
- next if e.to_s =~ /(?:addresser|recipient|timestamp)/
419
+ next if %w[addresser recipient timestamp].index(e.to_s)
439
420
  data[e.to_s] = self.send(e) || ''
440
421
  end
441
422
  data['addresser'] = self.addresser.address
@@ -450,13 +431,13 @@ module Sisimai
450
431
  # @return [String, Nil] Dumped data or nil if the value of the first
451
432
  # argument is neither "json" nor "yaml"
452
433
  def dump(type = 'json')
453
- return nil unless %w|json yaml|.index(type)
454
- referclass = sprintf('Sisimai::Data::%s', type.upcase)
434
+ return nil unless %w[json yaml].index(type)
435
+ referclass = 'Sisimai::Data::' << type.upcase
455
436
 
456
437
  begin
457
438
  require referclass.downcase.gsub('::', '/')
458
439
  rescue
459
- warn '***warning: Failed to load' + referclass
440
+ warn '***warning: Failed to load' << referclass
460
441
  end
461
442
 
462
443
  dumpeddata = Module.const_get(referclass).dump(self)