sisimai 4.22.3-java → 4.22.4-java

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 +4 -4
  130. data/lib/sisimai/skeleton.rb +0 -43
@@ -8,29 +8,18 @@ module Sisimai::Bite::Email
8
8
  # Based on Sisimai::Bite::Email::Exim
9
9
  require 'sisimai/bite/email'
10
10
 
11
- Re0 = {
12
- :'from' => %r/\AMail Delivery System/,
13
- :'subject' => %r{(?:
14
- Mail[ ]delivery[ ]failed(:[ ]returning[ ]message[ ]to[ ]sender)?
15
- |Warning:[ ]message[ ].+[ ]delayed[ ]+
16
- |Delivery[ ]Status[ ]Notification
17
- )
18
- }x,
19
- :'message-id' => %r/\A[<]mxl[~][0-9a-f]+/,
20
- }.freeze
21
- Re1 = {
22
- :rfc822 => %r/\AIncluded is a copy of the message header:\z/,
23
- :begin => %r/\AThis message was created automatically by mail delivery software[.]\z/,
24
- :endof => %r/\A__END_OF_EMAIL_MESSAGE__\z/,
11
+ Indicators = Sisimai::Bite::Email.INDICATORS
12
+ StartingOf = {
13
+ message: ['This message was created automatically by mail delivery software.'],
14
+ rfc822: ['Included is a copy of the message header:'],
25
15
  }.freeze
26
- ReCommand = [
16
+
17
+ ReCommands = [
27
18
  %r/SMTP error from remote (?:mail server|mailer) after ([A-Za-z]{4})/,
28
19
  %r/SMTP error from remote (?:mail server|mailer) after end of ([A-Za-z]{4})/,
29
20
  ].freeze
30
- ReFailure = {
31
- userunknown: %r{
32
- user[ ]not[ ]found
33
- }x,
21
+ ReFailures = {
22
+ userunknown: %r/user not found/,
34
23
  hostunknown: %r{(?>
35
24
  all[ ](?:
36
25
  host[ ]address[ ]lookups[ ]failed[ ]permanently
@@ -39,12 +28,8 @@ module Sisimai::Bite::Email
39
28
  |Unrouteable[ ]address
40
29
  )
41
30
  }x,
42
- mailboxfull: %r{(?:
43
- mailbox[ ]is[ ]full:?
44
- |error:[ ]quota[ ]exceed
45
- )
46
- }x,
47
- notaccept: %r{(?:
31
+ mailboxfull: %r/(?:mailbox is full:?|error: quota exceed)/,
32
+ notaccept: %r{(?:
48
33
  an[ ]MX[ ]or[ ]SRV[ ]record[ ]indicated[ ]no[ ]SMTP[ ]service
49
34
  |no[ ]host[ ]found[ ]for[ ]existing[ ]SMTP[ ]connection
50
35
  )
@@ -55,11 +40,9 @@ module Sisimai::Bite::Email
55
40
  |LMTP[ ]error[ ]after[ ]
56
41
  )
57
42
  }x,
58
- contenterror: %r{
59
- Too[ ]many[ ]["]Received["][ ]headers
60
- }x,
43
+ contenterror: %r/Too many ["]Received["] headers/,
61
44
  }.freeze
62
- ReDelayed = %r{(?:
45
+ ReDelaying = %r{(?:
63
46
  retry[ ]timeout[ ]exceeded
64
47
  |No[ ]action[ ]is[ ]required[ ]on[ ]your[ ]part
65
48
  |retry[ ]time[ ]not[ ]reached[ ]for[ ]any[ ]host[ ]after[ ]a[ ]long[ ]failure[ ]period
@@ -68,7 +51,6 @@ module Sisimai::Bite::Email
68
51
  |Message[ ].+[ ](?:has[ ]been[ ]frozen|was[ ]frozen[ ]on[ ]arrival[ ]by[ ])
69
52
  )
70
53
  }x
71
- Indicators = Sisimai::Bite::Email.INDICATORS
72
54
 
73
55
  def description; return 'McAfee SaaS'; end
74
56
  def smtpagent; return Sisimai::Bite.smtpagent(self); end
@@ -76,7 +58,6 @@ module Sisimai::Bite::Email
76
58
  # X-MXL-NoteHash: ffffffffffffffff-0000000000000000000000000000000000000000
77
59
  # X-MXL-Hash: 4c9d4d411993da17-bbd4212b6c887f6c23bab7db4bd87ef5edc00758
78
60
  def headerlist; return ['X-MXL-NoteHash', 'X-MXL-Hash', 'X-MX-Bounce']; end
79
- def pattern; return Re0; end
80
61
 
81
62
  # Parse bounce messages from MXLogic
82
63
  # @param [Hash] mhead Message headers of a bounce email
@@ -93,12 +74,18 @@ module Sisimai::Bite::Email
93
74
  return nil unless mhead
94
75
  return nil unless mbody
95
76
 
77
+ # :'message-id' => %r/\A[<]mxl[~][0-9a-f]+/,
96
78
  match = 0
97
79
  match += 1 if mhead['x-mx-bounce']
98
80
  match += 1 if mhead['x-mxl-hash']
99
81
  match += 1 if mhead['x-mxl-notehash']
100
- match += 1 if mhead['subject'] =~ Re0[:subject]
101
- match += 1 if mhead['from'] =~ Re0[:from]
82
+ match += 1 if mhead['from'].start_with?('Mail Delivery System')
83
+ match += 1 if mhead['subject'] =~ %r{(?:
84
+ Mail[ ]delivery[ ]failed(:[ ]returning[ ]message[ ]to[ ]sender)?
85
+ |Warning:[ ]message[ ].+[ ]delayed[ ]+
86
+ |Delivery[ ]Status[ ]Notification
87
+ )
88
+ }x
102
89
  return nil if match.zero?
103
90
 
104
91
  dscontents = [Sisimai::Bite.DELIVERYSTATUS]
@@ -110,10 +97,10 @@ module Sisimai::Bite::Email
110
97
  localhost0 = '' # (String) Local MTA
111
98
  v = nil
112
99
 
113
- hasdivided.each do |e|
100
+ while e = hasdivided.shift do
114
101
  if readcursor.zero?
115
102
  # Beginning of the bounce message or delivery status part
116
- if e =~ Re1[:begin]
103
+ if e == StartingOf[:message][0]
117
104
  readcursor |= Indicators[:deliverystatus]
118
105
  next
119
106
  end
@@ -121,7 +108,7 @@ module Sisimai::Bite::Email
121
108
 
122
109
  if (readcursor & Indicators[:'message-rfc822']).zero?
123
110
  # Beginning of the original message part
124
- if e =~ Re1[:rfc822]
111
+ if e == StartingOf[:rfc822][0]
125
112
  readcursor |= Indicators[:'message-rfc822']
126
113
  next
127
114
  end
@@ -135,7 +122,6 @@ module Sisimai::Bite::Email
135
122
  next
136
123
  end
137
124
  rfc822list << e
138
-
139
125
  else
140
126
  # Before "message/rfc822"
141
127
  next if (readcursor & Indicators[:deliverystatus]).zero?
@@ -168,8 +154,7 @@ module Sisimai::Bite::Email
168
154
  elsif dscontents.size == recipients
169
155
  # Error message
170
156
  next if e.empty?
171
- v['diagnosis'] ||= ''
172
- v['diagnosis'] += e + ' '
157
+ v['diagnosis'] << e + ' '
173
158
  end
174
159
  end
175
160
  end
@@ -199,16 +184,14 @@ module Sisimai::Bite::Email
199
184
  end
200
185
 
201
186
  unless e['rhost']
202
- if mhead['received'].size > 0
203
- # Get localhost and remote host name from Received header.
204
- e['rhost'] = Sisimai::RFC5322.received(mhead['received'][-1]).pop
205
- end
187
+ # Get localhost and remote host name from Received header.
188
+ e['rhost'] = Sisimai::RFC5322.received(mhead['received'][-1]).pop if mhead['received'].size > 0
206
189
  end
207
190
  end
208
191
 
209
192
  unless e['command']
210
193
  # Get the SMTP command name for the session
211
- ReCommand.each do |r|
194
+ ReCommands.each do |r|
212
195
  # Verify each regular expression of SMTP commands
213
196
  if cv = e['diagnosis'].match(r)
214
197
  e['command'] = cv[1].upcase
@@ -221,22 +204,21 @@ module Sisimai::Bite::Email
221
204
  # MAIL | Connected to 192.0.2.135 but sender was rejected.
222
205
  e['reason'] = 'rejected'
223
206
 
224
- elsif e['command'] =~ /\A(?:HELO|EHLO)\z/
207
+ elsif %w[HELO EHLO].index(e['command'])
225
208
  # HELO | Connected to 192.0.2.135 but my name was rejected.
226
209
  e['reason'] = 'blocked'
227
-
228
210
  else
229
211
  # Verify each regular expression of session errors
230
- ReFailure.each_key do |r|
212
+ ReFailures.each_key do |r|
231
213
  # Check each regular expression
232
- next unless e['diagnosis'] =~ ReFailure[r]
214
+ next unless e['diagnosis'] =~ ReFailures[r]
233
215
  e['reason'] = r.to_s
234
216
  break
235
217
  end
236
218
 
237
219
  unless e['reason']
238
220
  # The reason "expired"
239
- e['reason'] = 'expired' if e['diagnosis'] =~ ReDelayed
221
+ e['reason'] = 'expired' if e['diagnosis'] =~ ReDelaying
240
222
  end
241
223
  end
242
224
  end
@@ -6,15 +6,12 @@ module Sisimai::Bite::Email
6
6
  # Imported from p5-Sisimail/lib/Sisimai/Bite/Email/Notes.pm
7
7
  require 'sisimai/bite/email'
8
8
 
9
- Re0 = {
10
- :'subject' => %r/\AUndeliverable message/,
11
- }.freeze
12
- Re1 = {
13
- :begin => %r/\A[-]+[ ]+Failure Reasons[ ]+[-]+\z/,
14
- :rfc822 => %r/^[-]+[ ]+Returned Message[ ]+[-]+$/,
15
- :endof => %r/\A__END_OF_EMAIL_MESSAGE__\z/,
9
+ Indicators = Sisimai::Bite::Email.INDICATORS
10
+ StartingOf = {
11
+ message: ['------- Failure Reasons '],
12
+ rfc822: ['------- Returned Message '],
16
13
  }.freeze
17
- ReFailure = {
14
+ ReFailures = {
18
15
  userunknown: %r{(?:
19
16
  User[ ]not[ ]listed[ ]in[ ]public[ ]Name[ ][&][ ]Address[ ]Book
20
17
  |ディレクトリのリストにありません
@@ -22,12 +19,10 @@ module Sisimai::Bite::Email
22
19
  }x,
23
20
  networkerror: %r/Message has exceeded maximum hop count/,
24
21
  }.freeze
25
- Indicators = Sisimai::Bite::Email.INDICATORS
26
22
 
27
23
  def description; return 'Lotus Notes'; end
28
24
  def smtpagent; return Sisimai::Bite.smtpagent(self); end
29
25
  def headerlist; return []; end
30
- def pattern; return Re0; end
31
26
 
32
27
  # Parse bounce messages from Lotus Notes
33
28
  # @param [Hash] mhead Message headers of a bounce email
@@ -43,7 +38,7 @@ module Sisimai::Bite::Email
43
38
  def scan(mhead, mbody)
44
39
  return nil unless mhead
45
40
  return nil unless mbody
46
- return nil unless mhead['subject'] =~ Re0[:subject]
41
+ return nil unless mhead['subject'].start_with?('Undeliverable message')
47
42
 
48
43
  dscontents = [Sisimai::Bite.DELIVERYSTATUS]
49
44
  hasdivided = mbody.split("\n")
@@ -56,10 +51,10 @@ module Sisimai::Bite::Email
56
51
  encodedmsg = ''
57
52
  v = nil
58
53
 
59
- hasdivided.each do |e|
54
+ while e = hasdivided.shift do
60
55
  if readcursor.zero?
61
56
  # Beginning of the bounce message or delivery status part
62
- if e =~ Re1[:begin]
57
+ if e.start_with?(StartingOf[:message][0])
63
58
  readcursor |= Indicators[:deliverystatus]
64
59
  next
65
60
  end
@@ -67,7 +62,7 @@ module Sisimai::Bite::Email
67
62
 
68
63
  if (readcursor & Indicators[:'message-rfc822']).zero?
69
64
  # Beginning of the original message part
70
- if e =~ Re1[:rfc822]
65
+ if e.start_with?(StartingOf[:rfc822][0])
71
66
  readcursor |= Indicators[:'message-rfc822']
72
67
  next
73
68
  end
@@ -89,7 +84,6 @@ module Sisimai::Bite::Email
89
84
  next
90
85
  end
91
86
  rfc822list << e
92
-
93
87
  else
94
88
  # Before "message/rfc822"
95
89
  next if (readcursor & Indicators[:deliverystatus]).zero?
@@ -110,10 +104,9 @@ module Sisimai::Bite::Email
110
104
  end
111
105
  v['recipient'] ||= e
112
106
  recipients += 1
113
-
114
107
  else
115
- next if e =~ /\A\z/
116
- next if e =~ /\A[-]+/
108
+ next if e.empty?
109
+ next if e.start_with?('-')
117
110
 
118
111
  if e =~ /[^\x20-\x7e]/
119
112
  # Error message is not ISO-8859-1
@@ -130,11 +123,11 @@ module Sisimai::Bite::Email
130
123
  encodedmsg = removedmsg
131
124
  end
132
125
  v['diagnosis'] ||= ''
133
- v['diagnosis'] += encodedmsg
126
+ v['diagnosis'] << encodedmsg
134
127
  else
135
128
  # Error message does not include multi-byte character
136
129
  v['diagnosis'] ||= ''
137
- v['diagnosis'] += e
130
+ v['diagnosis'] << e
138
131
  end
139
132
  end
140
133
  end
@@ -150,19 +143,18 @@ module Sisimai::Bite::Email
150
143
  break
151
144
  end
152
145
  end
153
-
154
146
  return nil if recipients.zero?
147
+
155
148
  require 'sisimai/string'
156
149
  require 'sisimai/smtp/status'
157
-
158
150
  dscontents.map do |e|
159
151
  e['agent'] = self.smtpagent
160
152
  e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'])
161
153
  e['recipient'] = Sisimai::Address.s3s4(e['recipient'])
162
154
 
163
- ReFailure.each_key do |r|
155
+ ReFailures.each_key do |r|
164
156
  # Check each regular expression of Notes error messages
165
- next unless e['diagnosis'] =~ ReFailure[r]
157
+ next unless e['diagnosis'] =~ ReFailures[r]
166
158
  e['reason'] = r.to_s
167
159
  pseudostatus = Sisimai::SMTP::Status.code(r.to_s)
168
160
  e['status'] = pseudostatus if pseudostatus.size > 0
@@ -7,23 +7,20 @@ module Sisimai::Bite::Email
7
7
  # Imported from p5-Sisimail/lib/Sisimai/Bite/Email/Office365.pm
8
8
  require 'sisimai/bite/email'
9
9
 
10
- Re0 = {
11
- :'subject' => %r/Undeliverable:/,
12
- :'received' => %r/.+[.](?:outbound[.]protection|prod)[.]outlook[.]com\b/,
13
- :'message-id' => %r/.+[.](?:outbound[.]protection|prod)[.]outlook[.]com\b/,
10
+ Indicators = Sisimai::Bite::Email.INDICATORS
11
+ StartingOf = {
12
+ rfc822: ['Content-Type: message/rfc822'],
13
+ error: ['Diagnostic information for administrators:'],
14
+ eoerr: ['Original message headers:'],
14
15
  }.freeze
15
- Re1 = {
16
- :begin => %r{\A(?:
16
+ MarkingsOf = {
17
+ message: %r{\A(?:
17
18
  Delivery[ ]has[ ]failed[ ]to[ ]these[ ]recipients[ ]or[ ]groups:
18
19
  |.+[ ]rejected[ ]your[ ]message[ ]to[ ]the[ ]following[ ]e[-]?mail[ ]addresses:
19
20
  )
20
21
  }x,
21
- :error => %r/\ADiagnostic information for administrators:\z/,
22
- :eoerr => %r/\AOriginal message headers:\z/,
23
- :rfc822 => %r|\AContent-Type: message/rfc822\z|,
24
- :endof => %r/\A__END_OF_EMAIL_MESSAGE__\z/,
25
22
  }.freeze
26
- CodeTable = {
23
+ StatusList = {
27
24
  # https://support.office.com/en-us/article/Email-non-delivery-reports-in-Office-365-51daa6b9-2e35-49c4-a0c9-df85bf8533c3
28
25
  %r/\A4[.]4[.]7\z/ => 'expired',
29
26
  %r/\A4[.]7[.]26\z/ => 'securityerror',
@@ -49,7 +46,6 @@ module Sisimai::Bite::Email
49
46
  %r/\A5[.]7[.]6[1-4]\d\z/ => 'blocked',
50
47
  %r/\A5[.]7[.]7[0-4]\d\z/ => 'toomanyconn',
51
48
  }.freeze
52
- Indicators = Sisimai::Bite::Email.INDICATORS
53
49
 
54
50
  def description; return 'Microsoft Office 365: http://office.microsoft.com/'; end
55
51
  def smtpagent; return Sisimai::Bite.smtpagent(self); end
@@ -72,7 +68,6 @@ module Sisimai::Bite::Email
72
68
  'X-MS-Exchange-Transport-CrossTenantHeadersStamped',
73
69
  ]
74
70
  end
75
- def pattern; return Re0; end
76
71
 
77
72
  # Parse bounce messages from Microsoft Office 365
78
73
  # @param [Hash] mhead Message headers of a bounce email
@@ -89,8 +84,9 @@ module Sisimai::Bite::Email
89
84
  return nil unless mhead
90
85
  return nil unless mbody
91
86
 
87
+ tryto = %r/.+[.](?:outbound[.]protection|prod)[.]outlook[.]com\b/
92
88
  match = 0
93
- match += 1 if mhead['subject'] =~ Re0[:subject]
89
+ match += 1 if mhead['subject'].include?('Undeliverable:')
94
90
  match += 1 if mhead['x-ms-exchange-message-is-ndr']
95
91
  match += 1 if mhead['x-microsoft-antispam-prvs']
96
92
  match += 1 if mhead['x-exchange-antispam-report-test']
@@ -98,10 +94,10 @@ module Sisimai::Bite::Email
98
94
  match += 1 if mhead['x-ms-exchange-crosstenant-originalarrivaltime']
99
95
  match += 1 if mhead['x-ms-exchange-crosstenant-fromentityheader']
100
96
  match += 1 if mhead['x-ms-exchange-transport-crosstenantheadersstamped']
101
- match += 1 if mhead['received'].find { |a| a =~ Re0[:received] }
97
+ match += 1 if mhead['received'].find { |a| a =~ tryto }
102
98
  if mhead['message-id']
103
99
  # Message-ID: <00000000-0000-0000-0000-000000000000@*.*.prod.outlook.com>
104
- match += 1 if mhead['message-id'] =~ Re0[:'message-id']
100
+ match += 1 if mhead['message-id'] =~ tryto
105
101
  end
106
102
  return nil if match < 2
107
103
 
@@ -116,10 +112,10 @@ module Sisimai::Bite::Email
116
112
  htmlbegins = false # (Boolean) Flag for HTML part
117
113
  v = nil
118
114
 
119
- hasdivided.each do |e|
115
+ while e = hasdivided.shift do
120
116
  if readcursor.zero?
121
117
  # Beginning of the bounce message or delivery status part
122
- if e =~ Re1[:begin]
118
+ if e =~ MarkingsOf[:message]
123
119
  readcursor |= Indicators[:deliverystatus]
124
120
  next
125
121
  end
@@ -127,7 +123,7 @@ module Sisimai::Bite::Email
127
123
 
128
124
  if (readcursor & Indicators[:'message-rfc822']).zero?
129
125
  # Beginning of the original message part
130
- if e =~ Re1[:rfc822]
126
+ if e == StartingOf[:rfc822][0]
131
127
  readcursor |= Indicators[:'message-rfc822']
132
128
  next
133
129
  end
@@ -141,7 +137,6 @@ module Sisimai::Bite::Email
141
137
  next
142
138
  end
143
139
  rfc822list << e
144
-
145
140
  else
146
141
  # Before "message/rfc822"
147
142
  next if (readcursor & Indicators[:deliverystatus]).zero?
@@ -166,43 +161,40 @@ module Sisimai::Bite::Email
166
161
  elsif cv = e.match(/\AGenerating server: (.+)\z/)
167
162
  # Generating server: FFFFFFFFFFFF.e0.prod.outlook.com
168
163
  connheader['lhost'] = cv[1].downcase
169
-
170
164
  else
171
165
  if endoferror
172
166
  # After "Original message headers:"
173
167
  if htmlbegins
174
168
  # <html> .. </html>
175
- htmlbegins = false if e =~ %r|\A[<]/html[>]|
169
+ htmlbegins = false if e.start_with?('</html>')
176
170
  next
177
171
  end
178
172
 
179
- if cv = e.match(/\A[Aa]ction:[ ]*(.+)\z/)
173
+ if cv = e.match(/\AAction:[ ]*(.+)\z/)
180
174
  # Action: failed
181
175
  v['action'] = cv[1].downcase
182
176
 
183
- elsif cv = e.match(/\A[Ss]tatus:[ ]*(\d[.]\d+[.]\d+)/)
177
+ elsif cv = e.match(/\AStatus:[ ]*(\d[.]\d+[.]\d+)/)
184
178
  # Status:5.2.0
185
179
  v['status'] = cv[1]
186
180
 
187
- elsif cv = e.match(/\A[Rr]eporting-MTA:[ ]*(?:DNS|dns);[ ]*(.+)\z/)
181
+ elsif cv = e.match(/\AReporting-MTA:[ ]*(?:DNS|dns);[ ]*(.+)\z/)
188
182
  # Reporting-MTA: dns;BLU004-OMC3S13.hotmail.example.com
189
183
  connheader['lhost'] = cv[1].downcase
190
184
 
191
- elsif cv = e.match(/\A[Rr]eceived-[Ff]rom-MTA:[ ]*(?:DNS|dns);[ ]*(.+)\z/)
185
+ elsif cv = e.match(/\AReceived-From-MTA:[ ]*(?:DNS|dns);[ ]*(.+)\z/)
192
186
  # Reporting-MTA: dns;BLU004-OMC3S13.hotmail.example.com
193
187
  connheader['rhost'] = cv[1].downcase
194
188
 
195
- elsif cv = e.match(/\A[Aa]rrival-[Dd]ate:[ ]*(.+)\z/)
189
+ elsif cv = e.match(/\AArrival-Date:[ ]*(.+)\z/)
196
190
  # Arrival-Date: Wed, 29 Apr 2009 16:03:18 +0900
197
191
  next if connheader['date']
198
192
  connheader['date'] = cv[1]
199
-
200
193
  else
201
- htmlbegins = true if e =~ /\A[<]html[>]/
194
+ htmlbegins = true if e.start_with?('<html>')
202
195
  end
203
-
204
196
  else
205
- if e =~ Re1[:error]
197
+ if e == StartingOf[:error][0]
206
198
  # Diagnostic information for administrators:
207
199
  v['diagnosis'] = e
208
200
  else
@@ -210,23 +202,22 @@ module Sisimai::Bite::Email
210
202
  # Remote Server returned '550 5.1.10 RESOLVER.ADR.RecipientNotFound; Recipien=
211
203
  # t not found by SMTP address lookup'
212
204
  next unless v['diagnosis']
213
- if e =~ Re1[:eoerr]
205
+ if e == StartingOf[:eoerr][0]
214
206
  # Original message headers:
215
207
  endoferror = true
216
208
  next
217
209
  end
218
- v['diagnosis'] += ' ' + e
210
+ v['diagnosis'] << ' ' << e
219
211
  end
220
212
  end
221
213
  end
222
214
 
223
215
  end
224
216
  end
225
-
226
217
  return nil if recipients.zero?
218
+
227
219
  require 'sisimai/string'
228
220
  require 'sisimai/smtp/status'
229
-
230
221
  dscontents.map do |e|
231
222
  # Set default values if each value is empty.
232
223
  connheader.each_key { |a| e[a] ||= connheader[a] || '' }
@@ -235,17 +226,17 @@ module Sisimai::Bite::Email
235
226
  e['status'] ||= ''
236
227
  e['diagnosis'] = Sisimai::String.sweep(e['diagnosis']) || ''
237
228
 
238
- if e['status'].empty? || e['status'] =~ /\A\d[.]0[.]0\z/
229
+ if e['status'].empty? || e['status'].end_with?('.0.0')
239
230
  # There is no value of Status header or the value is 5.0.0, 4.0.0
240
231
  pseudostatus = Sisimai::SMTP::Status.find(e['diagnosis'])
241
232
  e['status'] = pseudostatus if pseudostatus.size > 0
242
233
  end
243
234
  next unless e['status']
244
235
 
245
- CodeTable.each_key do |f|
236
+ StatusList.each_key do |f|
246
237
  # Try to match with each key as a regular expression
247
238
  next unless e['status'] =~ f
248
- e['reason'] = CodeTable[f]
239
+ e['reason'] = StatusList[f]
249
240
  break
250
241
  end
251
242
  end