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,22 +6,21 @@ module Sisimai::Bite::Email
6
6
  # Imported from p5-Sisimail/lib/Sisimai/Bite/Email/Google.pm
7
7
  require 'sisimai/bite/email'
8
8
 
9
- Re0 = {
10
- :from => %r/[@]googlemail[.]com[>]?\z/,
11
- :subject => %r/Delivery[ ]Status[ ]Notification/,
9
+ Indicators = Sisimai::Bite::Email.INDICATORS
10
+ StartingOf = {
11
+ message: ['Delivery to the following recipient'],
12
+ error: ['The error that the other server returned was:'],
12
13
  }.freeze
13
- Re1 = {
14
- :begin => %r/Delivery to the following recipient/,
15
- :start => %r/Technical details of (?:permanent|temporary) failure:/,
16
- :error => %r/The error that the other server returned was:/,
17
- :rfc822 => %r{\A(?:
14
+ MarkingsOf = {
15
+ start: %r/Technical details of (?:permanent|temporary) failure:/,
16
+ rfc822: %r{\A(?:
18
17
  -----[ ]Original[ ]message[ ]-----
19
18
  |[ \t]*-----[ ]Message[ ]header[ ]follows[ ]-----
20
19
  )\z
21
20
  }x,
22
- :endof => %r/\A__END_OF_EMAIL_MESSAGE__\z/,
23
21
  }.freeze
24
- ReFailure = {
22
+
23
+ ReFailures = {
25
24
  expired: %r{(?:
26
25
  DNS[ ]Error:[ ]Could[ ]not[ ]contact[ ]DNS[ ]servers
27
26
  |Delivery[ ]to[ ]the[ ]following[ ]recipient[ ]has[ ]been[ ]delayed
@@ -107,12 +106,10 @@ module Sisimai::Bite::Email
107
106
  # 550 550 Unknown user *****@***.**.*** (state 18).
108
107
  '18' => { 'command' => 'DATA', 'reason' => 'filtered' },
109
108
  }.freeze
110
- Indicators = Sisimai::Bite::Email.INDICATORS
111
109
 
112
110
  def description; return 'Google Gmail: https://mail.google.com'; end
113
111
  def smtpagent; return Sisimai::Bite.smtpagent(self); end
114
112
  def headerlist; return ['X-Failed-Recipients']; end
115
- def pattern; return Re0; end
116
113
 
117
114
  # Parse bounce messages from Google Gmail
118
115
  # @param [Hash] mhead Message headers of a bounce email
@@ -176,8 +173,8 @@ module Sisimai::Bite::Email
176
173
  # The error that the other server returned was:
177
174
  # 550 5.1.1 <userunknown@example.jp>... User Unknown
178
175
  #
179
- return nil unless mhead['from'] =~ Re0[:from]
180
- return nil unless mhead['subject'] =~ Re0[:subject]
176
+ return nil unless mhead['from'].include?('<mailer-daemon@googlemail.com>')
177
+ return nil unless mhead['subject'].include?('Delivery Status Notification')
181
178
 
182
179
  require 'sisimai/address'
183
180
  dscontents = [Sisimai::Bite.DELIVERYSTATUS]
@@ -189,15 +186,15 @@ module Sisimai::Bite::Email
189
186
  statecode0 = 0 # (Integer) The value of (state *) in the error message
190
187
  v = nil
191
188
 
192
- hasdivided.each do |e|
189
+ while e = hasdivided.shift do
193
190
  if readcursor.zero?
194
191
  # Beginning of the bounce message or delivery status part
195
- readcursor |= Indicators[:deliverystatus] if e =~ Re1[:begin]
192
+ readcursor |= Indicators[:deliverystatus] if e.include?(StartingOf[:message][0])
196
193
  end
197
194
 
198
195
  if (readcursor & Indicators[:'message-rfc822']).zero?
199
196
  # Beginning of the original message part
200
- if e =~ Re1[:rfc822]
197
+ if e =~ MarkingsOf[:rfc822]
201
198
  readcursor |= Indicators[:'message-rfc822']
202
199
  next
203
200
  end
@@ -211,7 +208,6 @@ module Sisimai::Bite::Email
211
208
  next
212
209
  end
213
210
  rfc822list << e
214
-
215
211
  else
216
212
  # Before "message/rfc822"
217
213
  next if (readcursor & Indicators[:deliverystatus]).zero?
@@ -247,18 +243,16 @@ module Sisimai::Bite::Email
247
243
  v['recipient'] = addr0
248
244
  recipients += 1
249
245
  end
250
-
251
246
  else
252
247
  v['diagnosis'] ||= ''
253
- v['diagnosis'] += e + ' '
248
+ v['diagnosis'] << e + ' '
254
249
  end
255
250
  end
256
251
  end
257
-
258
252
  return nil if recipients.zero?
253
+
259
254
  require 'sisimai/string'
260
255
  require 'sisimai/smtp/status'
261
-
262
256
  dscontents.map do |e|
263
257
  e['agent'] = self.smtpagent
264
258
  e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'])
@@ -287,12 +281,11 @@ module Sisimai::Bite::Email
287
281
  # (state *)
288
282
  e['reason'] = StateTable[statecode0]['reason']
289
283
  e['command'] = StateTable[statecode0]['command']
290
-
291
284
  else
292
285
  # No state code
293
- ReFailure.each_key do |r|
286
+ ReFailures.each_key do |r|
294
287
  # Verify each regular expression of session errors
295
- next unless e['diagnosis'] =~ ReFailure[r]
288
+ next unless e['diagnosis'] =~ ReFailures[r]
296
289
  e['reason'] = r.to_s
297
290
  break
298
291
  end
@@ -301,10 +294,7 @@ module Sisimai::Bite::Email
301
294
 
302
295
  # Set pseudo status code
303
296
  e['status'] = Sisimai::SMTP::Status.find(e['diagnosis'])
304
- if e['status'] =~ /\A[45][.][1-7][.][1-9]\z/
305
- # Override bounce reason
306
- e['reason'] = Sisimai::SMTP::Status.name(e['status'])
307
- end
297
+ e['reason'] = Sisimai::SMTP::Status.name(e['status']) if e['status'] =~ /\A[45][.][1-7][.][1-9]\z/
308
298
  end
309
299
 
310
300
  rfc822part = Sisimai::RFC5322.weedout(rfc822list)
@@ -6,28 +6,22 @@ module Sisimai::Bite::Email
6
6
  # Imported from p5-Sisimail/lib/Sisimai/Bite/Email/GSuite.pm
7
7
  require 'sisimai/bite/email'
8
8
 
9
- Re0 = {
10
- :from => %r/[@]googlemail[.]com[>]?\z/,
11
- :subject => %r/Delivery[ ]Status[ ]Notification/,
12
- }.freeze
13
- Re1 = {
14
- :begin => %r/\A[*][*][ ].+[ ][*][*]\z/,
15
- :error => %r/\AThe[ ]response([ ]from[ ]the[ ]remote[ ]server)?[ ]was:\z/,
16
- :html => %r{\AContent-Type:[ ]*text/html;[ ]*charset=['"]?(?:UTF|utf)[-]8['"]?\z},
17
- :rfc822 => %r{\AContent-Type:[ ]*(?:message/rfc822|text/rfc822-headers)\z},
18
- :endof => %r/\A__END_OF_EMAIL_MESSAGE__\z/,
9
+ Indicators = Sisimai::Bite::Email.INDICATORS
10
+ MarkingsOf = {
11
+ message: %r/\A[*][*][ ].+[ ][*][*]\z/,
12
+ rfc822: %r{\AContent-Type:[ ]*(?:message/rfc822|text/rfc822-headers)\z},
13
+ error: %r/\AThe[ ]response([ ]from[ ]the[ ]remote[ ]server)?[ ]was:\z/,
14
+ html: %r{\AContent-Type:[ ]*text/html;[ ]*charset=['"]?(?:UTF|utf)[-]8['"]?\z},
19
15
  }.freeze
20
16
  ErrorMayBe = {
21
- :userunknown => %r/because the address couldn't be found/,
22
- :notaccept => %r/Null MX/,
23
- :networkerror => %r/DNS type .+ lookup of .+ responded with code NXDOMAIN/,
17
+ userunknown: %r/because the address couldn't be found/,
18
+ notaccept: %r/Null MX/,
19
+ networkerror: %r/DNS type .+ lookup of .+ responded with code NXDOMAIN/,
24
20
  }.freeze
25
- Indicators = Sisimai::Bite::Email.INDICATORS
26
21
 
27
22
  def description; return 'G Suite: https://gsuite.google.com'; end
28
23
  def smtpagent; return Sisimai::Bite.smtpagent(self); end
29
24
  def headerlist; return ['X-Gm-Message-State']; end
30
- def pattern; return Re0; end
31
25
 
32
26
  # Parse bounce messages from G Suite (Transfer from G Suite to a destinaion host)
33
27
  # @param [Hash] mhead Message headers of a bounce email
@@ -44,8 +38,8 @@ module Sisimai::Bite::Email
44
38
  return nil unless mhead
45
39
  return nil unless mbody
46
40
 
47
- return nil unless mhead['from'] =~ Re0[:from]
48
- return nil unless mhead['subject'] =~ Re0[:subject]
41
+ return nil unless mhead['from'].include?('<mailer-daemon@googlemail.com>')
42
+ return nil unless mhead['subject'].include?('Delivery Status Notification')
49
43
  return nil unless mhead['x-gm-message-state']
50
44
 
51
45
  require 'sisimai/address'
@@ -55,7 +49,7 @@ module Sisimai::Bite::Email
55
49
  blanklines = 0 # (Integer) The number of blank lines
56
50
  readcursor = 0 # (Integer) Points the current cursor position
57
51
  recipients = 0 # (Integer) The number of 'Final-Recipient' header
58
- endoferror = true # (Integer) Flag for a blank line after error messages
52
+ endoferror = false # (Integer) Flag for a blank line after error messages
59
53
  anotherset = {} # (Hash) Another error information
60
54
  emptylines = 0 # (Integer) The number of empty lines
61
55
  connvalues = 0 # (Integer) Flag, 1 if all the value of connheader have been set
@@ -65,15 +59,15 @@ module Sisimai::Bite::Email
65
59
  }
66
60
  v = nil
67
61
 
68
- hasdivided.each do |e|
62
+ while e = hasdivided.shift do
69
63
  if readcursor.zero?
70
64
  # Beginning of the bounce message or delivery status part
71
- readcursor |= Indicators[:deliverystatus] if e =~ Re1[:begin]
65
+ readcursor |= Indicators[:deliverystatus] if e =~ MarkingsOf[:message]
72
66
  end
73
67
 
74
68
  if (readcursor & Indicators[:'message-rfc822']).zero?
75
69
  # Beginning of the original message part
76
- if e =~ Re1[:rfc822]
70
+ if e =~ MarkingsOf[:rfc822]
77
71
  readcursor |= Indicators[:'message-rfc822']
78
72
  next
79
73
  end
@@ -87,7 +81,6 @@ module Sisimai::Bite::Email
87
81
  next
88
82
  end
89
83
  rfc822list << e
90
-
91
84
  else
92
85
  # Before "message/rfc822"
93
86
  next if (readcursor & Indicators[:deliverystatus]).zero?
@@ -101,7 +94,7 @@ module Sisimai::Bite::Email
101
94
  # Last-Attempt-Date: Fri, 24 Mar 2017 23:34:10 -0700 (PDT)
102
95
  v = dscontents[-1]
103
96
 
104
- if cv = e.match(/\A[Ff]inal-[Rr]ecipient:[ ]*(?:RFC|rfc)822;[ ]*(.+)\z/)
97
+ if cv = e.match(/\AFinal-Recipient:[ ]*(?:RFC|rfc)822;[ ]*(.+)\z/)
105
98
  # Final-Recipient: rfc822; kijitora@example.de
106
99
  if v['recipient']
107
100
  # There are multiple recipient addresses in the message body.
@@ -111,63 +104,60 @@ module Sisimai::Bite::Email
111
104
  v['recipient'] = cv[1]
112
105
  recipients += 1
113
106
 
114
- elsif cv = e.match(/\A[Aa]ction:[ ]*(.+)\z/)
107
+ elsif cv = e.match(/\AAction:[ ]*(.+)\z/)
115
108
  # Action: failed
116
109
  v['action'] = cv[1].downcase
117
110
 
118
- elsif cv = e.match(/\A[Ss]tatus:[ ]*(\d[.]\d+[.]\d+)/)
111
+ elsif cv = e.match(/\AStatus:[ ]*(\d[.]\d+[.]\d+)/)
119
112
  # Status: 5.0.0
120
113
  v['status'] = cv[1]
121
114
 
122
- elsif cv = e.match(/\A[Rr]emote-MTA:[ ]*(?:DNS|dns);[ ]*(.+)\z/)
115
+ elsif cv = e.match(/\ARemote-MTA:[ ]*(?:DNS|dns);[ ]*(.+)\z/)
123
116
  # Remote-MTA: dns; 192.0.2.222 (192.0.2.222, the server for the domain.)
124
117
  v['rhost'] = cv[1].downcase
125
118
  v['rhost'] = '' if v['rhost'] =~ /\A\s+\z/ # Remote-MTA: DNS;
126
119
 
127
- elsif cv = e.match(/\A[Ll]ast-[Aa]ttempt-[Dd]ate:[ ]*(.+)\z/)
120
+ elsif cv = e.match(/\ALast-Attempt-Date:[ ]*(.+)\z/)
128
121
  # Last-Attempt-Date: Fri, 24 Mar 2017 23:34:10 -0700 (PDT)
129
122
  v['date'] = cv[1]
130
-
131
123
  else
132
- if cv = e.match(/\A[Dd]iagnostic-[Cc]ode:[ ]*(.+?);[ ]*(.+)\z/)
124
+ if cv = e.match(/\ADiagnostic-Code:[ ]*(.+?);[ ]*(.+)\z/)
133
125
  # Diagnostic-Code: smtp; 550 #5.1.0 Address rejected.
134
126
  v['spec'] = cv[1].upcase
135
127
  v['diagnosis'] = cv[2]
136
128
  else
137
129
  # Append error messages continued from the previous line
138
- if endoferror && (v['diagnosis'] && v['diagnosis'].size > 0)
139
- endoferror = true if e.empty?
140
- endoferror = true if e.start_with?('--')
130
+ if endoferror == false && v['diagnosis'].to_s.size > 0
131
+ endoferror ||= true if e.empty?
132
+ endoferror ||= true if e.start_with?('--')
141
133
 
142
134
  next if endoferror
143
- next unless e =~ /\A[ ]/
144
- v['diagnosis'] += e
135
+ next unless e.start_with?(' ')
136
+ v['diagnosis'] << e
145
137
  end
146
138
  end
147
139
  end
148
-
149
140
  else
150
141
  # Reporting-MTA: dns; googlemail.com
151
142
  # Received-From-MTA: dns; sironeko@example.jp
152
143
  # Arrival-Date: Fri, 24 Mar 2017 23:34:07 -0700 (PDT)
153
144
  # X-Original-Message-ID: <06C1ED5C-7E02-4036-AEE1-AA448067FB2C@example.jp>
154
- if cv = e.match(/\A[Rr]eporting-MTA:[ ]*(?:DNS|dns);[ ]*(.+)\z/)
145
+ if cv = e.match(/\AReporting-MTA:[ ]*(?:DNS|dns);[ ]*(.+)\z/)
155
146
  # Reporting-MTA: dns; mx.example.jp
156
147
  next if connheader['lhost'].size > 0
157
148
  connheader['lhost'] = cv[1].downcase
158
149
  connvalues += 1
159
150
 
160
- elsif cv = e.match(/\A[Aa]rrival-[Dd]ate:[ ]*(.+)\z/)
151
+ elsif cv = e.match(/\AArrival-Date:[ ]*(.+)\z/)
161
152
  # Arrival-Date: Wed, 29 Apr 2009 16:03:18 +0900
162
153
  next if connheader['date'].size > 0
163
154
  connheader['date'] = cv[1]
164
155
  connvalues += 1
165
-
166
156
  else
167
157
  # Detect SMTP session error or connection error
168
- if e =~ Re1[:error]
158
+ if e =~ MarkingsOf[:error]
169
159
  # The response from the remote server was:
170
- anotherset['diagnosis'] += e
160
+ anotherset['diagnosis'] << e
171
161
  else
172
162
  # ** Address not found **
173
163
  #
@@ -176,7 +166,7 @@ module Sisimai::Bite::Email
176
166
  #
177
167
  # The response from the remote server was:
178
168
  # 550 #5.1.0 Address rejected.
179
- next if e =~ Re1[:html]
169
+ next if e =~ MarkingsOf[:html]
180
170
 
181
171
  if anotherset['diagnosis']
182
172
  # Continued error messages from the previous line like
@@ -187,14 +177,14 @@ module Sisimai::Bite::Email
187
177
  emptylines += 1
188
178
  next
189
179
  end
190
- anotherset['diagnosis'] += ' ' + e
180
+ anotherset['diagnosis'] << ' ' << e
191
181
  else
192
182
  # ** Address not found **
193
183
  #
194
184
  # Your message wasn't delivered to * because the address couldn't be found.
195
185
  # Check for typos or unnecessary spaces and try again.
196
186
  next if e.empty?
197
- next unless e =~ Re1[:begin]
187
+ next unless e =~ MarkingsOf[:message]
198
188
  anotherset['diagnosis'] = e
199
189
  end
200
190
  end
@@ -203,12 +193,11 @@ module Sisimai::Bite::Email
203
193
  end
204
194
  end
205
195
  end
206
-
207
196
  return nil if recipients.zero?
197
+
208
198
  require 'sisimai/string'
209
199
  require 'sisimai/smtp/reply'
210
200
  require 'sisimai/smtp/status'
211
-
212
201
  dscontents.map do |e|
213
202
  # Set default values if each value is empty.
214
203
  connheader.each_key { |a| e[a] ||= connheader[a] || '' }
@@ -224,7 +213,10 @@ module Sisimai::Bite::Email
224
213
  as = nil # status
225
214
  ar = nil # replycode
226
215
 
227
- if e['status'] == '' || e['status'] =~ /\A[45][.]0[.]0\z/
216
+ e['status'] ||= ''
217
+ e['replycode'] ||= ''
218
+
219
+ if e['status'] == '' || e['status'].start_with?('4.0.0', '5.0.0')
228
220
  # Check the value of D.S.N. in anotherset
229
221
  as = Sisimai::SMTP::Status.find(anotherset['diagnosis'])
230
222
  if as.size > 0 && as[-3, 3] != '0.0'
@@ -233,7 +225,7 @@ module Sisimai::Bite::Email
233
225
  end
234
226
  end
235
227
 
236
- if e['replycode'] == '' || e['replycode'] =~ /\A[45]00\z/
228
+ if e['replycode'].empty? || e['replycode'].start_with?('400', '500')
237
229
  # Check the value of SMTP reply code in anotherset
238
230
  ar = Sisimai::SMTP::Reply.find(anotherset['diagnosis'])
239
231
  if ar.size > 0 && ar[-2, 2].to_i != 0
@@ -258,7 +250,6 @@ module Sisimai::Bite::Email
258
250
  e['reason'] = q.to_s
259
251
  break
260
252
  end
261
-
262
253
  end
263
254
 
264
255
  rfc822part = Sisimai::RFC5322.weedout(rfc822list)
@@ -7,41 +7,32 @@ module Sisimai::Bite::Email
7
7
  # Imported from p5-Sisimail/lib/Sisimai/Bite::Email/IMailServer.pm
8
8
  require 'sisimai/bite/email'
9
9
 
10
- Re0 = {
11
- :'x-mailer' => %r/\A[<]SMTP32 v[\d.]+[>][ ]*\z/,
12
- :'subject' => %r/\AUndeliverable Mail[ ]*\z/,
13
- }.freeze
14
- Re1 = {
15
- :begin => %r/\A\z/, # Blank line
16
- :error => %r/Body of message generated response:/,
17
- :rfc822 => %r/\AOriginal message follows[.]\z/,
18
- :endof => %r/\A__END_OF_EMAIL_MESSAGE__\z/,
10
+ Indicators = Sisimai::Bite::Email.INDICATORS
11
+ StartingOf = {
12
+ message: [''], # Blank line
13
+ rfc822: ['Original message follows.'],
14
+ error: ['Body of message generated response:'],
19
15
  }.freeze
16
+
20
17
  ReSMTP = {
21
- conn: %r{(?:
22
- SMTP[ ]connection[ ]failed,
23
- |Unexpected[ ]connection[ ]response[ ]from[ ]server:
24
- )
25
- },
18
+ conn: %r/(?:SMTP connection failed,|Unexpected connection response from server:)/,
26
19
  ehlo: %r|Unexpected response to EHLO/HELO:|,
27
20
  mail: %r|Server response to MAIL FROM:|,
28
21
  rcpt: %r|Additional RCPT TO generated following response:|,
29
22
  data: %r|DATA command generated response:|,
30
23
  }.freeze
31
- ReFailure = {
32
- hostunknown: %r/Unknown[ ]host/x,
33
- userunknown: %r/\A(?:Unknown[ ]user|Invalid[ ]final[ ]delivery[ ]userid)/x,
34
- mailboxfull: %r/\AUser[ ]mailbox[ ]exceeds[ ]allowed[ ]size/x,
35
- securityerr: %r/\ARequested[ ]action[ ]not[ ]taken:[ ]virus[ ]detected/x,
36
- undefined: %r/\Aundeliverable[ ]to[ ]/x,
37
- expired: %r/\ADelivery[ ]failed[ ]\d+[ ]attempts/x,
24
+ ReFailures = {
25
+ hostunknown: %r/Unknown host/,
26
+ userunknown: %r/\A(?:Unknown user|Invalid final delivery userid)/,
27
+ mailboxfull: %r/\AUser mailbox exceeds allowed size/,
28
+ securityerr: %r/\ARequested action not taken: virus detected/,
29
+ undefined: %r/\Aundeliverable to /,
30
+ expired: %r/\ADelivery failed \d+ attempts/,
38
31
  }.freeze
39
- Indicators = Sisimai::Bite::Email.INDICATORS
40
32
 
41
33
  def description; return 'IPSWITCH IMail Server'; end
42
34
  def smtpagent; return Sisimai::Bite.smtpagent(self); end
43
35
  def headerlist; return ['X-Mailer']; end
44
- def pattern; return Re0; end
45
36
 
46
37
  # Parse bounce messages from IMailServer
47
38
  # @param [Hash] mhead Message headers of a bounce email
@@ -59,8 +50,8 @@ module Sisimai::Bite::Email
59
50
  return nil unless mbody
60
51
 
61
52
  match = 0
62
- match += 1 if mhead['subject'] =~ Re0[:subject]
63
- match += 1 if mhead['x-mailer'] && mhead['x-mailer'] =~ Re0[:'x-mailer']
53
+ match += 1 if mhead['subject'] =~ /\AUndeliverable Mail[ ]*\z/
54
+ match += 1 if mhead['x-mailer'].to_s.start_with?('<SMTP32 v')
64
55
  return nil if match.zero?
65
56
 
66
57
  dscontents = [Sisimai::Bite.DELIVERYSTATUS]
@@ -71,10 +62,10 @@ module Sisimai::Bite::Email
71
62
  recipients = 0 # (Integer) The number of 'Final-Recipient' header
72
63
  v = nil
73
64
 
74
- hasdivided.each do |e|
65
+ while e = hasdivided.shift do
75
66
  if readcursor.zero?
76
67
  # Beginning of the bounce message or delivery status part
77
- if e =~ Re1[:begin]
68
+ if e == StartingOf[:message][0]
78
69
  readcursor |= Indicators[:deliverystatus]
79
70
  next
80
71
  end
@@ -82,7 +73,7 @@ module Sisimai::Bite::Email
82
73
 
83
74
  if (readcursor & Indicators[:'message-rfc822']).zero?
84
75
  # Beginning of the original message part
85
- if e =~ Re1[:rfc822]
76
+ if e == StartingOf[:rfc822][0]
86
77
  readcursor |= Indicators[:'message-rfc822']
87
78
  next
88
79
  end
@@ -96,7 +87,6 @@ module Sisimai::Bite::Email
96
87
  next
97
88
  end
98
89
  rfc822list << e
99
-
100
90
  else
101
91
  # Before "message/rfc822"
102
92
  break if readcursor & Indicators[:'message-rfc822'] > 0
@@ -126,24 +116,20 @@ module Sisimai::Bite::Email
126
116
  end
127
117
  v['recipient'] = cv[1]
128
118
  recipients += 1
129
-
130
119
  else
131
120
  # Other error message text
132
- v['alterrors'] += ' ' + e if v['alterrors']
133
- if e =~ Re1[:error]
134
- # Body of message generated response:
135
- v['alterrors'] = e
136
- end
121
+ v['alterrors'] << ' ' << e if v['alterrors']
122
+ v['alterrors'] = e if e.include?(StartingOf[:error][0])
137
123
  end
138
124
  end
139
125
  end
140
126
  return nil if recipients.zero?
141
- require 'sisimai/string'
142
127
 
128
+ require 'sisimai/string'
143
129
  dscontents.map do |e|
144
130
  e['agent'] = self.smtpagent
145
131
 
146
- if e['alterrors'] && e['alterrors'].size > 0
132
+ if e['alterrors'].to_s.size > 0
147
133
  # Copy alternative error message
148
134
  e['diagnosis'] = if e['diagnosis']
149
135
  e['alterrors'] + ' ' + e['diagnosis']
@@ -162,9 +148,9 @@ module Sisimai::Bite::Email
162
148
  break
163
149
  end
164
150
 
165
- ReFailure.each_key do |r|
151
+ ReFailures.each_key do |r|
166
152
  # Verify each regular expression of session errors
167
- next unless e['diagnosis'] =~ ReFailure[r]
153
+ next unless e['diagnosis'] =~ ReFailures[r]
168
154
  e['reason'] = r.to_s
169
155
  break
170
156
  end