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
@@ -7,23 +7,20 @@ module Sisimai::Bite::Email
7
7
  # MTA module for qmail clones
8
8
  require 'sisimai/bite/email'
9
9
 
10
- Re0 = {
11
- :subject => %r{\A(?:
12
- failure[ ]notice
13
- |Permanent[ ]Delivery[ ]Failure
14
- )
15
- }xi,
16
- :received => %r/\A[(]qmail[ ]+\d+[ ]+invoked[ ]+for[ ]+bounce[)]/,
10
+ Indicators = Sisimai::Bite::Email.INDICATORS
11
+ StartingOf = {
12
+ error: ['Remote host said:'],
13
+ rfc822: ['--- Below this line is a copy of the message.', '--- Original message follows.'],
17
14
  }.freeze
18
- # qmail-remote.c:248| if (code >= 500) {
19
- # qmail-remote.c:249| out("h"); outhost(); out(" does not like recipient.\n");
20
- # qmail-remote.c:265| if (code >= 500) quit("D"," failed on DATA command");
21
- # qmail-remote.c:271| if (code >= 500) quit("D"," failed after I sent the message");
22
- #
23
- # Characters: K,Z,D in qmail-qmqpc.c, qmail-send.c, qmail-rspawn.c
24
- # K = success, Z = temporary error, D = permanent error
25
- Re1 = {
26
- :begin => %r{\A(?>
15
+ MarkingsOf = {
16
+ # qmail-remote.c:248| if (code >= 500) {
17
+ # qmail-remote.c:249| out("h"); outhost(); out(" does not like recipient.\n");
18
+ # qmail-remote.c:265| if (code >= 500) quit("D"," failed on DATA command");
19
+ # qmail-remote.c:271| if (code >= 500) quit("D"," failed after I sent the message");
20
+ #
21
+ # Characters: K,Z,D in qmail-qmqpc.c, qmail-send.c, qmail-rspawn.c
22
+ # K = success, Z = temporary error, D = permanent error
23
+ message: %r{\A(?>
27
24
  He/Her[ ]is[ ]not.+[ ]user
28
25
  |Hi[.][ ].+[ ]unable[ ]to[ ]deliver[ ]your[ ]message[ ]to[ ]
29
26
  the[ ]following[ ]addresses
@@ -40,29 +37,22 @@ module Sisimai::Bite::Email
40
37
  )
41
38
  |We're[ ]sorry[.]
42
39
  )
43
- }ix,
44
- :rfc822 => %r{\A(?:
45
- ---[ ]Below[ ]this[ ]line[ ]is[ ]a[ ]copy[ ]of[ ]the[ ]message[.]
46
- |---[ ]Original[ ]message[ ]follows[.]
47
- )
48
- }xi,
49
- :error => %r/\ARemote host said:/,
50
- :sorry => %r/\A[Ss]orry[,.][ ]/,
51
- :endof => %r/\A__END_OF_EMAIL_MESSAGE__\z/,
40
+ }x,
52
41
  }.freeze
42
+
53
43
  ReSMTP = {
54
44
  # Error text regular expressions which defined in qmail-remote.c
55
45
  # qmail-remote.c:225| if (smtpcode() != 220) quit("ZConnected to "," but greeting failed");
56
- conn: %r/(?:Error:)?Connected[ ]to[ ].+[ ]but[ ]greeting[ ]failed[.]/x,
46
+ conn: %r/(?:Error:)?Connected to .+ but greeting failed[.]/,
57
47
  # qmail-remote.c:231| if (smtpcode() != 250) quit("ZConnected to "," but my name was rejected");
58
- ehlo: %r/(?:Error:)?Connected[ ]to[ ].+[ ]but[ ]my[ ]name[ ]was[ ]rejected[.]/x,
48
+ ehlo: %r/(?:Error:)?Connected to .+ but my name was rejected[.]/,
59
49
  # qmail-remote.c:238| if (code >= 500) quit("DConnected to "," but sender was rejected");
60
50
  # reason = rejected
61
- mail: %r/(?:Error:)?Connected[ ]to[ ].+[ ]but[ ]sender[ ]was[ ]rejected[.]/x,
51
+ mail: %r/(?:Error:)?Connected to .+ but sender was rejected[.]/,
62
52
  # qmail-remote.c:249| out("h"); outhost(); out(" does not like recipient.\n");
63
53
  # qmail-remote.c:253| out("s"); outhost(); out(" does not like recipient.\n");
64
54
  # reason = userunknown
65
- rcpt: %r/(?:Error:)?.+[ ]does[ ]not[ ]like[ ]recipient[.]/x,
55
+ rcpt: %r/(?:Error:)?.+ does not like recipient[.]/,
66
56
  # qmail-remote.c:265| if (code >= 500) quit("D"," failed on DATA command");
67
57
  # qmail-remote.c:266| if (code >= 400) quit("Z"," failed on DATA command");
68
58
  # qmail-remote.c:271| if (code >= 500) quit("D"," failed after I sent the message");
@@ -106,26 +96,24 @@ module Sisimai::Bite::Email
106
96
  )
107
97
  }x,
108
98
  }.freeze
109
- # userunknown + expired
110
- ReOnHold = %r/\A[^ ]+ does not like recipient[.][ ]+.+this message has been in the queue too long[.]\z/
111
- # qmail-remote-fallback.patch
112
- ReCommand = %r/Sorry,[ ]no[ ]SMTP[ ]connection[ ]got[ ]far[ ]enough;[ ]most[ ]progress[ ]was[ ]([A-Z]{4})[ ]/x
113
- ReFailure = {
99
+
100
+ # qmail-send.c:922| ... (&dline[c],"I'm not going to try again; this message has been in the queue too long.\n")) nomem();
101
+ ReDelaying = %r/this message has been in the queue too long[.]\z/
102
+ ReIsOnHold = %r/\A[^ ]+ does not like recipient[.][ ]+.+this message has been in the queue too long[.]\z/
103
+ ReCommands = %r/Sorry, no SMTP connection got far enough; most progress was ([A-Z]{4})[ ]/
104
+ ReFailures = {
114
105
  # qmail-local.c:589| strerr_die1x(100,"Sorry, no mailbox here by that name. (#5.1.1)");
115
106
  # qmail-remote.c:253| out("s"); outhost(); out(" does not like recipient.\n");
116
- userunknown: %r{(?:
117
- no[ ]mailbox[ ]here[ ]by[ ]that[ ]name
118
- |[ ]does[ ]not[ ]like[ ]recipient[.]
119
- )
120
- }x,
107
+ userunknown: %r/(?:no mailbox here by that name | does not like recipient[.])/,
121
108
  # error_str.c:192| X(EDQUOT,"disk quota exceeded")
122
- mailboxfull: %r/disk[ ]quota[ ]exceeded/x,
109
+ mailboxfull: %r/disk quota exceeded/,
123
110
  # qmail-qmtpd.c:233| ... result = "Dsorry, that message size exceeds my databytes limit (#5.3.4)";
124
111
  # qmail-smtpd.c:391| ... out("552 sorry, that message size exceeds my databytes limit (#5.3.4)\r\n"); return;
125
- mesgtoobig: %r/Message[ ]size[ ]exceeds[ ]fixed[ ]maximum[ ]message[ ]size:/x,
112
+ mesgtoobig: %r/Message size exceeds fixed maximum message size:/,
126
113
  # qmail-remote.c:68| Sorry, I couldn't find any host by that name. (#4.1.2)\n"); zerodie();
127
114
  # qmail-remote.c:78| Sorry, I couldn't find any host named ");
128
- hostunknown: %r/\ASorry[,][ ]I[ ]couldn[']t[ ]find[ ]any[ ]host[ ]/x,
115
+ hostunknown: %r/\ASorry, I couldn't find any host /,
116
+ systemfull: %r/Requested action not taken: mailbox unavailable [(]not enough free space[)]/,
129
117
  systemerror: %r{(?>
130
118
  bad[ ]interpreter:[ ]No[ ]such[ ]file[ ]or[ ]directory
131
119
  |system[ ]error
@@ -138,16 +126,11 @@ module Sisimai::Bite::Email
138
126
  |[.][ ]Although[ ]I[']m[ ]listed[ ]as[ ]a[ ]best[-]preference[ ]MX[ ]or[ ]A[ ]for[ ]that[ ]host
139
127
  )
140
128
  }x,
141
- systemfull: %r/Requested action not taken: mailbox unavailable [(]not enough free space[)]/,
142
129
  }.freeze
143
- # qmail-send.c:922| ... (&dline[c],"I'm not going to try again; this message has been in the queue too long.\n")) nomem();
144
- ReDelayed = %r/this[ ]message[ ]has[ ]been[ ]in[ ]the[ ]queue[ ]too[ ]long[.]\z/x
145
- Indicators = Sisimai::Bite::Email.INDICATORS
146
130
 
147
131
  def description; return 'Unknown MTA #4'; end
148
132
  def smtpagent; return Sisimai::Bite.smtpagent(self); end
149
133
  def headerlist; return []; end
150
- def pattern; return Re0; end
151
134
 
152
135
  # Parse bounce messages from Unknown MTA #4
153
136
  # @param [Hash] mhead Message headers of a bounce email
@@ -168,9 +151,10 @@ module Sisimai::Bite::Email
168
151
  # by qmail, see http://cr.yp.to/qmail.html
169
152
  # e.g.) Received: (qmail 12345 invoked for bounce); 29 Apr 2009 12:34:56 -0000
170
153
  # Subject: failure notice
154
+ tryto = %r/\A[(]qmail[ ]+\d+[ ]+invoked[ ]+for[ ]+bounce[)]/
171
155
  match = 0
172
- match += 1 if mhead['subject'] =~ Re0[:subject]
173
- match += 1 if mhead['received'].find { |a| a =~ Re0[:received] }
156
+ match += 1 if mhead['subject'].start_with?('failure notice', 'Permanent Delivery Failure')
157
+ match += 1 if mhead['received'].find { |a| a =~ tryto }
174
158
  return nil if match.zero?
175
159
 
176
160
  dscontents = [Sisimai::Bite.DELIVERYSTATUS]
@@ -181,10 +165,10 @@ module Sisimai::Bite::Email
181
165
  recipients = 0 # (Integer) The number of 'Final-Recipient' header
182
166
  v = nil
183
167
 
184
- hasdivided.each do |e|
168
+ while e = hasdivided.shift do
185
169
  if readcursor.zero?
186
170
  # Beginning of the bounce message or delivery status part
187
- if e =~ Re1[:begin]
171
+ if e =~ MarkingsOf[:message]
188
172
  readcursor |= Indicators[:deliverystatus]
189
173
  next
190
174
  end
@@ -192,7 +176,7 @@ module Sisimai::Bite::Email
192
176
 
193
177
  if (readcursor & Indicators[:'message-rfc822']).zero?
194
178
  # Beginning of the original message part
195
- if e =~ Re1[:rfc822]
179
+ if e.start_with?(StartingOf[:rfc822][0], StartingOf[:rfc822][1])
196
180
  readcursor |= Indicators[:'message-rfc822']
197
181
  next
198
182
  end
@@ -206,7 +190,6 @@ module Sisimai::Bite::Email
206
190
  next
207
191
  end
208
192
  rfc822list << e
209
-
210
193
  else
211
194
  # Before "message/rfc822"
212
195
  next if (readcursor & Indicators[:deliverystatus]).zero?
@@ -232,8 +215,8 @@ module Sisimai::Bite::Email
232
215
  # Append error message
233
216
  next if e.empty?
234
217
  v['diagnosis'] ||= ''
235
- v['diagnosis'] += e + ' '
236
- v['alterrors'] = e if e =~ Re1[:error]
218
+ v['diagnosis'] << e + ' '
219
+ v['alterrors'] = e if e.start_with?(StartingOf[:error][0])
237
220
 
238
221
  next if v['rhost']
239
222
  if cv = e.match(ReHost)
@@ -243,8 +226,8 @@ module Sisimai::Bite::Email
243
226
  end
244
227
  end
245
228
  return nil if recipients.zero?
246
- require 'sisimai/string'
247
229
 
230
+ require 'sisimai/string'
248
231
  dscontents.map do |e|
249
232
  e['agent'] = self.smtpagent
250
233
  e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'])
@@ -260,7 +243,7 @@ module Sisimai::Bite::Email
260
243
 
261
244
  unless e['command']
262
245
  # Verify each regular expression of patches
263
- if cv = e['diagnosis'].match(ReCommand)
246
+ if cv = e['diagnosis'].match(ReCommands)
264
247
  e['command'] = cv[1].upcase
265
248
  end
266
249
  e['command'] ||= ''
@@ -272,28 +255,26 @@ module Sisimai::Bite::Email
272
255
  # MAIL | Connected to 192.0.2.135 but sender was rejected.
273
256
  e['reason'] = 'rejected'
274
257
 
275
- elsif e['command'] =~ /\A(?:HELO|EHLO)\z/
258
+ elsif %w[HELO EHLO].index(e['command'])
276
259
  # HELO | Connected to 192.0.2.135 but my name was rejected.
277
260
  e['reason'] = 'blocked'
278
-
279
261
  else
280
262
  # Try to match with each error message in the table
281
- if e['diagnosis'] =~ ReOnHold
263
+ if e['diagnosis'] =~ ReIsOnHold
282
264
  # To decide the reason require pattern match with
283
265
  # Sisimai::Reason::* modules
284
266
  e['reason'] = 'onhold'
285
-
286
267
  else
287
- ReFailure.each_key do |r|
268
+ ReFailures.each_key do |r|
288
269
  # Verify each regular expression of session errors
289
270
  if e['alterrors']
290
271
  # Check the value of "alterrors"
291
- next unless e['alterrors'] =~ ReFailure[r]
272
+ next unless e['alterrors'] =~ ReFailures[r]
292
273
  e['reason'] = r.to_s
293
274
  end
294
275
  break if e['reason']
295
276
 
296
- next unless e['diagnosis'] =~ ReFailure[r]
277
+ next unless e['diagnosis'] =~ ReFailures[r]
297
278
  e['reason'] = r.to_s
298
279
  break
299
280
  end
@@ -308,7 +289,7 @@ module Sisimai::Bite::Email
308
289
  end
309
290
 
310
291
  unless e['reason']
311
- e['reason'] = 'expired' if e['diagnosis'] =~ ReDelayed
292
+ e['reason'] = 'expired' if e['diagnosis'] =~ ReDelaying
312
293
  end
313
294
  end
314
295
  end
@@ -6,21 +6,15 @@ module Sisimai::Bite::Email
6
6
  # Imported from p5-Sisimail/lib/Sisimai/Bite/Email/X5.pm
7
7
  require 'sisimai/bite/email'
8
8
 
9
- Re0 = {
10
- :from => %r/\bTWFpbCBEZWxpdmVyeSBTdWJzeXN0ZW0\b/,
11
- :to => %r/\bNotificationRecipients\b/,
12
- }.freeze
13
- Re1 = {
14
- :begin => %r|\AContent-Type: message/delivery-status|,
15
- :rfc822 => %r|\AContent-Type: message/rfc822|,
16
- :endof => %r/\A__END_OF_EMAIL_MESSAGE__\z/,
17
- }.freeze
18
9
  Indicators = Sisimai::Bite::Email.INDICATORS
10
+ StartingOf = {
11
+ message: ['Content-Type: message/delivery-status'],
12
+ rfc822: ['Content-Type: message/rfc822'],
13
+ }.freeze
19
14
 
20
15
  def description; return 'Unknown MTA #5'; end
21
16
  def smtpagent; return Sisimai::Bite.smtpagent(self); end
22
17
  def headerlist; return []; end
23
- def pattern; return Re0; end
24
18
 
25
19
  # Parse bounce messages from Unknown MTA #5
26
20
  # @param [Hash] mhead Message headers of a bounce email
@@ -36,19 +30,17 @@ module Sisimai::Bite::Email
36
30
  def scan(mhead, mbody)
37
31
  return nil unless mhead
38
32
  return nil unless mbody
39
- match = 0
40
-
41
- # To: "NotificationRecipients" <...>
42
- match += 1 if mhead['to'] && mhead['to'] =~ Re0[:to]
43
-
44
33
  require 'sisimai/mime'
45
- if mhead['from'] =~ Re0[:from]
34
+
35
+ match = 0
36
+ match += 1 if mhead['to'].to_s.include?('NotificationRecipients')
37
+ if mhead['from'].include?('TWFpbCBEZWxpdmVyeSBTdWJzeXN0ZW0')
46
38
  # From: "=?iso-2022-jp?B?TWFpbCBEZWxpdmVyeSBTdWJzeXN0ZW0=?=" <...>
47
39
  # Mail Delivery Subsystem
48
40
  mhead['from'].split(' ').each do |f|
49
41
  # Check each element of From: header
50
42
  next unless Sisimai::MIME.is_mimeencoded(f)
51
- match += 1 if Sisimai::MIME.mimedecode([f]) =~ /Mail Delivery Subsystem/
43
+ match += 1 if Sisimai::MIME.mimedecode([f]).include?('Mail Delivery Subsystem')
52
44
  break
53
45
  end
54
46
  end
@@ -56,7 +48,7 @@ module Sisimai::Bite::Email
56
48
  if Sisimai::MIME.is_mimeencoded(mhead['subject'])
57
49
  # Subject: =?iso-2022-jp?B?UmV0dXJuZWQgbWFpbDogVXNlciB1bmtub3du?=
58
50
  plain = Sisimai::MIME.mimedecode([mhead['subject']])
59
- match += 1 if plain =~ /Mail Delivery Subsystem/
51
+ match += 1 if plain.include?('Mail Delivery Subsystem')
60
52
  end
61
53
  return nil if match < 2
62
54
 
@@ -69,14 +61,14 @@ module Sisimai::Bite::Email
69
61
  recipients = 0 # (Integer) The number of 'Final-Recipient' header
70
62
  v = nil
71
63
 
72
- hasdivided.each do |e|
64
+ while e = hasdivided.shift do
73
65
  # Save the current line for the next loop
74
66
  havepassed << e
75
67
  p = havepassed[-2]
76
68
 
77
69
  if readcursor.zero?
78
70
  # Beginning of the bounce message or delivery status part
79
- if e =~ Re1[:begin]
71
+ if e.start_with?(StartingOf[:message][0])
80
72
  readcursor |= Indicators[:deliverystatus]
81
73
  next
82
74
  end
@@ -84,7 +76,7 @@ module Sisimai::Bite::Email
84
76
 
85
77
  if (readcursor & Indicators[:'message-rfc822']).zero?
86
78
  # Beginning of the original message part
87
- if e =~ Re1[:rfc822]
79
+ if e.start_with?(StartingOf[:rfc822][0])
88
80
  readcursor |= Indicators[:'message-rfc822']
89
81
  next
90
82
  end
@@ -95,7 +87,7 @@ module Sisimai::Bite::Email
95
87
  next if e.empty?
96
88
  v = dscontents[-1]
97
89
 
98
- if cv = e.match(/\A[Ff]inal-[Rr]ecipient:[ ]*(?:RFC|rfc)822;[ ]*([^ ]+)\z/)
90
+ if cv = e.match(/\AFinal-Recipient:[ ]*(?:RFC|rfc)822;[ ]*([^ ]+)\z/)
99
91
  # Final-Recipient: RFC822; kijitora@example.jp
100
92
  if v['recipient']
101
93
  # There are multiple recipient addresses in the message body.
@@ -105,44 +97,42 @@ module Sisimai::Bite::Email
105
97
  v['recipient'] = cv[1]
106
98
  recipients += 1
107
99
 
108
- elsif cv = e.match(/\A[Xx]-[Aa]ctual-[Rr]ecipient:[ ]*(?:RFC|rfc)822;[ ]*([^ ]+)\z/) ||
109
- e.match(/\A[Oo]riginal-[Rr]ecipient:[ ]*(?:RFC|rfc)822;[ ]*([^ ]+)\z/)
100
+ elsif cv = e.match(/\AX-Actual-Recipient:[ ]*(?:RFC|rfc)822;[ ]*([^ ]+)\z/) ||
101
+ e.match(/\AOriginal-Recipient:[ ]*(?:RFC|rfc)822;[ ]*([^ ]+)\z/)
110
102
  # X-Actual-Recipient: RFC822; kijitora@example.co.jp
111
103
  # Original-Recipient: rfc822;kijitora@example.co.jp
112
104
  v['alias'] = cv[1]
113
105
 
114
- elsif cv = e.match(/\A[Aa]ction:[ ]*(.+)\z/)
106
+ elsif cv = e.match(/\AAction:[ ]*(.+)\z/)
115
107
  # Action: failed
116
108
  v['action'] = cv[1].downcase
117
109
 
118
- elsif cv = e.match(/\A[Ss]tatus:[ ]*(\d[.]\d+[.]\d+)/)
110
+ elsif cv = e.match(/\AStatus:[ ]*(\d[.]\d+[.]\d+)/)
119
111
  # Status: 5.1.1
120
112
  v['status'] = cv[1]
121
113
 
122
- elsif cv = e.match(/\A[Rr]eporting-MTA:[ ]*(?:DNS|dns);[ ]*(.+)\z/)
114
+ elsif cv = e.match(/\AReporting-MTA:[ ]*(?:DNS|dns);[ ]*(.+)\z/)
123
115
  # Reporting-MTA: dns; mx.example.jp
124
116
  v['lhost'] = cv[1].downcase
125
117
 
126
- elsif cv = e.match(/\A[Rr]emote-MTA:[ ]*(?:DNS|dns);[ ]*(.+)\z/)
118
+ elsif cv = e.match(/\ARemote-MTA:[ ]*(?:DNS|dns);[ ]*(.+)\z/)
127
119
  # Remote-MTA: DNS; mx.example.jp
128
120
  v['rhost'] = cv[1].downcase
129
121
 
130
- elsif cv = e.match(/\A[Ll]ast-[Aa]ttempt-[Dd]ate:[ ]*(.+)\z/)
122
+ elsif cv = e.match(/\ALast-Attempt-Date:[ ]*(.+)\z/)
131
123
  # Last-Attempt-Date: Fri, 14 Feb 2014 12:30:08 -0500
132
124
  v['date'] = cv[1]
133
-
134
125
  else
135
126
  # Get an error message from Diagnostic-Code: field
136
- if cv = e.match(/\A[Dd]iagnostic-[Cc]ode:[ ]*(.+?);[ ]*(.+)\z/)
127
+ if cv = e.match(/\ADiagnostic-Code:[ ]*(.+?);[ ]*(.+)\z/)
137
128
  # Diagnostic-Code: SMTP; 550 5.1.1 <userunknown@example.jp>... User Unknown
138
129
  v['spec'] = cv[1].downcase
139
130
  v['diagnosis'] = cv[2]
140
131
 
141
- elsif p =~ /\A[Dd]iagnostic-[Cc]ode:[ ]*/ && cv = e.match(/\A[ \t]+(.+)\z/)
132
+ elsif p.start_with?('Diagnostic-Code:') && cv = e.match(/\A[ \t]+(.+)\z/)
142
133
  # Continued line of the value of Diagnostic-Code header
143
- v['diagnosis'] ||= ''
144
- v['diagnosis'] += ' ' + cv[1]
145
- havepassed[-1] = 'Diagnostic-Code: ' + e
134
+ v['diagnosis'] << ' ' << cv[1]
135
+ havepassed[-1] = 'Diagnostic-Code: ' << e
146
136
  end
147
137
  end
148
138
  else
@@ -156,12 +146,11 @@ module Sisimai::Bite::Email
156
146
  next
157
147
  end
158
148
  rfc822list << e
159
-
160
149
  end
161
150
  end
162
151
  return nil if recipients.zero?
163
- require 'sisimai/string'
164
152
 
153
+ require 'sisimai/string'
165
154
  dscontents.map do |e|
166
155
  e['agent'] = self.smtpagent
167
156
  e['diagnosis'] ||= Sisimai::String.sweep(e['diagnosis'])
@@ -6,15 +6,11 @@ module Sisimai::Bite::Email
6
6
  # Imported from p5-Sisimail/lib/Sisimai/Bite/Email/Yahoo.pm
7
7
  require 'sisimai/bite/email'
8
8
 
9
- Re0 = {
10
- :subject => %r/\AFailure Notice\z/,
11
- }.freeze
12
- Re1 = {
13
- :begin => %r/\ASorry, we were unable to deliver your message/,
14
- :rfc822 => %r/\A--- Below this line is a copy of the message[.]\z/,
15
- :endof => %r/\A__END_OF_EMAIL_MESSAGE__\z/,
16
- }.freeze
17
9
  Indicators = Sisimai::Bite::Email.INDICATORS
10
+ StartingOf = {
11
+ message: ['Sorry, we were unable to deliver your message'],
12
+ rfc822: ['--- Below this line is a copy of the message.'],
13
+ }.freeze
18
14
 
19
15
  def description; return 'Yahoo! MAIL: https://www.yahoo.com'; end
20
16
  def smtpagent; return Sisimai::Bite.smtpagent(self); end
@@ -24,7 +20,6 @@ module Sisimai::Bite::Email
24
20
  # X-YMail-OSG: bTIbpDEVM1lHz...
25
21
  # X-Originating-IP: [192.0.2.9]
26
22
  def headerlist; return ['X-YMailISG']; end
27
- def pattern; return Re0; end
28
23
 
29
24
  # Parse bounce messages from Yahoo! MAIL
30
25
  # @param [Hash] mhead Message headers of a bounce email
@@ -40,6 +35,8 @@ module Sisimai::Bite::Email
40
35
  def scan(mhead, mbody)
41
36
  return nil unless mhead
42
37
  return nil unless mbody
38
+
39
+ # :subject => %r/\AFailure Notice\z/,
43
40
  return nil unless mhead['x-ymailisg']
44
41
 
45
42
  dscontents = [Sisimai::Bite.DELIVERYSTATUS]
@@ -50,10 +47,10 @@ module Sisimai::Bite::Email
50
47
  recipients = 0 # (Integer) The number of 'Final-Recipient' header
51
48
  v = nil
52
49
 
53
- hasdivided.each do |e|
50
+ while e = hasdivided.shift do
54
51
  if readcursor.zero?
55
52
  # Beginning of the bounce message or delivery status part
56
- if e =~ Re1[:begin]
53
+ if e.start_with?(StartingOf[:message][0])
57
54
  readcursor |= Indicators[:deliverystatus]
58
55
  next
59
56
  end
@@ -61,7 +58,7 @@ module Sisimai::Bite::Email
61
58
 
62
59
  if (readcursor & Indicators[:'message-rfc822']).zero?
63
60
  # Beginning of the original message part
64
- if e =~ Re1[:rfc822]
61
+ if e == StartingOf[:rfc822][0]
65
62
  readcursor |= Indicators[:'message-rfc822']
66
63
  next
67
64
  end
@@ -75,7 +72,6 @@ module Sisimai::Bite::Email
75
72
  next
76
73
  end
77
74
  rfc822list << e
78
-
79
75
  else
80
76
  # Before "message/rfc822"
81
77
  next if (readcursor & Indicators[:deliverystatus]).zero?
@@ -96,7 +92,6 @@ module Sisimai::Bite::Email
96
92
  end
97
93
  v['recipient'] = cv[1]
98
94
  recipients += 1
99
-
100
95
  else
101
96
  if e.start_with?('Remote host said:')
102
97
  # Remote host said: 550 5.1.1 <kijitora@example.org>... User Unknown [RCPT_TO]
@@ -106,13 +101,12 @@ module Sisimai::Bite::Email
106
101
  # Get SMTP command from the value of "Remote host said:"
107
102
  v['command'] = cv[1]
108
103
  end
109
-
110
104
  else
111
105
  # <mailboxfull@example.jp>:
112
106
  # Remote host said:
113
107
  # 550 5.2.2 <mailboxfull@example.jp>... Mailbox Full
114
108
  # [RCPT_TO]
115
- if v['diagnosis'] =~ /\ARemote host said:\z/
109
+ if v['diagnosis'].start_with?('Remote host said:')
116
110
  # Remote host said:
117
111
  # 550 5.2.2 <mailboxfull@example.jp>... Mailbox Full
118
112
  if cv = e.match(/\[([A-Z]{4}).*\]\z/)
@@ -123,15 +117,13 @@ module Sisimai::Bite::Email
123
117
  v['diagnosis'] = e
124
118
  end
125
119
  end
126
-
127
120
  end
128
-
129
121
  end
130
122
  end
131
123
  end
132
124
  return nil if recipients.zero?
133
- require 'sisimai/string'
134
125
 
126
+ require 'sisimai/string'
135
127
  dscontents.map do |e|
136
128
  e['diagnosis'] = e['diagnosis'].gsub(/\\n/, ' ')
137
129
  e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'])