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,55 +6,42 @@ module Sisimai::Bite::Email
6
6
  # Imported from p5-Sisimail/lib/Sisimai/Bite/Email/Exim.pm
7
7
  require 'sisimai/bite/email'
8
8
 
9
- ReE = {
10
- :from => %r/[@].+[.]mail[.]ru[>]?/,
11
- }.freeze
12
- Re0 = {
13
- :from => %r/\AMail Delivery System/,
14
- :subject => %r{(?:
15
- Mail[ ]delivery[ ]failed(:[ ]returning[ ]message[ ]to[ ]sender)?
16
- |Warning:[ ]message[ ].+[ ]delayed[ ]+
17
- |Delivery[ ]Status[ ]Notification
18
- |Mail[ ]failure
19
- |Message[ ]frozen
20
- |error[(]s[)][ ]in[ ]forwarding[ ]or[ ]filtering
21
- )
22
- }x,
23
- # :'message-id' => %r/\A[<]\w+[-]\w+[-]\w+[@].+\z/,
24
- # Message-Id: <E1P1YNN-0003AD-Ga@example.org>
9
+ Indicators = Sisimai::Bite::Email.INDICATORS
10
+ StartingOf = {
11
+ deliverystatus: ['Content-type: message/delivery-status'],
12
+ endof: ['__END_OF_EMAIL_MESSAGE__'],
25
13
  }.freeze
26
-
27
- # Error text regular expressions which defined in exim/src/deliver.c
28
- #
29
- # deliver.c:6292| fprintf(f,
30
- # deliver.c:6293|"This message was created automatically by mail delivery software.\n");
31
- # deliver.c:6294| if (to_sender)
32
- # deliver.c:6295| {
33
- # deliver.c:6296| fprintf(f,
34
- # deliver.c:6297|"\nA message that you sent could not be delivered to one or more of its\n"
35
- # deliver.c:6298|"recipients. This is a permanent error. The following address(es) failed:\n");
36
- # deliver.c:6299| }
37
- # deliver.c:6300| else
38
- # deliver.c:6301| {
39
- # deliver.c:6302| fprintf(f,
40
- # deliver.c:6303|"\nA message sent by\n\n <%s>\n\n"
41
- # deliver.c:6304|"could not be delivered to one or more of its recipients. The following\n"
42
- # deliver.c:6305|"address(es) failed:\n", sender_address);
43
- # deliver.c:6306| }
44
- #
45
- # deliver.c:6423| if (bounce_return_body) fprintf(f,
46
- # deliver.c:6424|"------ This is a copy of the message, including all the headers. ------\n");
47
- # deliver.c:6425| else fprintf(f,
48
- # deliver.c:6426|"------ This is a copy of the message's headers. ------\n");
49
- Re1 = {
50
- :alias => %r/\A([ ]+an[ ]undisclosed[ ]address)\z/,
51
- :frozen => %r/\AMessage .+ (?:has been frozen|was frozen on arrival)/,
52
- :rfc822 => %r{\A(?:
14
+ MarkingsOf = {
15
+ # Error text regular expressions which defined in exim/src/deliver.c
16
+ #
17
+ # deliver.c:6292| fprintf(f,
18
+ # deliver.c:6293|"This message was created automatically by mail delivery software.\n");
19
+ # deliver.c:6294| if (to_sender)
20
+ # deliver.c:6295| {
21
+ # deliver.c:6296| fprintf(f,
22
+ # deliver.c:6297|"\nA message that you sent could not be delivered to one or more of its\n"
23
+ # deliver.c:6298|"recipients. This is a permanent error. The following address(es) failed:\n");
24
+ # deliver.c:6299| }
25
+ # deliver.c:6300| else
26
+ # deliver.c:6301| {
27
+ # deliver.c:6302| fprintf(f,
28
+ # deliver.c:6303|"\nA message sent by\n\n <%s>\n\n"
29
+ # deliver.c:6304|"could not be delivered to one or more of its recipients. The following\n"
30
+ # deliver.c:6305|"address(es) failed:\n", sender_address);
31
+ # deliver.c:6306| }
32
+ #
33
+ # deliver.c:6423| if (bounce_return_body) fprintf(f,
34
+ # deliver.c:6424|"------ This is a copy of the message, including all the headers. ------\n");
35
+ # deliver.c:6425| else fprintf(f,
36
+ # deliver.c:6426|"------ This is a copy of the message's headers. ------\n");
37
+ alias: %r/\A([ ]+an undisclosed address)\z/,
38
+ frozen: %r/\AMessage .+ (?:has been frozen|was frozen on arrival)/,
39
+ rfc822: %r{\A(?:
53
40
  [-]+[ ]This[ ]is[ ]a[ ]copy[ ]of[ ](?:the|your)[ ]message.+headers[.][ ][-]+
54
41
  |Content-Type:[ ]*message/rfc822
55
42
  )\z
56
43
  }x,
57
- :begin => %r{\A(?>
44
+ message: %r{\A(?>
58
45
  This[ ]message[ ]was[ ]created[ ]automatically[ ]by[ ]mail[ ]delivery[ ]software[.]
59
46
  |A[ ]message[ ]that[ ]you[ ]sent[ ]was[ ]rejected[ ]by[ ]the[ ]local[ ]scanning[ ]code
60
47
  |A[ ]message[ ]that[ ]you[ ]sent[ ]contained[ ]one[ ]or[ ]more[ ]recipient[ ]addresses[ ]
@@ -62,11 +49,9 @@ module Sisimai::Bite::Email
62
49
  |The[ ].+[ ]router[ ]encountered[ ]the[ ]following[ ]error[(]s[)]:
63
50
  )
64
51
  }x,
65
- :deliverystatus => %r|\AContent-type: message/delivery-status|,
66
- :endof => %r/\A__END_OF_EMAIL_MESSAGE__\z/,
67
52
  }.freeze
68
53
 
69
- ReCommand = [
54
+ ReCommands = [
70
55
  # transports/smtp.c:564| *message = US string_sprintf("SMTP error from remote mail server after %s%s: "
71
56
  # transports/smtp.c:837| string_sprintf("SMTP error from remote mail server after RCPT TO:<%s>: "
72
57
  %r/SMTP error from remote (?:mail server|mailer) after ([A-Za-z]{4})/,
@@ -74,11 +59,10 @@ module Sisimai::Bite::Email
74
59
  %r/LMTP error after ([A-Za-z]{4})/,
75
60
  %r/LMTP error after end of ([A-Za-z]{4})/,
76
61
  ].freeze
77
-
78
- # find exim/ -type f -exec grep 'message = US' {} /dev/null \;
79
- ReFailure = {
62
+ ReFailures = {
63
+ # find exim/ -type f -exec grep 'message = US' {} /dev/null \;
80
64
  # route.c:1158| DEBUG(D_uid) debug_printf("getpwnam() returned NULL (user not found)\n");
81
- userunknown: %r/user[ ]not[ ]found/x,
65
+ userunknown: %r/user not found/,
82
66
  # transports/smtp.c:3524| addr->message = US"all host address lookups failed permanently";
83
67
  # routers/dnslookup.c:331| addr->message = US"all relevant MX records point to non-existent hosts";
84
68
  # route.c:1826| uschar *message = US"Unrouteable address";
@@ -93,7 +77,7 @@ module Sisimai::Bite::Email
93
77
  # transports/appendfile.c:2567| addr->user_message = US"mailbox is full";
94
78
  # transports/appendfile.c:3049| addr->message = string_sprintf("mailbox is full "
95
79
  # transports/appendfile.c:3050| "(quota exceeded while writing to file %s)", filename);
96
- mailboxfull: %r/(?:mailbox[ ]is[ ]full:?|error:[ ]quota[ ]exceed)/x,
80
+ mailboxfull: %r/(?:mailbox is full:?|error: quota exceed)/,
97
81
  # routers/dnslookup.c:328| addr->message = US"an MX or SRV record indicated no SMTP service";
98
82
  # transports/smtp.c:3502| addr->message = US"no host found for existing SMTP connection";
99
83
  notaccept: %r{(?:
@@ -122,7 +106,7 @@ module Sisimai::Bite::Email
122
106
  )
123
107
  }x,
124
108
  # deliver.c:5425| new->message = US"Too many \"Received\" headers - suspected mail loop";
125
- contenterror: %r/Too[ ]many[ ]["]Received["][ ]headers/x,
109
+ contenterror: %r/Too many ["]Received["] headers/,
126
110
  }.freeze
127
111
 
128
112
  # retry.c:902| addr->message = (addr->message == NULL)? US"retry timeout exceeded" :
@@ -134,7 +118,7 @@ module Sisimai::Bite::Email
134
118
  # deliver.c:7586| "Message %s has been frozen%s.\nThe sender is <%s>.\n", message_id,
135
119
  # receive.c:4021| moan_tell_someone(freeze_tell, NULL, US"Message frozen on arrival",
136
120
  # receive.c:4022| "Message %s was frozen on arrival by %s.\nThe sender is <%s>.\n",
137
- ReDelayed = %r{(?:
121
+ ReDelaying = %r{(?:
138
122
  retry[ ]timeout[ ]exceeded
139
123
  |No[ ]action[ ]is[ ]required[ ]on[ ]your[ ]part
140
124
  |retry[ ]time[ ]not[ ]reached[ ]for[ ]any[ ]host[ ]after[ ]a[ ]long[ ]failure[ ]period
@@ -143,12 +127,10 @@ module Sisimai::Bite::Email
143
127
  |Message[ ].+[ ](?:has[ ]been[ ]frozen|was[ ]frozen[ ]on[ ]arrival[ ]by[ ])
144
128
  )
145
129
  }x
146
- Indicators = Sisimai::Bite::Email.INDICATORS
147
130
 
148
131
  def description; return 'Exim'; end
149
132
  def smtpagent; return Sisimai::Bite.smtpagent(self); end
150
133
  def headerlist; return ['X-Failed-Recipients']; end
151
- def pattern; return Re0; end
152
134
 
153
135
  # Parse bounce messages from Exim
154
136
  # @param [Hash] mhead Message headers of a bounce email
@@ -164,9 +146,19 @@ module Sisimai::Bite::Email
164
146
  def scan(mhead, mbody)
165
147
  return nil unless mhead
166
148
  return nil unless mbody
167
- return nil if mhead['from'] =~ ReE[:from]
168
- return nil unless mhead['from'] =~ Re0[:from]
169
- return nil unless mhead['subject'] =~ Re0[:subject]
149
+
150
+ # :'message-id' => %r/\A[<]\w+[-]\w+[-]\w+[@].+\z/,
151
+ return nil if mhead['from'] =~ /[@].+[.]mail[.]ru[>]?/
152
+ return nil unless mhead['from'].start_with?('Mail Delivery System')
153
+ return nil unless mhead['subject'] =~ %r{(?:
154
+ Mail[ ]delivery[ ]failed(:[ ]returning[ ]message[ ]to[ ]sender)?
155
+ |Warning:[ ]message[ ].+[ ]delayed[ ]+
156
+ |Delivery[ ]Status[ ]Notification
157
+ |Mail[ ]failure
158
+ |Message[ ]frozen
159
+ |error[(]s[)][ ]in[ ]forwarding[ ]or[ ]filtering
160
+ )
161
+ }x
170
162
 
171
163
  dscontents = [Sisimai::Bite.DELIVERYSTATUS]
172
164
  hasdivided = mbody.split("\n")
@@ -188,20 +180,20 @@ module Sisimai::Bite::Email
188
180
  boundary00 = Sisimai::MIME.boundary(mhead['content-type']) || ''
189
181
  end
190
182
 
191
- hasdivided.each do |e|
192
- break if e =~ Re1[:endof]
183
+ while e = hasdivided.shift do
184
+ break if e == StartingOf[:endof][0]
193
185
 
194
186
  if readcursor.zero?
195
187
  # Beginning of the bounce message or delivery status part
196
- if e =~ Re1[:begin]
188
+ if e =~ MarkingsOf[:message]
197
189
  readcursor |= Indicators[:deliverystatus]
198
- next unless e =~ Re1[:frozen]
190
+ next unless e =~ MarkingsOf[:frozen]
199
191
  end
200
192
  end
201
193
 
202
194
  if (readcursor & Indicators[:'message-rfc822']).zero?
203
195
  # Beginning of the original message part
204
- if e =~ Re1[:rfc822]
196
+ if e =~ MarkingsOf[:rfc822]
205
197
  readcursor |= Indicators[:'message-rfc822']
206
198
  next
207
199
  end
@@ -215,7 +207,6 @@ module Sisimai::Bite::Email
215
207
  next
216
208
  end
217
209
  rfc822list << e
218
-
219
210
  else
220
211
  # Before "message/rfc822"
221
212
  next if (readcursor & Indicators[:deliverystatus]).zero?
@@ -233,7 +224,7 @@ module Sisimai::Bite::Email
233
224
 
234
225
  if cv = e.match(/\A[ \t]{2}([^ \t]+[@][^ \t]+[.]?[a-zA-Z]+)(:.+)?\z/) ||
235
226
  e.match(/\A[ \t]{2}[^ \t]+[@][^ \t]+[.][a-zA-Z]+[ ]<(.+?[@].+?)>:.+\z/) ||
236
- e.match(Re1[:alias])
227
+ e.match(MarkingsOf[:alias])
237
228
  # kijitora@example.jp
238
229
  # sabineko@example.jp: forced freeze
239
230
  # mikeneko@example.jp <nekochan@example.org>: ...
@@ -271,49 +262,46 @@ module Sisimai::Bite::Email
271
262
  # pipe to |/bin/echo "Some pipe output"
272
263
  # generated by userx@myhost.test.ex
273
264
  v['alias'] = cv[1]
274
-
275
265
  else
276
266
  next if e.empty?
277
267
 
278
- if e =~ Re1[:frozen]
268
+ if e =~ MarkingsOf[:frozen]
279
269
  # Message *** has been frozen by the system filter.
280
270
  # Message *** was frozen on arrival by ACL.
281
271
  v['alterrors'] ||= ''
282
- v['alterrors'] += e + ' '
283
-
272
+ v['alterrors'] << e + ' '
284
273
  else
285
274
  if boundary00.size > 0
286
275
  # --NNNNNNNNNN-eximdsn-MMMMMMMMMM
287
276
  # Content-type: message/delivery-status
288
277
  # ...
289
- if cv = e.match(/\A[Rr]eporting-MTA:[ ]*(?:DNS|dns);[ ]*(.+)\z/)
278
+ if cv = e.match(/\AReporting-MTA:[ ]*(?:DNS|dns);[ ]*(.+)\z/)
290
279
  # Reporting-MTA: dns; mx.example.jp
291
280
  v['lhost'] = cv[1]
292
281
 
293
- elsif cv = e.match(/\A[Aa]ction:[ ]*(.+)\z/)
282
+ elsif cv = e.match(/\AAction:[ ]*(.+)\z/)
294
283
  # Action: failed
295
284
  v['action'] = cv[1].downcase
296
285
 
297
- elsif cv = e.match(/\A[Ss]tatus:[ ]*(\d[.]\d+[.]\d+)/)
286
+ elsif cv = e.match(/\AStatus:[ ]*(\d[.]\d+[.]\d+)/)
298
287
  # Status: 5.0.0
299
288
  v['status'] = cv[1]
300
289
 
301
- elsif cv = e.match(/\A[Dd]iagnostic-[Cc]ode:[ ]*(.+?);[ ]*(.+)\z/)
290
+ elsif cv = e.match(/\ADiagnostic-Code:[ ]*(.+?);[ ]*(.+)\z/)
302
291
  # Diagnostic-Code: SMTP; 550 5.1.1 <userunknown@example.jp>... User Unknown
303
292
  v['spec'] = cv[1].upcase
304
293
  v['diagnosis'] = cv[2]
305
294
 
306
- elsif cv = e.match(/\A[Ff]inal-[Rr]ecipient:[ ]*(?:RFC|rfc)822;[ ]*(.+)\z/)
295
+ elsif cv = e.match(/\AFinal-Recipient:[ ]*(?:RFC|rfc)822;[ ]*(.+)\z/)
307
296
  # Final-Recipient: rfc822;|/bin/echo "Some pipe output"
308
- v['spec'] ||= cv[1] =~ /[@]/ ? 'SMTP' : 'X-UNIX'
309
-
297
+ v['spec'] ||= cv[1].include?('@') ? 'SMTP' : 'X-UNIX'
310
298
  else
311
299
  # Error message ?
312
300
  if havepassed[:deliverystatus].zero?
313
301
  # Content-type: message/delivery-status
314
- havepassed[:deliverystatus] = 1 if e =~ Re1[:deliverystatus]
302
+ havepassed[:deliverystatus] = 1 if e.start_with?(StartingOf[:deliverystatus][0])
315
303
  v['alterrors'] ||= ''
316
- v['alterrors'] += e + ' ' if e =~ /\A[ ]+/
304
+ v['alterrors'] << e + ' ' if e.start_with?(' ')
317
305
  end
318
306
  end
319
307
  else
@@ -321,8 +309,7 @@ module Sisimai::Bite::Email
321
309
  # Error message
322
310
  next unless e.size
323
311
  v['diagnosis'] ||= ''
324
- v['diagnosis'] += e + ' '
325
-
312
+ v['diagnosis'] << e + ' '
326
313
  else
327
314
  # Error message when email address above does not include '@'
328
315
  # and domain part.
@@ -331,9 +318,9 @@ module Sisimai::Bite::Email
331
318
  # generated by kijitora@example.com
332
319
  v['diagnosis'] = e
333
320
  else
334
- next unless e =~ /\A[ ]{4}/
321
+ next unless e.start_with?(' ')
335
322
  v['alterrors'] ||= ''
336
- v['alterrors'] += e + ' '
323
+ v['alterrors'] << e + ' '
337
324
  end
338
325
 
339
326
  end
@@ -349,12 +336,11 @@ module Sisimai::Bite::Email
349
336
  # Replace the recipient address with the value of "alias"
350
337
  next unless q['alias']
351
338
  next unless q['alias'].size > 0
352
- if q['recipient'].empty? || q['recipient'] !~ /[@]/
339
+ if q['recipient'].empty? || q['recipient'].include?('@') == false
353
340
  # The value of "recipient" is empty or does not include "@"
354
341
  q['recipient'] = q['alias']
355
342
  end
356
343
  end
357
-
358
344
  else
359
345
  # Fallback for getting recipient addresses
360
346
  if mhead['x-failed-recipients']
@@ -367,7 +353,7 @@ module Sisimai::Bite::Email
367
353
  end
368
354
  recipients = rcptinhead.size
369
355
 
370
- rcptinhead.each do |e|
356
+ while e = rcptinhead.shift do
371
357
  # Insert each recipient address into dscontents
372
358
  dscontents[-1]['recipient'] = e
373
359
  next if dscontents.size == recipients
@@ -388,7 +374,6 @@ module Sisimai::Bite::Email
388
374
  require 'sisimai/string'
389
375
  require 'sisimai/smtp/reply'
390
376
  require 'sisimai/smtp/status'
391
-
392
377
  dscontents.map do |e|
393
378
  # Set default values if each value is empty.
394
379
  e['agent'] = self.smtpagent
@@ -412,33 +397,30 @@ module Sisimai::Bite::Email
412
397
  e['diagnosis'] = dscontents[0]['diagnosis'] || ''
413
398
  e['spec'] ||= dscontents[0]['spec']
414
399
 
415
- if dscontents[0]['alterrors'] && dscontents[0]['alterrors'].size > 0
400
+ if dscontents[0]['alterrors'].to_s.size > 0
416
401
  # The value of "alterrors" is also copied
417
402
  e['alterrors'] = dscontents[0]['alterrors']
418
403
  end
419
404
  end
420
405
  end
421
406
 
422
- if e['alterrors'] && e['alterrors'].size > 0
407
+ if e['alterrors'].to_s.size > 0
423
408
  # Copy alternative error message
424
409
  if e['diagnosis'].nil? || e['diagnosis'].empty?
425
410
  e['diagnosis'] = e['alterrors']
426
411
  end
427
412
 
428
- if e['diagnosis'] =~ /\A[-]+/ || e['diagnosis'].end_with?('__')
413
+ if e['diagnosis'].start_with?('-') || e['diagnosis'].end_with?('__')
429
414
  # Override the value of diagnostic code message
430
415
  e['diagnosis'] = e['alterrors'] if e['alterrors'].size > 0
431
-
432
416
  else
433
417
  # Check the both value and try to match
434
418
  if e['diagnosis'].size < e['alterrors'].size
435
419
  # Check the value of alterrors
436
420
  rxdiagnosis = %r/e['diagnosis']/i
437
- if e['alterrors'] =~ rxdiagnosis
438
- # Override the value of diagnostic code message because
439
- # the value of alterrors includes the value of diagnosis.
440
- e['diagnosis'] = e['alterrors']
441
- end
421
+ # Override the value of diagnostic code message because
422
+ # the value of alterrors includes the value of diagnosis.
423
+ e['diagnosis'] = e['alterrors'] if e['alterrors'] =~ rxdiagnosis
442
424
  end
443
425
  end
444
426
  e.delete('alterrors')
@@ -454,16 +436,14 @@ module Sisimai::Bite::Email
454
436
  end
455
437
 
456
438
  unless e['rhost']
457
- if mhead['received'].size > 0
458
- # Get localhost and remote host name from Received header.
459
- e['rhost'] = Sisimai::RFC5322.received(mhead['received'][-1]).pop
460
- end
439
+ # Get localhost and remote host name from Received header.
440
+ e['rhost'] = Sisimai::RFC5322.received(mhead['received'][-1]).pop if mhead['received'].size > 0
461
441
  end
462
442
  end
463
443
 
464
444
  unless e['command']
465
445
  # Get the SMTP command name for the session
466
- ReCommand.each do |r|
446
+ ReCommands.each do |r|
467
447
  # Verify each regular expression of SMTP commands
468
448
  if cv = e['diagnosis'].match(r)
469
449
  e['command'] = cv[1].upcase
@@ -472,26 +452,25 @@ module Sisimai::Bite::Email
472
452
  end
473
453
 
474
454
  # Detect the reason of bounce
475
- if e['command'] =~ /\A(?:HELO|EHLO)\z/
455
+ if %w[HELO EHLO].index(e['command'])
476
456
  # HELO | Connected to 192.0.2.135 but my name was rejected.
477
457
  e['reason'] = 'blocked'
478
458
 
479
459
  elsif e['command'] == 'MAIL'
480
460
  # MAIL | Connected to 192.0.2.135 but sender was rejected.
481
461
  e['reason'] = 'onhold'
482
-
483
462
  else
484
463
  # Verify each regular expression of session errors
485
- ReFailure.each_key do |r|
464
+ ReFailures.each_key do |r|
486
465
  # Check each regular expression
487
- next unless e['diagnosis'] =~ ReFailure[r]
466
+ next unless e['diagnosis'] =~ ReFailures[r]
488
467
  e['reason'] = r.to_s
489
468
  break
490
469
  end
491
470
 
492
471
  unless e['reason']
493
472
  # The reason "expired"
494
- e['reason'] = 'expired' if e['diagnosis'] =~ ReDelayed
473
+ e['reason'] = 'expired' if e['diagnosis'] =~ ReDelaying
495
474
  end
496
475
  end
497
476
  end
@@ -511,25 +490,27 @@ module Sisimai::Bite::Email
511
490
  r1 = 0 # First character of SMTP reply code as integer
512
491
 
513
492
  # "Status:" field did not exist in the bounce message
514
- if sv.empty?
493
+ while true
494
+ break unless sv.empty?
495
+ break if rv.empty?
496
+
515
497
  # Check SMTP reply code
516
- if rv.size > 0
517
- # Generate pseudo DSN code from SMTP reply code
518
- r1 = rv[0, 1].to_i
519
- if r1 == 4
520
- # Get the internal DSN(temporary error)
521
- sv = Sisimai::SMTP::Status.code(e['reason'], true)
522
-
523
- elsif r1 == 5
524
- # Get the internal DSN(permanent error)
525
- sv = Sisimai::SMTP::Status.code(e['reason'], false)
526
- end
498
+ # Generate pseudo DSN code from SMTP reply code
499
+ r1 = rv[0, 1].to_i
500
+ if r1 == 4
501
+ # Get the internal DSN(temporary error)
502
+ sv = Sisimai::SMTP::Status.code(e['reason'], true)
503
+
504
+ elsif r1 == 5
505
+ # Get the internal DSN(permanent error)
506
+ sv = Sisimai::SMTP::Status.code(e['reason'], false)
527
507
  end
508
+ break
528
509
  end
529
510
 
530
511
  s1 = sv[0, 1].to_i if sv.size > 0
531
512
  v1 = s1 + r1
532
- v1 += e['status'][0, 1].to_i if e['status']
513
+ v1 << e['status'][0, 1].to_i if e['status']
533
514
 
534
515
  if v1 > 0
535
516
  # Status or SMTP reply code exists
@@ -537,7 +518,7 @@ module Sisimai::Bite::Email
537
518
  e['status'] = sv if r1 > 0
538
519
  else
539
520
  # Neither Status nor SMTP reply code exist
540
- sv = if e['reason'] =~ /\A(?:expired|mailboxfull)/
521
+ sv = if %w[expired mailboxfull].include?(e['reason'])
541
522
  # Set pseudo DSN (temporary error)
542
523
  Sisimai::SMTP::Status.code(e['reason'], true)
543
524
  else