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,9 +6,7 @@ module Sisimai
6
6
  # Imported from p5-Sisimail/lib/Sisimai/Reason/Vacation.pm
7
7
  class << self
8
8
  def text; return 'vacation'; end
9
- def description
10
- return 'Email replied automatically due to a recipient is out of office'
11
- end
9
+ def description; return 'Email replied automatically due to a recipient is out of office'; end
12
10
 
13
11
  # Try to match that the given text and regular expressions
14
12
  # @param [String] argv1 String to be matched with regular expressions
@@ -17,13 +15,13 @@ module Sisimai
17
15
  def match(argv1)
18
16
  return nil unless argv1
19
17
  regex = %r{(?>
20
- I[ ]am[ ](?:
18
+ i[ ]am[ ](?:
21
19
  away[ ](?:on[ ]vacation|until)
22
20
  |out[ ]of[ ]the[ ]office
23
21
  )
24
- |I[ ]will[ ]be[ ]traveling[ ]for[ ]work[ ]on
22
+ |i[ ]will[ ]be[ ]traveling[ ]for[ ]work[ ]on
25
23
  )
26
- }ix
24
+ }x
27
25
 
28
26
  return true if argv1 =~ regex
29
27
  return false
@@ -17,9 +17,7 @@ module Sisimai
17
17
  # Imported from p5-Sisimail/lib/Sisimai/Reason/VirusDetected.pm
18
18
  class << self
19
19
  def text; return 'virusdetected'; end
20
- def description
21
- return 'Email rejected due to a virus scanner on a destination host'
22
- end
20
+ def description; return 'Email rejected due to a virus scanner on a destination host'; end
23
21
 
24
22
  # Try to match that the given text and regular expressions
25
23
  # @param [String] argv1 String to be matched with regular expressions
@@ -31,10 +29,10 @@ module Sisimai
31
29
  regex = %r{(?>
32
30
  it[ ]has[ ]a[ ]potentially[ ]executable[ ]attachment
33
31
  |the[ ]message[ ]was[ ]rejected[ ]because[ ]it[ ]contains[ ]prohibited[ ]virus[ ]or[ ]spam[ ]content
34
- |This[ ]form[ ]of[ ]attachment[ ]has[ ]been[ ]used[ ]by[ ]recent[ ]viruses[ ]or[ ]other[ ]malware
35
- |Your[ ]message[ ]was[ ]infected[ ]with[ ]a[ ]virus
32
+ |this[ ]form[ ]of[ ]attachment[ ]has[ ]been[ ]used[ ]by[ ]recent[ ]viruses[ ]or[ ]other[ ]malware
33
+ |your[ ]message[ ]was[ ]infected[ ]with[ ]a[ ]virus
36
34
  )
37
- }ix
35
+ }x
38
36
 
39
37
  return true if argv1 =~ regex
40
38
  return false
@@ -14,8 +14,7 @@ module Sisimai
14
14
  return false unless argv.is_a?(::String)
15
15
 
16
16
  return true if argv =~ /[.](?:test|example|invalid|localhost)\z/
17
- return true if argv =~ /example[.](?:com|net|org)\z/
18
- return true if argv =~ /example[.]jp\z/
17
+ return true if argv =~ /example[.](?:com|net|org|jp)\z/
19
18
  return true if argv =~ /example[.](?:ac|ad|co|ed|go|gr|lg|ne|or)[.]jp\z/
20
19
  return false
21
20
  end
@@ -6,46 +6,30 @@ module Sisimai
6
6
  require 'sisimai/bite/email'
7
7
 
8
8
  # http://tools.ietf.org/html/rfc3464
9
- Re0 = {
10
- :'from' => %r/\b(?:postmaster|mailer-daemon|root)[@]/i,
11
- :'return-path' => %r/(?:[<][>]|mailer-daemon)/i,
12
- :'subject' => %r{(?>
13
- delivery[ ](?:failed|failure|report)
14
- |failure[ ]notice
15
- |mail[ ](?:delivery|error)
16
- |non[-]delivery
17
- |returned[ ]mail
18
- |undeliverable[ ]mail
19
- |Warning:[ ]
20
- )
21
- }xi,
22
- }.freeze
23
- Re1 = {
24
- :begin => %r{\A(?>
25
- Content-Type:[ ]*(?:
9
+ Indicators = Sisimai::Bite::Email.INDICATORS
10
+ MarkingsOf = {
11
+ message: %r{\A(?>
12
+ content-type:[ ]*(?:
26
13
  message/delivery-status
27
14
  |message/disposition-notification
28
15
  |text/plain;[ ]charset=
29
16
  )
30
- |The[ ]original[ ]message[ ]was[ ]received[ ]at[ ]
31
- |This[ ]report[ ]relates[ ]to[ ]your[ ]message
32
- |Your[ ]message[ ]was[ ]not[ ]delivered[ ]to[ ]the[ ]following[ ]recipients
17
+ |the[ ]original[ ]message[ ]was[ ]received[ ]at[ ]
18
+ |this[ ]report[ ]relates[ ]to[ ]your[ ]message
19
+ |your[ ]message[ ]was[ ]not[ ]delivered[ ]to[ ]the[ ]following[ ]recipients
33
20
  )
34
- }xi,
35
- :endof => %r/\A__END_OF_EMAIL_MESSAGE__\z/,
36
- :rfc822 => %r{\A(?>
37
- Content-Type:[ ]*(?:message/rfc822|text/rfc822-headers)
38
- |Return-Path:[ ]*[<].+[>]\z
21
+ }x,
22
+ rfc822: %r{\A(?>
23
+ content-type:[ ]*(?:message/rfc822|text/rfc822-headers)
24
+ |return-path:[ ]*[<].+[>]\z
39
25
  )\z
40
- }xi,
41
- :error => %r/\A(?:[45]\d\d[ \t]+|[<][^@]+[@][^@]+[>]:?[ \t]+)/i,
42
- :command => %r/[ ](RCPT|MAIL|DATA)[ ]+command\b/,
26
+ }x,
27
+ error: %r/\A(?:[45]\d\d[ \t]+|[<][^@]+[@][^@]+[>]:?[ \t]+)/,
28
+ command: %r/[ ](RCPT|MAIL|DATA)[ ]+command\b/,
43
29
  }.freeze
44
- Indicators = Sisimai::Bite::Email.INDICATORS
45
30
 
46
31
  def description; 'Fallback Module for MTAs'; end
47
32
  def smtpagent; 'RFC3464'; end
48
- def pattern; return Re0; end
49
33
  def headerlist; return []; end
50
34
 
51
35
  # Detect an error for RFC3464
@@ -82,14 +66,15 @@ module Sisimai
82
66
  }
83
67
  v = nil
84
68
 
85
- hasdivided.each do |e|
69
+ while e = hasdivided.shift do
86
70
  # Save the current line for the next loop
87
71
  havepassed << e
72
+ d = e.downcase
88
73
  p = havepassed[-2]
89
74
 
90
75
  if readcursor.zero?
91
76
  # Beginning of the bounce message or delivery status part
92
- if e =~ Re1[:begin]
77
+ if d =~ MarkingsOf[:message]
93
78
  readcursor |= Indicators[:deliverystatus]
94
79
  next
95
80
  end
@@ -97,7 +82,7 @@ module Sisimai
97
82
 
98
83
  if (readcursor & Indicators[:'message-rfc822']).zero?
99
84
  # Beginning of the original message part
100
- if e =~ Re1[:rfc822]
85
+ if d =~ MarkingsOf[:rfc822]
101
86
  readcursor |= Indicators[:'message-rfc822']
102
87
  next
103
88
  end
@@ -111,15 +96,14 @@ module Sisimai
111
96
  next
112
97
  end
113
98
  rfc822list << e
114
-
115
99
  else
116
100
  # Before "message/rfc822"
117
101
  next unless readcursor & Indicators[:deliverystatus] > 0
118
102
  next unless e.size > 0
119
103
 
120
104
  v = dscontents[-1]
121
- if cv = e.match(/\A(?:[Ff]inal|[Oo]riginal)-[Rr]ecipient:[ ]*(?:RFC|rfc)822;[ ]*([^ ]+)\z/) ||
122
- e.match(/\A(?:[Ff]inal|[Oo]riginal)-[Rr]ecipient:[ ]*([^ ]+)\z/)
105
+ if cv = e.match(/\A(?:Final|Original)-Recipient:[ ]*(?:RFC|rfc)822;[ ]*([^ ]+)\z/) ||
106
+ e.match(/\A(?:Final|Original)-Recipient:[ ]*([^ ]+)\z/)
123
107
  # 2.3.2 Final-Recipient field
124
108
  # The Final-Recipient field indicates the recipient for which this set
125
109
  # of per-recipient fields applies. This field MUST be present in each
@@ -149,17 +133,15 @@ module Sisimai
149
133
  v['recipient'] = y
150
134
  recipients += 1
151
135
 
152
- elsif cv = e.match(/\A[Xx]-[Aa]ctual-[Rr]ecipient:[ ]*(?:RFC|rfc)822;[ ]*([^ ]+)\z/)
136
+ elsif cv = e.match(/\AX-Actual-Recipient:[ ]*(?:RFC|rfc)822;[ ]*([^ ]+)\z/)
153
137
  # X-Actual-Recipient:
154
138
  if cv[1] =~ /[ \t]+/
155
139
  # X-Actual-Recipient: RFC822; |IFS=' ' && exec procmail -f- || exit 75 ...
156
-
157
140
  else
158
141
  # X-Actual-Recipient: rfc822; kijitora@neko.example.jp
159
142
  v['alias'] = cv[1]
160
143
  end
161
-
162
- elsif cv = e.match(/\A[Aa]ction:[ ]*(.+)\z/)
144
+ elsif cv = e.match(/\AAction:[ ]*(.+)\z/)
163
145
  # 2.3.3 Action field
164
146
  # The Action field indicates the action performed by the Reporting-MTA
165
147
  # as a result of its attempt to deliver the message to this recipient
@@ -179,8 +161,7 @@ module Sisimai
179
161
  # failed (bad destination mailbox address)
180
162
  v['action'] = cv[1]
181
163
  end
182
-
183
- elsif cv = e.match(/\A[Ss]tatus:[ ]*(\d[.]\d+[.]\d+)/)
164
+ elsif cv = e.match(/\AStatus:[ ]*(\d[.]\d+[.]\d+)/)
184
165
  # 2.3.4 Status field
185
166
  # The per-recipient Status field contains a transport-independent
186
167
  # status code that indicates the delivery status of the message to that
@@ -193,11 +174,11 @@ module Sisimai
193
174
  # status-code = DIGIT "." 1*3DIGIT "." 1*3DIGIT
194
175
  v['status'] = cv[1]
195
176
 
196
- elsif cv = e.match(/\A[Ss]tatus:[ ]*(\d+[ ]+.+)\z/)
177
+ elsif cv = e.match(/\AStatus:[ ]*(\d+[ ]+.+)\z/)
197
178
  # Status: 553 Exceeded maximum inbound message size
198
179
  v['alterrors'] = cv[1]
199
180
 
200
- elsif cv = e.match(/\A[Rr]emote-MTA:[ ]*(?:DNS|dns);[ ]*(.+)\z/)
181
+ elsif cv = e.match(/\ARemote-MTA:[ ]*(?:DNS|dns);[ ]*(.+)\z/)
201
182
  # 2.3.5 Remote-MTA field
202
183
  # The value associated with the Remote-MTA DSN field is a printable
203
184
  # ASCII representation of the name of the "remote" MTA that reported
@@ -213,7 +194,7 @@ module Sisimai
213
194
  # involved in the attempted delivery of the message to that recipient.
214
195
  v['rhost'] = cv[1].downcase
215
196
 
216
- elsif cv = e.match(/\A[Ll]ast-[Aa]ttempt-[Dd]ate:[ ]*(.+)\z/)
197
+ elsif cv = e.match(/\ALast-Attempt-Date:[ ]*(.+)\z/)
217
198
  # 2.3.7 Last-Attempt-Date field
218
199
  # The Last-Attempt-Date field gives the date and time of the last
219
200
  # attempt to relay, gateway, or deliver the message (whether successful
@@ -227,9 +208,8 @@ module Sisimai
227
208
  #
228
209
  # last-attempt-date-field = "Last-Attempt-Date" ":" date-time
229
210
  v['date'] = cv[1]
230
-
231
211
  else
232
- if cv = e.match(/\A[Dd]iagnostic-[Cc]ode:[ ]*(.+?);[ ]*(.+)\z/)
212
+ if cv = e.match(/\ADiagnostic-Code:[ ]*(.+?);[ ]*(.+)\z/)
233
213
  # 2.3.6 Diagnostic-Code field
234
214
  # For a "failed" or "delayed" recipient, the Diagnostic-Code DSN field
235
215
  # contains the actual diagnostic code issued by the mail transport.
@@ -242,18 +222,17 @@ module Sisimai
242
222
  v['spec'] = cv[1].upcase
243
223
  v['diagnosis'] = cv[2]
244
224
 
245
- elsif cv = e.match(/\A[Dd]iagnostic-[Cc]ode:[ ]*(.+)\z/)
225
+ elsif cv = e.match(/\ADiagnostic-Code:[ ]*(.+)\z/)
246
226
  # No value of "diagnostic-type"
247
227
  # Diagnostic-Code: 554 ...
248
228
  v['diagnosis'] = cv[1]
249
229
 
250
- elsif p =~ /\A[Dd]iagnostic-[Cc]ode:[ ]*/ && cv = e.match(/\A[ \t]+(.+)\z/)
230
+ elsif p.start_with?('Diagnostic-Code:') && cv = e.match(/\A[ \t]+(.+)\z/)
251
231
  # Continued line of the value of Diagnostic-Code header
252
- v['diagnosis'] += ' ' + cv[1]
253
- e = 'Diagnostic-Code: ' + e
254
-
232
+ v['diagnosis'] << ' ' << cv[1]
233
+ e = 'Diagnostic-Code: ' << e
255
234
  else
256
- if cv = e.match(/\A[Rr]eporting-MTA:[ ]*(?:DNS|dns);[ ]*(.+)\z/)
235
+ if cv = e.match(/\AReporting-MTA:[ ]*(?:DNS|dns);[ ]*(.+)\z/)
257
236
  # 2.2.2 The Reporting-MTA DSN field
258
237
  #
259
238
  # reporting-mta-field =
@@ -268,7 +247,7 @@ module Sisimai
268
247
  # operation described in the DSN. This field is required.
269
248
  connheader['rhost'] ||= cv[1].downcase
270
249
 
271
- elsif cv = e.match(/\A[Rr]eceived-[Ff]rom-MTA:[ ]*(?:DNS|dns);[ ]*(.+)\z/)
250
+ elsif cv = e.match(/\AReceived-From-MTA:[ ]*(?:DNS|dns);[ ]*(.+)\z/)
272
251
  # 2.2.4 The Received-From-MTA DSN field
273
252
  # The optional Received-From-MTA field indicates the name of the MTA
274
253
  # from which the message was received.
@@ -283,7 +262,7 @@ module Sisimai
283
262
  # parentheses. (In this case, the MTA-name-type will be "dns".)
284
263
  connheader['lhost'] = cv[1].downcase
285
264
 
286
- elsif cv = e.match(/\A[Aa]rrival-[Dd]ate:[ ]*(.+)\z/)
265
+ elsif cv = e.match(/\AArrival-Date:[ ]*(.+)\z/)
287
266
  # 2.2.5 The Arrival-Date DSN field
288
267
  # The optional Arrival-Date field indicates the date and time at which
289
268
  # the message arrived at the Reporting MTA. If the Last-Attempt-Date
@@ -293,35 +272,44 @@ module Sisimai
293
272
  #
294
273
  # arrival-date-field = "Arrival-Date" ":" date-time
295
274
  connheader['date'] = cv[1]
296
-
297
275
  else
298
276
  # Get error message
299
- next if e =~ /\A[ -]+/
300
- next unless e =~ Re1[:error]
277
+ next if e.start_with?(' ', '-')
278
+ next unless e =~ MarkingsOf[:error]
301
279
 
302
280
  # 500 User Unknown
303
281
  # <kijitora@example.jp> Unknown
304
282
  v['alterrors'] ||= ' '
305
- v['alterrors'] += ' ' + e
283
+ v['alterrors'] << ' ' << e
306
284
  end
307
285
  end
308
286
  end
309
287
  end # End of if: rfc822
310
-
311
288
  end
312
289
 
313
- loop do
290
+ while true
314
291
  # Fallback, parse entire message body
315
292
  break if recipients > 0
316
293
  match = 0
294
+ mfrom = mhead['from'].downcase
317
295
 
318
296
  # Failed to get a recipient address at code above
319
- match += 1 if mhead['from'] =~ Re0[:from]
320
- match += 1 if mhead['subject'] =~ Re0[:subject]
297
+ match += 1 if mfrom.include?('postmaster@') || mfrom.include?('mailer-daemon@') || mfrom.include?('root@')
298
+ match += 1 if mhead['subject'].downcase =~ %r{(?>
299
+ delivery[ ](?:failed|failure|report)
300
+ |failure[ ]notice
301
+ |mail[ ](?:delivery|error)
302
+ |non[-]delivery
303
+ |returned[ ]mail
304
+ |undeliverable[ ]mail
305
+ |warning:[ ]
306
+ )
307
+ }x
321
308
 
322
309
  if mhead['return-path']
323
310
  # Check the value of Return-Path of the message
324
- match += 1 if mhead['return-path'] =~ Re0[:'return-path']
311
+ rpath = mhead['return-path'].downcase
312
+ match += 1 if rpath.include?('<>') || rpath.include?('mailer-daemon')
325
313
  end
326
314
  break unless match > 0
327
315
 
@@ -330,35 +318,35 @@ module Sisimai
330
318
  |\A\s+\z
331
319
  |\A\s*--
332
320
  |\A\s+[=]\d+
333
- |\AHi[ ][!]
334
- |Content-(?:Description|Disposition|Transfer-Encoding|Type):[ ]
321
+ |\Ahi[ ][!]
322
+ |content-(?:description|disposition|transfer-encoding|type):[ ]
335
323
  |(?:name|charset)=
336
324
  |--\z
337
325
  |:[ ]--------
338
326
  )
339
- }xi
327
+ }x
340
328
  re_stop = %r{(?:
341
329
  \A[*][*][*][ ].+[ ].+[ ][*][*][*]
342
- |\AContent-Type:[ ]message/delivery-status
343
- |\AHere[ ]is[ ]a[ ]copy[ ]of[ ]the[ ]first[ ]part[ ]of[ ]the[ ]message
344
- |\AThe[ ]non-delivered[ ]message[ ]is[ ]attached[ ]to[ ]this[ ]message.
345
- |\AReceived:[ \t]*
346
- |\AReceived-From-MTA:[ \t]*
347
- |\AReporting-MTA:[ \t]*
348
- |\AReturn-Path:[ \t]*
349
- |\AA[ ]copy[ ]of[ ]the[ ]original[ ]message[ ]below[ ]this[ ]line:
350
- |Attachment[ ]is[ ]a[ ]copy[ ]of[ ]the[ ]message
351
- |Below[ ]is[ ]a[ ]copy[ ]of[ ]the[ ]original[ ]message:
352
- |Below[ ]this[ ]line[ ]is[ ]a[ ]copy[ ]of[ ]the[ ]message
353
- |Message[ ]contains[ ].+[ ]file[ ]attachments
354
- |Message[ ]text[ ]follows:[ ]
355
- |Original[ ]message[ ]follows
356
- |The[ ]attachment[ ]contains[ ]the[ ]original[ ]mail[ ]headers
357
- |The[ ]first[ ]\d+[ ]lines[ ]
358
- |Unsent[ ]Message[ ]below
359
- |Your[ ]message[ ]reads[ ][(]in[ ]part[)]:
330
+ |\Acontent-type:[ ]message/delivery-status
331
+ |\Ahere[ ]is[ ]a[ ]copy[ ]of[ ]the[ ]first[ ]part[ ]of[ ]the[ ]message
332
+ |\Athe[ ]non-delivered[ ]message[ ]is[ ]attached[ ]to[ ]this[ ]message.
333
+ |\Areceived:[ \t]*
334
+ |\Areceived-from-mta:[ \t]*
335
+ |\Areporting-mta:[ \t]*
336
+ |\Areturn-path:[ \t]*
337
+ |\Aa[ ]copy[ ]of[ ]the[ ]original[ ]message[ ]below[ ]this[ ]line:
338
+ |attachment[ ]is[ ]a[ ]copy[ ]of[ ]the[ ]message
339
+ |below[ ]is[ ]a[ ]copy[ ]of[ ]the[ ]original[ ]message:
340
+ |below[ ]this[ ]line[ ]is[ ]a[ ]copy[ ]of[ ]the[ ]message
341
+ |message[ ]contains[ ].+[ ]file[ ]attachments
342
+ |message[ ]text[ ]follows:[ ]
343
+ |original[ ]message[ ]follows
344
+ |the[ ]attachment[ ]contains[ ]the[ ]original[ ]mail[ ]headers
345
+ |the[ ]first[ ]\d+[ ]lines[ ]
346
+ |unsent[ ]Message[ ]below
347
+ |your[ ]message[ ]reads[ ][(]in[ ]part[)]:
360
348
  )
361
- }xi
349
+ }x
362
350
  re_addr = %r{(?:
363
351
  \A\s*
364
352
  |\A["].+["]\s*
@@ -388,15 +376,17 @@ module Sisimai
388
376
  }xi
389
377
 
390
378
  b = dscontents[-1]
391
- mbody.split("\n").each do |e|
379
+ hasdivided = mbody.split("\n")
380
+ while e = hasdivided.shift do
392
381
  # Get the recipient's email address and error messages.
393
- break if e =~ Re1[:endof]
394
- break if e =~ Re1[:rfc822]
395
- break if e =~ re_stop
382
+ break if e.start_with?('__END_OF_EMAIL_MESSAGE__')
383
+ d = e.downcase
384
+ break if d =~ MarkingsOf[:rfc822]
385
+ break if d =~ re_stop
396
386
 
397
387
  next if e.size.zero?
398
- next if e =~ re_skip
399
- next if e =~ /\A[*]/
388
+ next if d =~ re_skip
389
+ next if e.start_with?('*')
400
390
 
401
391
  if cv = e.match(re_addr)
402
392
  # May be an email address
@@ -418,7 +408,7 @@ module Sisimai
418
408
  b['alias'] = Sisimai::Address.s3s4(cv[1])
419
409
  end
420
410
  b['diagnosis'] ||= ''
421
- b['diagnosis'] += ' ' + e
411
+ b['diagnosis'] << ' ' << e
422
412
  end
423
413
 
424
414
  break
@@ -431,21 +421,18 @@ module Sisimai
431
421
  next unless cv = e.match(/\ATo:\s*(.+)\z/)
432
422
  r = Sisimai::Address.find(cv[1], true) || []
433
423
  next if r.empty?
424
+ dscontents << Sisimai::Bite::Email.DELIVERYSTATUS if dscontents.size == recipients
434
425
 
435
- if dscontents.size == recipients
436
- dscontents << Sisimai::Bite::Email.DELIVERYSTATUS
437
- end
438
426
  b = dscontents[-1]
439
427
  b['recipient'] = r[0][:address]
440
428
  b['agent'] = Sisimai::RFC3464.smtpagent + '::Fallback'
441
429
  recipients += 1
442
430
  end
443
431
  end
432
+ return nil if recipients.zero?
444
433
 
445
- return nil unless recipients > 0
446
434
  require 'sisimai/string'
447
435
  require 'sisimai/smtp/status'
448
-
449
436
  dscontents.map do |e|
450
437
  # Set default values if each value is empty.
451
438
  connheader.each_key { |a| e[a] ||= connheader[a] || '' }
@@ -453,7 +440,7 @@ module Sisimai
453
440
  if e.key?('alterrors') && e['alterrors'].size > 0
454
441
  # Copy alternative error message
455
442
  e['diagnosis'] ||= e['alterrors']
456
- if e['diagnosis'] =~ /\A[-]+/ || e['diagnosis'].end_with?('__')
443
+ if e['diagnosis'].start_with?('-') || e['diagnosis'].end_with?('__')
457
444
  # Override the value of diagnostic code message
458
445
  e['diagnosis'] = e['alterrors'] if e['alterrors'].size > 0
459
446
  end
@@ -467,14 +454,13 @@ module Sisimai
467
454
  e['reason'] = scannedset['reason'] || 'undefined'
468
455
  e['diagnosis'] = scannedset['message'] if scannedset['message'].size > 0
469
456
  e['command'] = ''
470
-
471
457
  else
472
458
  # Set the value of smtpagent
473
459
  e['agent'] = self.smtpagent
474
460
  end
475
461
 
476
462
  e['status'] ||= Sisimai::SMTP::Status.find(e['diagnosis'])
477
- if cv = e['diagnosis'].match(Re1[:command])
463
+ if cv = e['diagnosis'].match(MarkingsOf[:command])
478
464
  e['command'] = cv[1]
479
465
  end
480
466
  e['date'] ||= mhead['date']