sisimai 4.25.17 → 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (178) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +3 -3
  3. data/ANALYTICAL-PRECISION +2 -2
  4. data/Benchmarks.mk +3 -3
  5. data/CONTRIBUTING +1 -1
  6. data/ChangeLog.md +406 -407
  7. data/Developers.mk +5 -6
  8. data/Gemfile +1 -1
  9. data/Makefile +12 -12
  10. data/README-JA.md +142 -94
  11. data/README.md +282 -150
  12. data/Rakefile +9 -3
  13. data/Repository.mk +2 -3
  14. data/lib/sisimai/address.rb +118 -74
  15. data/lib/sisimai/arf.rb +84 -82
  16. data/lib/sisimai/datetime.rb +5 -52
  17. data/lib/sisimai/{data → fact}/json.rb +7 -9
  18. data/lib/sisimai/fact/yaml.rb +31 -0
  19. data/lib/sisimai/fact.rb +468 -0
  20. data/lib/sisimai/lhost/activehunter.rb +12 -14
  21. data/lib/sisimai/lhost/amavis.rb +11 -14
  22. data/lib/sisimai/lhost/amazonses.rb +37 -41
  23. data/lib/sisimai/lhost/amazonworkmail.rb +15 -18
  24. data/lib/sisimai/lhost/aol.rb +12 -14
  25. data/lib/sisimai/lhost/apachejames.rb +19 -21
  26. data/lib/sisimai/lhost/barracuda.rb +10 -12
  27. data/lib/sisimai/lhost/bigfoot.rb +21 -21
  28. data/lib/sisimai/lhost/biglobe.rb +15 -16
  29. data/lib/sisimai/lhost/courier.rb +20 -20
  30. data/lib/sisimai/lhost/domino.rb +23 -19
  31. data/lib/sisimai/lhost/einsundeins.rb +20 -16
  32. data/lib/sisimai/lhost/exchange2003.rb +30 -29
  33. data/lib/sisimai/lhost/exchange2007.rb +70 -58
  34. data/lib/sisimai/lhost/exim.rb +175 -161
  35. data/lib/sisimai/lhost/ezweb.rb +31 -56
  36. data/lib/sisimai/lhost/facebook.rb +21 -33
  37. data/lib/sisimai/lhost/fml.rb +43 -48
  38. data/lib/sisimai/lhost/gmail.rb +29 -29
  39. data/lib/sisimai/lhost/gmx.rb +18 -17
  40. data/lib/sisimai/lhost/googlegroups.rb +9 -10
  41. data/lib/sisimai/lhost/gsuite.rb +21 -27
  42. data/lib/sisimai/lhost/imailserver.rb +25 -39
  43. data/lib/sisimai/lhost/interscanmss.rb +28 -31
  44. data/lib/sisimai/lhost/kddi.rb +22 -28
  45. data/lib/sisimai/lhost/mailfoundry.rb +11 -12
  46. data/lib/sisimai/lhost/mailmarshalsmtp.rb +25 -29
  47. data/lib/sisimai/lhost/mailru.rb +33 -27
  48. data/lib/sisimai/lhost/mcafee.rb +21 -31
  49. data/lib/sisimai/lhost/messagelabs.rb +17 -20
  50. data/lib/sisimai/lhost/messagingserver.rb +40 -37
  51. data/lib/sisimai/lhost/mfilter.rb +15 -16
  52. data/lib/sisimai/lhost/mxlogic.rb +24 -23
  53. data/lib/sisimai/lhost/notes.rb +17 -17
  54. data/lib/sisimai/lhost/office365.rb +63 -27
  55. data/lib/sisimai/lhost/opensmtpd.rb +12 -13
  56. data/lib/sisimai/lhost/outlook.rb +12 -15
  57. data/lib/sisimai/lhost/postfix.rb +179 -129
  58. data/lib/sisimai/lhost/powermta.rb +12 -14
  59. data/lib/sisimai/lhost/qmail.rb +44 -47
  60. data/lib/sisimai/lhost/receivingses.rb +15 -20
  61. data/lib/sisimai/lhost/sendgrid.rb +34 -32
  62. data/lib/sisimai/lhost/sendmail.rb +66 -53
  63. data/lib/sisimai/lhost/surfcontrol.rb +19 -19
  64. data/lib/sisimai/lhost/v5sendmail.rb +45 -39
  65. data/lib/sisimai/lhost/verizon.rb +35 -39
  66. data/lib/sisimai/lhost/x1.rb +18 -17
  67. data/lib/sisimai/lhost/x2.rb +17 -14
  68. data/lib/sisimai/lhost/x3.rb +19 -19
  69. data/lib/sisimai/lhost/x4.rb +72 -57
  70. data/lib/sisimai/lhost/x5.rb +17 -19
  71. data/lib/sisimai/lhost/x6.rb +41 -17
  72. data/lib/sisimai/lhost/yahoo.rb +17 -16
  73. data/lib/sisimai/lhost/yandex.rb +16 -20
  74. data/lib/sisimai/lhost/zoho.rb +16 -15
  75. data/lib/sisimai/lhost.rb +8 -10
  76. data/lib/sisimai/mail/maildir.rb +1 -3
  77. data/lib/sisimai/mail/mbox.rb +3 -4
  78. data/lib/sisimai/mail/memory.rb +0 -1
  79. data/lib/sisimai/mail/stdin.rb +1 -3
  80. data/lib/sisimai/mail.rb +3 -7
  81. data/lib/sisimai/mda.rb +28 -42
  82. data/lib/sisimai/message.rb +435 -325
  83. data/lib/sisimai/order.rb +5 -5
  84. data/lib/sisimai/reason/authfailure.rb +64 -0
  85. data/lib/sisimai/reason/badreputation.rb +53 -0
  86. data/lib/sisimai/reason/blocked.rb +94 -160
  87. data/lib/sisimai/reason/contenterror.rb +8 -9
  88. data/lib/sisimai/reason/delivered.rb +4 -6
  89. data/lib/sisimai/reason/exceedlimit.rb +10 -12
  90. data/lib/sisimai/reason/expired.rb +6 -8
  91. data/lib/sisimai/reason/feedback.rb +2 -3
  92. data/lib/sisimai/reason/filtered.rb +17 -19
  93. data/lib/sisimai/reason/hasmoved.rb +9 -10
  94. data/lib/sisimai/reason/hostunknown.rb +15 -15
  95. data/lib/sisimai/reason/mailboxfull.rb +10 -12
  96. data/lib/sisimai/reason/mailererror.rb +18 -20
  97. data/lib/sisimai/reason/mesgtoobig.rb +9 -11
  98. data/lib/sisimai/reason/networkerror.rb +5 -8
  99. data/lib/sisimai/reason/norelaying.rb +8 -11
  100. data/lib/sisimai/reason/notaccept.rb +13 -14
  101. data/lib/sisimai/reason/notcompliantrfc.rb +43 -0
  102. data/lib/sisimai/reason/onhold.rb +6 -9
  103. data/lib/sisimai/reason/policyviolation.rb +14 -12
  104. data/lib/sisimai/reason/rejected.rb +26 -24
  105. data/lib/sisimai/reason/requireptr.rb +69 -0
  106. data/lib/sisimai/reason/securityerror.rb +33 -36
  107. data/lib/sisimai/reason/spamdetected.rb +114 -147
  108. data/lib/sisimai/reason/speeding.rb +49 -0
  109. data/lib/sisimai/reason/suspend.rb +11 -11
  110. data/lib/sisimai/reason/syntaxerror.rb +11 -10
  111. data/lib/sisimai/reason/systemerror.rb +7 -9
  112. data/lib/sisimai/reason/systemfull.rb +7 -8
  113. data/lib/sisimai/reason/toomanyconn.rb +9 -11
  114. data/lib/sisimai/reason/undefined.rb +2 -3
  115. data/lib/sisimai/reason/userunknown.rb +129 -146
  116. data/lib/sisimai/reason/vacation.rb +3 -4
  117. data/lib/sisimai/reason/virusdetected.rb +10 -11
  118. data/lib/sisimai/reason.rb +59 -64
  119. data/lib/sisimai/rfc1894.rb +55 -28
  120. data/lib/sisimai/rfc2045.rb +373 -0
  121. data/lib/sisimai/rfc3464.rb +250 -308
  122. data/lib/sisimai/rfc3834.rb +42 -45
  123. data/lib/sisimai/rfc5322.rb +75 -100
  124. data/lib/sisimai/rfc5965.rb +31 -0
  125. data/lib/sisimai/rhost/cox.rb +5 -6
  126. data/lib/sisimai/rhost/franceptt.rb +6 -8
  127. data/lib/sisimai/rhost/godaddy.rb +12 -12
  128. data/lib/sisimai/rhost/{googleapps.rb → google.rb} +80 -72
  129. data/lib/sisimai/rhost/iua.rb +9 -10
  130. data/lib/sisimai/rhost/kddi.rb +6 -8
  131. data/lib/sisimai/rhost/{exchangeonline.rb → microsoft.rb} +115 -114
  132. data/lib/sisimai/rhost/mimecast.rb +42 -40
  133. data/lib/sisimai/rhost/nttdocomo.rb +13 -18
  134. data/lib/sisimai/rhost/spectrum.rb +10 -12
  135. data/lib/sisimai/rhost/{tencentqq.rb → tencent.rb} +7 -8
  136. data/lib/sisimai/rhost.rb +23 -31
  137. data/lib/sisimai/smtp/command.rb +59 -0
  138. data/lib/sisimai/smtp/error.rb +4 -7
  139. data/lib/sisimai/smtp/reply.rb +161 -74
  140. data/lib/sisimai/smtp/status.rb +504 -393
  141. data/lib/sisimai/smtp/transcript.rb +124 -0
  142. data/lib/sisimai/smtp.rb +0 -1
  143. data/lib/sisimai/string.rb +74 -5
  144. data/lib/sisimai/time.rb +1 -2
  145. data/lib/sisimai/version.rb +1 -1
  146. data/lib/sisimai.rb +35 -21
  147. data/set-of-emails/maildir/bsd/lhost-domino-02.eml +6 -3
  148. data/set-of-emails/maildir/bsd/lhost-googlegroups-15.eml +174 -0
  149. data/set-of-emails/maildir/bsd/lhost-gsuite-15.eml +229 -0
  150. data/set-of-emails/maildir/bsd/lhost-postfix-75.eml +51 -0
  151. data/set-of-emails/maildir/bsd/lhost-postfix-76.eml +101 -0
  152. data/set-of-emails/maildir/bsd/lhost-postfix-77.eml +74 -0
  153. data/set-of-emails/maildir/bsd/lhost-postfix-78.eml +91 -0
  154. data/set-of-emails/maildir/bsd/lhost-receivingses-08.eml +88 -0
  155. data/set-of-emails/maildir/bsd/rfc3464-43.eml +88 -0
  156. data/set-of-emails/maildir/bsd/rhost-google-03.eml +101 -0
  157. data/set-of-emails/maildir/bsd/rhost-google-04.eml +102 -0
  158. data/set-of-emails/maildir/bsd/rhost-google-05.eml +82 -0
  159. data/set-of-emails/maildir/bsd/rhost-google-06.eml +102 -0
  160. data/set-of-emails/maildir/bsd/rhost-google-07.eml +69 -0
  161. data/set-of-emails/maildir/bsd/rhost-google-08.eml +99 -0
  162. data/sisimai-java.gemspec +1 -1
  163. data/sisimai.gemspec +1 -1
  164. metadata +41 -21
  165. data/.rspec +0 -2
  166. data/lib/sisimai/data/yaml.rb +0 -33
  167. data/lib/sisimai/data.rb +0 -411
  168. data/lib/sisimai/mime.rb +0 -456
  169. data/set-of-emails/maildir/mac/reported-from-nick4tech-san-01.eml +0 -6
  170. /data/set-of-emails/maildir/bsd/{rfc3464-41.eml → rfc3834-05.eml} +0 -0
  171. /data/set-of-emails/maildir/bsd/{rhost-googleapps-01.eml → rhost-google-01.eml} +0 -0
  172. /data/set-of-emails/maildir/bsd/{rhost-googleapps-02.eml → rhost-google-02.eml} +0 -0
  173. /data/set-of-emails/maildir/bsd/{rhost-exchangeonline-01.eml → rhost-microsoft-01.eml} +0 -0
  174. /data/set-of-emails/maildir/bsd/{rhost-exchangeonline-02.eml → rhost-microsoft-02.eml} +0 -0
  175. /data/set-of-emails/maildir/bsd/{rhost-exchangeonline-03.eml → rhost-microsoft-03.eml} +0 -0
  176. /data/set-of-emails/maildir/bsd/{rhost-tencentqq-01.eml → rhost-tencent-01.eml} +0 -0
  177. /data/set-of-emails/maildir/bsd/{rhost-tencentqq-02.eml → rhost-tencent-02.eml} +0 -0
  178. /data/set-of-emails/maildir/bsd/{rhost-tencentqq-03.eml → rhost-tencent-03.eml} +0 -0
@@ -1,14 +1,12 @@
1
1
  module Sisimai::Lhost
2
- # Sisimai::Lhost::Exchange2003 parses a bounce email which created by
3
- # Microsoft Exchange Server 2003.
2
+ # Sisimai::Lhost::Exchange2003 parses a bounce email which created by Microsoft Exchange Server 2003.
4
3
  # Methods in the module are called from only Sisimai::Message.
5
4
  module Exchange2003
6
5
  class << self
7
- # Imported from p5-Sisimail/lib/Sisimai/Lhost/Exchange2003.pm
8
6
  require 'sisimai/lhost'
9
7
 
10
8
  Indicators = Sisimai::Lhost.INDICATORS
11
- ReBackbone = %r|^Content-Type:[ ]message/rfc822|.freeze
9
+ Boundaries = ['Content-Type: message/rfc822'].freeze
12
10
  StartingOf = {
13
11
  message: ['Your message'],
14
12
  error: ['did not reach the following recipient(s):'],
@@ -46,7 +44,7 @@ module Sisimai::Lhost
46
44
  # @param [String] mbody Message body of a bounce email
47
45
  # @return [Hash] Bounce data list and message/rfc822 part
48
46
  # @return [Nil] it failed to parse or the arguments are missing
49
- def make(mhead, mbody)
47
+ def inquire(mhead, mbody)
50
48
  match = 0
51
49
  tryto = []
52
50
 
@@ -85,8 +83,8 @@ module Sisimai::Lhost
85
83
  return nil unless match > 0
86
84
 
87
85
  dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
88
- emailsteak = Sisimai::RFC5322.fillet(mbody, ReBackbone)
89
- bodyslices = emailsteak[0].split("\n")
86
+ emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
87
+ bodyslices = emailparts[0].split("\n")
90
88
  readcursor = 0 # (Integer) Points the current cursor position
91
89
  recipients = 0 # (Integer) The number of 'Final-Recipient' header
92
90
  statuspart = false # (Boolean) Flag, true = have got delivery status part.
@@ -99,8 +97,8 @@ module Sisimai::Lhost
99
97
  v = nil
100
98
 
101
99
  while e = bodyslices.shift do
102
- # Read error messages and delivery status lines from the head of the email
103
- # to the previous line of the beginning of the original message.
100
+ # Read error messages and delivery status lines from the head of the email to the previous
101
+ # line of the beginning of the original message.
104
102
  if readcursor == 0
105
103
  # Beginning of the bounce message or delivery status part
106
104
  readcursor |= Indicators[:deliverystatus] if e.start_with?(StartingOf[:message][0])
@@ -124,8 +122,7 @@ module Sisimai::Lhost
124
122
  # MSEXCH:IMS:KIJITORA CAT:EXAMPLE:EXCHANGE 0 (000C05A6) Unknown Recipient
125
123
  v = dscontents[-1]
126
124
 
127
- if cv = e.match(/\A[ \t]*([^ ]+[@][^ ]+) on[ \t]*.*\z/) ||
128
- e.match(/\A[ \t]*.+(?:SMTP|smtp)=([^ ]+[@][^ ]+) on[ \t]*.*\z/)
125
+ if Sisimai::String.aligned(e, ['@', ' on '])
129
126
  # kijitora@example.co.jp on Thu, 29 Apr 2007 16:51:51 -0500
130
127
  # kijitora@example.com on 4/29/99 9:19:59 AM
131
128
  if v['recipient']
@@ -133,14 +130,16 @@ module Sisimai::Lhost
133
130
  dscontents << Sisimai::Lhost.DELIVERYSTATUS
134
131
  v = dscontents[-1]
135
132
  end
136
- v['recipient'] = cv[1]
133
+ p1 = e.downcase.index('smtp='); p1 = p1.nil? ? 0 : p1 + 5
134
+ p2 = e.index(' on ') + 1
135
+ v['recipient'] = Sisimai::Address.s3s4(e[p1, p2])
137
136
  v['msexch'] = false
138
137
  recipients += 1
139
138
 
140
- elsif cv = e.match(/\A[ \t]+(MSEXCH:.+)\z/)
139
+ elsif e.start_with?(' ') && e.include?('MSEXCH:')
141
140
  # MSEXCH:IMS:KIJITORA CAT:EXAMPLE:EXCHANGE 0 (000C05A6) Unknown Recipient
142
141
  v['diagnosis'] ||= ''
143
- v['diagnosis'] << cv[1]
142
+ v['diagnosis'] << e[e.index('MSEXCH:'), e.size]
144
143
  else
145
144
  next if v['msexch']
146
145
  if v['diagnosis'].to_s.start_with?('MSEXCH:')
@@ -161,24 +160,23 @@ module Sisimai::Lhost
161
160
  # Subject: ...
162
161
  # Sent: Thu, 29 Apr 2010 18:14:35 +0000
163
162
  #
164
- if cv = e.match(/\A[ \t]+To:[ \t]+(.+)\z/)
163
+ if e.start_with?(' To: ') || e.start_with?(' To: ')
165
164
  # To: shironeko@example.jp
166
165
  next unless connheader['to'].empty?
167
- connheader['to'] = cv[1]
166
+ connheader['to'] = e[e.rindex(' ') + 1, e.size]
168
167
  connvalues += 1
169
168
 
170
- elsif cv = e.match(/\A[ \t]+Subject:[ \t]+(.+)\z/)
169
+ elsif e.start_with?(' Subject: ') || e.start_with?(' Subject: ')
171
170
  # Subject: ...
172
171
  next unless connheader['subject'].empty?
173
- connheader['subject'] = cv[1]
172
+ connheader['subject'] = e[e.rindex(' ') + 1, e.size]
174
173
  connvalues += 1
175
174
 
176
- elsif cv = e.match(%r|\A[ \t]+Sent:[ \t]+([A-Z][a-z]{2},.+[-+]\d{4})\z|) ||
177
- e.match(%r|\A[ \t]+Sent:[ \t]+(\d+[/]\d+[/]\d+[ \t]+\d+:\d+:\d+[ \t].+)|)
175
+ elsif e.start_with?(' Sent: ') || e.start_with?(' Sent: ')
178
176
  # Sent: Thu, 29 Apr 2010 18:14:35 +0000
179
177
  # Sent: 4/29/99 9:19:59 AM
180
178
  next unless connheader['date'].empty?
181
- connheader['date'] = cv[1]
179
+ connheader['date'] = e[e.index(':') + 2, e.size]
182
180
  connvalues += 1
183
181
  end
184
182
  end
@@ -187,10 +185,13 @@ module Sisimai::Lhost
187
185
 
188
186
  dscontents.each do |e|
189
187
  e.delete('msexch')
190
- if cv = e['diagnosis'].match(/\AMSEXCH:.+[ \t]*[(]([0-9A-F]{8})[)][ \t]*(.*)\z/)
188
+ e['diagnosis'] ||= ''
189
+ if e['diagnosis'].start_with?('MSEXCH:')
191
190
  # MSEXCH:IMS:KIJITORA CAT:EXAMPLE:EXCHANGE 0 (000C05A6) Unknown Recipient
192
- capturedcode = cv[1]
193
- errormessage = cv[2]
191
+ p1 = e['diagnosis'].index('(') || -1
192
+ p2 = e['diagnosis'].index(')') || -1
193
+ capturedcode = e['diagnosis'][p1 + 1, 8]
194
+ errormessage = e['diagnosis'][p2 + 1, e['diagnosis'].size]
194
195
 
195
196
  ErrorCodes.each_key do |r|
196
197
  # Find captured code from the error code table
@@ -214,14 +215,14 @@ module Sisimai::Lhost
214
215
  end
215
216
  end
216
217
 
217
- if emailsteak[1].empty?
218
+ if emailparts[1].empty?
218
219
  # When original message does not included in the bounce message
219
- emailsteak[1] << ('From: ' << connheader['to'] << "\n")
220
- emailsteak[1] << ('Date: ' << connheader['date'] << "\n")
221
- emailsteak[1] << ('Subject: ' << connheader['subject'] << "\n")
220
+ emailparts[1] << ('From: ' << connheader['to'] << "\n")
221
+ emailparts[1] << ('Date: ' << connheader['date'] << "\n")
222
+ emailparts[1] << ('Subject: ' << connheader['subject'] << "\n")
222
223
  end
223
224
 
224
- return { 'ds' => dscontents, 'rfc822' => emailsteak[1] }
225
+ return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
225
226
  end
226
227
  def description; return 'Microsoft Exchange Server 2003'; end
227
228
  end
@@ -1,34 +1,28 @@
1
1
  module Sisimai::Lhost
2
- # Sisimai::Lhost::Exchange2007 parses a bounce email which created by
3
- # Microsoft Exchange Server 2007.
2
+ # Sisimai::Lhost::Exchange2007 parses a bounce email which created by Microsoft Exchange Server 2007.
4
3
  # Methods in the module are called from only Sisimai::Message.
5
4
  module Exchange2007
6
5
  class << self
7
- # Imported from p5-Sisimail/lib/Sisimai/Lhost/Exchange2007.pm
8
6
  require 'sisimai/lhost'
9
7
 
10
8
  Indicators = Sisimai::Lhost.INDICATORS
11
- ReBackbone = %r{^(?:
12
- Original[ ]message[ ]headers: # en-US
13
- |En-t.tes[ ]de[ ]message[ ]d'origine[ ]: # fr-FR/En-têtes de message d'origine
14
- |Intestazioni[ ]originali[ ]del[ ]messaggio: # it-CH
15
- )
16
- }x.freeze
9
+ Boundaries = [
10
+ 'Original message headers:', # en-US
11
+ "tes de message d'origine :", # fr-FR/En-têtes de message d'origine
12
+ 'Intestazioni originali del messaggio:', # it-CH
13
+ ].freeze
17
14
  MarkingsOf = {
18
- message: %r{\A(?:
19
- Diagnostic[ ]information[ ]for[ ]administrators: # en-US
20
- |Informations[ ]de[ ]diagnostic[ ]pour[ ]les[ ]administrateurs # fr-FR
21
- |Informazioni[ ]di[ ]diagnostica[ ]per[ ]gli[ ]amministratori # it-CH
22
- )
23
- }x,
24
- error: %r/ ((?:RESOLVER|QUEUE)[.][A-Za-z]+(?:[.]\w+)?);/,
25
- rhost: %r{\A(?:
26
- Generating[ ]server # en-US
27
- |Serveur[ ]de[ ]g[^ ]+ration[ ] # fr-FR/Serveur de génération
28
- |Server[ ]di[ ]generazione # it-CH
29
- ):[ ]?(.*)
30
- }x,
31
- subject: %r/\A(?:Undeliverable|Non_remis_|Non[ ]recapitabile):/,
15
+ message: [
16
+ 'Diagnostic information for administrators:', # en-US
17
+ 'Informations de diagnostic pour les administrateurs', # fr-FR
18
+ 'Informazioni di diagnostica per gli amministratori', # it-CH
19
+ ],
20
+ error: [' RESOLVER.', ' QUEUE.'],
21
+ rhost: [
22
+ 'Generating server', # en-US
23
+ 'Serveur de g', # fr-FR/Serveur de g�Hn�Hration
24
+ 'Server di generazione', # it-CH
25
+ ]
32
26
  }.freeze
33
27
  NDRSubject = {
34
28
  'SMTPSEND.DNS.NonExistentDomain' => 'hostunknown', # 554 5.4.4 SMTPSEND.DNS.NonExistentDomain
@@ -50,19 +44,26 @@ module Sisimai::Lhost
50
44
  # @param [String] mbody Message body of a bounce email
51
45
  # @return [Hash] Bounce data list and message/rfc822 part
52
46
  # @return [Nil] it failed to parse or the arguments are missing
53
- def make(mhead, mbody)
47
+ def inquire(mhead, mbody)
54
48
  # Content-Language: en-US, fr-FR
55
- return nil unless mhead['subject'] =~ MarkingsOf[:subject]
49
+ match = nil
50
+ match ||= 1 if mhead['subject'].start_with?('Undeliverable')
51
+ match ||= 1 if mhead['subject'].start_with?('Non_remis_')
52
+ match ||= 1 if mhead['subject'].start_with?('Non recapitabile')
53
+ return nil unless match
56
54
  return nil unless mhead['content-language']
57
- return nil unless mhead['content-language'] =~ /\A[a-z]{2}(?:[-][A-Z]{2})?\z/
55
+
56
+ match += 1 if mhead['content-language'].size == 2 # JP
57
+ match += 1 if mhead['content-language'].size == 5 # ja-JP
58
+ return nil unless match > 1
58
59
 
59
60
  # These headers exist only a bounce mail from Office365
60
61
  return nil if mhead['x-ms-exchange-crosstenant-originalarrivaltime']
61
62
  return nil if mhead['x-ms-exchange-crosstenant-fromentityheader']
62
63
 
63
64
  dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
64
- emailsteak = Sisimai::RFC5322.fillet(mbody, ReBackbone)
65
- bodyslices = emailsteak[0].split("\n")
65
+ emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
66
+ bodyslices = emailparts[0].split("\n")
66
67
  readcursor = 0 # (Integer) Points the current cursor position
67
68
  recipients = 0 # (Integer) The number of 'Final-Recipient' header
68
69
  connvalues = 0 # (Integer) Flag, 1 if all the value of connheader have been set
@@ -72,11 +73,11 @@ module Sisimai::Lhost
72
73
  v = nil
73
74
 
74
75
  while e = bodyslices.shift do
75
- # Read error messages and delivery status lines from the head of the email
76
- # to the previous line of the beginning of the original message.
76
+ # Read error messages and delivery status lines from the head of the email to the previous
77
+ # line of the beginning of the original message.
77
78
  if readcursor == 0
78
79
  # Beginning of the bounce message or delivery status part
79
- readcursor |= Indicators[:deliverystatus] if e =~ MarkingsOf[:message]
80
+ readcursor |= Indicators[:deliverystatus] if MarkingsOf[:message].any? { |a| e.start_with?(a) }
80
81
  next
81
82
  end
82
83
  next if (readcursor & Indicators[:deliverystatus]) == 0
@@ -92,59 +93,70 @@ module Sisimai::Lhost
92
93
  # Original message headers:
93
94
  v = dscontents[-1]
94
95
 
95
- if cv = e.match(/\A([^ @]+[@][^ @]+)\z/)
96
+ if e.include?('@') && e.include?(' ') == false
96
97
  # kijitora@example.jp
97
98
  if v['recipient']
98
99
  # There are multiple recipient addresses in the message body.
99
100
  dscontents << Sisimai::Lhost.DELIVERYSTATUS
100
101
  v = dscontents[-1]
101
102
  end
102
- v['recipient'] = cv[1]
103
+ v['recipient'] = Sisimai::Address.s3s4(e)
103
104
  v['diagnosis'] = ''
104
105
  recipients += 1
105
106
 
106
- elsif cv = e.match(/([45]\d{2})[ ]([45][.]\d[.]\d+)[ ].+\z/)
107
- # #550 5.1.1 RESOLVER.ADR.RecipNotFound; not found ##
108
- # #550 5.2.3 RESOLVER.RST.RecipSizeLimit; message too large for this recipient ##
109
- # Remote Server returned '550 5.1.1 RESOLVER.ADR.RecipNotFound; not found'
110
- # 3/09/2016 8:05:56 PM - Remote Server at mydomain.com (10.1.1.3) returned '550 4.4.7 QUEUE.Expired; message expired'
111
- v['replycode'] = cv[1]
112
- v['status'] = cv[2]
113
- v['diagnosis'] = e
114
107
  else
115
108
  # Continued line of error messages
116
- next if v['diagnosis'].to_s.empty?
117
- next unless v['diagnosis'].end_with?('=')
118
- v['diagnosis'] = v['diagnosis'].chomp('=')
119
- v['diagnosis'] << e
109
+ cr = Sisimai::SMTP::Reply.find(e)
110
+ cs = Sisimai::SMTP::Status.find(e)
111
+ if cr || cs
112
+ # #550 5.1.1 RESOLVER.ADR.RecipNotFound; not found ##
113
+ # #550 5.2.3 RESOLVER.RST.RecipSizeLimit; message too large for this recipient ##
114
+ # Remote Server returned '550 5.1.1 RESOLVER.ADR.RecipNotFound; not found'
115
+ # 3/09/2016 8:05:56 PM - Remote Server at mydomain.com (10.1.1.3) returned '550 4.4.7 QUEUE.Expired; message expired'
116
+ v['replycode'] = cr || ''
117
+ v['status'] = cs || ''
118
+ v['diagnosis'] = e
119
+ else
120
+ # Continued line of error messages
121
+ next if v['diagnosis'].to_s.empty?
122
+ next unless v['diagnosis'].end_with?('=')
123
+ v['diagnosis'] = v['diagnosis'].chomp('=')
124
+ v['diagnosis'] << e
125
+ end
120
126
  end
121
127
  else
122
128
  # Diagnostic information for administrators:
123
129
  #
124
130
  # Generating server: mta22.neko.example.org
125
- next unless cv = e.match(MarkingsOf[:rhost])
131
+ next unless MarkingsOf[:rhost].any? { |a| e.start_with?(a) }
126
132
  next unless connheader['rhost'].empty?
127
- connheader['rhost'] = cv[1]
133
+ connheader['rhost'] = e[e.index(':') + 1, e.size]
128
134
  connvalues += 1
129
135
  end
130
136
  end
131
137
  return nil unless recipients > 0
132
138
 
133
139
  dscontents.each do |e|
134
- if cv = e['diagnosis'].match(MarkingsOf[:error])
135
- # #550 5.1.1 RESOLVER.ADR.RecipNotFound; not found ##
136
- f = cv[1]
137
- NDRSubject.each_key do |r|
138
- # Try to match with error subject strings
139
- next unless f == r
140
- e['reason'] = NDRSubject[r]
141
- break
142
- end
143
- end
140
+ p = -1
144
141
  e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'])
142
+ MarkingsOf[:error].each do |q|
143
+ # Find an error message, get an error code.
144
+ p = e['diagnosis'].index(q) || -1
145
+ break if p > -1
146
+ end
147
+ next unless p > 0
148
+
149
+ # #550 5.1.1 RESOLVER.ADR.RecipNotFound; not found ##
150
+ f = e['diagnosis'][p + 1, e['diagnosis'].index(';') - p -1]
151
+ NDRSubject.each_key do |r|
152
+ # Try to match with error subject strings
153
+ next unless f == r
154
+ e['reason'] = NDRSubject[r]
155
+ break
156
+ end
145
157
  end
146
158
 
147
- return { 'ds' => dscontents, 'rfc822' => emailsteak[1] }
159
+ return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
148
160
  end
149
161
  def description; return 'Microsoft Exchange Server 2007'; end
150
162
  end