sisimai 4.25.17-java → 5.0.0-java

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 +5 -5
  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 +42 -23
  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::MessagingServer parses a bounce email which created
3
- # by Oracle Communications Messaging Server and Sun Java System Messaging
4
- # Server. Methods in the module are called from only Sisimai::Message.
2
+ # Sisimai::Lhost::MessagingServer parses a bounce email which created by Oracle Communications Messaging
3
+ # Server and Sun Java System Messaging Server. Methods in the module are called from only Sisimai::Message.
5
4
  module MessagingServer
6
5
  class << self
7
- # Imported from p5-Sisimail/lib/Sisimai/Lhost/MessagingServer.pm
8
6
  require 'sisimai/lhost'
9
7
 
10
8
  Indicators = Sisimai::Lhost.INDICATORS
11
- ReBackbone = %r<^(?:Content-type:[ ]*message/rfc822|Return-path:[ ]*)>.freeze
9
+ Boundaries = ['Content-Type: message/rfc822', 'Return-path: '].freeze
12
10
  StartingOf = { message: ['This report relates to a message you sent with the following header fields:'] }.freeze
13
11
  MessagesOf = { 'hostunknown' => ['Illegal host/domain name found'] }.freeze
14
12
 
@@ -17,23 +15,22 @@ module Sisimai::Lhost
17
15
  # @param [String] mbody Message body of a bounce email
18
16
  # @return [Hash] Bounce data list and message/rfc822 part
19
17
  # @return [Nil] it failed to parse or the arguments are missing
20
- def make(mhead, mbody)
21
- # :received => %r/[ ][(]MessagingServer[)][ ]with[ ]/,
18
+ def inquire(mhead, mbody)
22
19
  match = 0
23
20
  match += 1 if mhead['content-type'].include?('Boundary_(ID_')
24
21
  match += 1 if mhead['subject'].start_with?('Delivery Notification: ')
25
22
  return nil unless match > 0
26
23
 
27
24
  dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
28
- emailsteak = Sisimai::RFC5322.fillet(mbody, ReBackbone)
29
- bodyslices = emailsteak[0].split("\n")
25
+ emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
26
+ bodyslices = emailparts[0].split("\n")
30
27
  readcursor = 0 # (Integer) Points the current cursor position
31
28
  recipients = 0 # (Integer) The number of 'Final-Recipient' header
32
29
  v = nil
33
30
 
34
31
  while e = bodyslices.shift do
35
- # Read error messages and delivery status lines from the head of the email
36
- # to the previous line of the beginning of the original message.
32
+ # Read error messages and delivery status lines from the head of the email to the previous
33
+ # line of the beginning of the original message.
37
34
  if readcursor == 0
38
35
  # Beginning of the bounce message or delivery status part
39
36
  readcursor |= Indicators[:deliverystatus] if e.start_with?(StartingOf[:message][0])
@@ -62,45 +59,49 @@ module Sisimai::Lhost
62
59
  # Remote system: dns;mx.example.jp (TCP|17.111.174.67|47323|192.0.2.225|25) (6jo.example.jp ESMTP SENDMAIL-VM)
63
60
  v = dscontents[-1]
64
61
 
65
- if cv = e.match(/\A[ \t]+Recipient address:[ \t]*([^ ]+[@][^ ]+)\z/)
62
+ if e.start_with?(' Recipient address: ') && e.index('@') > 1
66
63
  # Recipient address: kijitora@example.jp
67
64
  if v['recipient']
68
65
  # There are multiple recipient addresses in the message body.
69
66
  dscontents << Sisimai::Lhost.DELIVERYSTATUS
70
67
  v = dscontents[-1]
71
68
  end
72
- v['recipient'] = Sisimai::Address.s3s4(cv[1])
69
+ v['recipient'] = Sisimai::Address.s3s4(e[e.rindex(' ') + 1, e.size])
73
70
  recipients += 1
74
71
 
75
- elsif cv = e.match(/\A[ \t]+Original address:[ \t]*([^ ]+[@][^ ]+)\z/)
72
+ elsif e.start_with?(' Original address: ') && e.index('@') > 1
76
73
  # Original address: kijitora@example.jp
77
- v['recipient'] = Sisimai::Address.s3s4(cv[1])
74
+ v['recipient'] = Sisimai::Address.s3s4(e[e.rindex(' ') + 1, e.size])
78
75
 
79
- elsif cv = e.match(/\A[ \t]+Date:[ \t]*(.+)\z/)
76
+ elsif e.start_with?(' Date: ')
80
77
  # Date: Fri, 21 Nov 2014 23:34:45 +0900
81
- v['date'] = cv[1]
78
+ v['date'] = e[e.index(':') + 2, e.size]
82
79
 
83
- elsif cv = e.match(/\A[ \t]+Reason:[ \t]*(.+)\z/)
80
+ elsif e.start_with?(' Reason: ')
84
81
  # Reason: Remote SMTP server has rejected address
85
- v['diagnosis'] = cv[1]
82
+ v['diagnosis'] = e[e.index(':') + 2, e.size]
86
83
 
87
- elsif cv = e.match(/\A[ \t]+Diagnostic code:[ \t]*([^ ]+);(.+)\z/)
84
+ elsif e.start_with?(' Diagnostic code: ')
88
85
  # Diagnostic code: smtp;550 5.1.1 <kijitora@example.jp>... User Unknown
89
- v['spec'] = cv[1].upcase
90
- v['diagnosis'] = cv[2]
86
+ p1 = e.index(':')
87
+ p2 = e.index(';')
88
+ v['spec'] = e[p1 + 2, p2 - p1 - 2].upcase
89
+ v['diagnosis'] = e[p2 + 1, e.size]
91
90
 
92
- elsif cv = e.match(/\A[ \t]+Remote system:[ ]*dns;([^ ]+)[ ]*([^ ]+)[ ]*.+\z/)
91
+ elsif e.start_with?(' Remote system: ')
93
92
  # Remote system: dns;mx.example.jp (TCP|17.111.174.67|47323|192.0.2.225|25)
94
93
  # (6jo.example.jp ESMTP SENDMAIL-VM)
95
- remotehost = cv[1] # remote host
96
- sessionlog = cv[2] # smtp session
94
+ p1 = e.index(';')
95
+ p2 = e.index('(')
96
+ remotehost = e[p1 + 1, p2 - p1 - 2]
97
+ sessionlog = e[p2, e.size].split('|')
97
98
  v['rhost'] = remotehost
98
99
 
99
100
  # The value does not include ".", use IP address instead.
100
101
  # (TCP|17.111.174.67|47323|192.0.2.225|25)
101
- next unless cv = sessionlog.match(/\A[(]TCP|(.+)|\d+|(.+)|\d+[)]/)
102
- v['lhost'] = cv[1]
103
- v['rhost'] = cv[2] unless remotehost =~ /[^.]+[.][^.]+/
102
+ next unless sessionlog[0] == '(TCP'
103
+ v['lhost'] = sessionlog[1]
104
+ v['rhost'] = sessionlog[3] unless remotehost.index('.') > 1
104
105
  else
105
106
  # Original-envelope-id: 0NFC009FLKOUVMA0@mr21p30im-asmtp004.me.com
106
107
  # Reporting-MTA: dns;mr21p30im-asmtp004.me.com (tcp-daemon)
@@ -114,20 +115,22 @@ module Sisimai::Lhost
114
115
  # (6jo.example.jp ESMTP SENDMAIL-VM)
115
116
  # Diagnostic-code: smtp;550 5.1.1 <kijitora@example.jp>... User Unknown
116
117
  #
117
- if cv = e.match(/\AStatus:[ ]*(\d[.]\d[.]\d)[ ]*[(](.+)[)]\z/)
118
+ if e.start_with?('Status: ')
118
119
  # Status: 5.1.1 (Remote SMTP server has rejected address)
119
- v['status'] = cv[1]
120
- v['diagnosis'] ||= cv[2]
120
+ p1 = e.index(':')
121
+ p2 = e.index('(')
122
+ v['status'] = e[p1 + 2, p2 - p1 - 3]
123
+ v['diagnosis'] ||= e[p2 + 1, e[e.index(')') - p2 - 1]]
121
124
 
122
- elsif cv = e.match(/\AArrival-Date:[ ]*(.+)\z/)
125
+ elsif e.start_with?('Arrival-Date: ')
123
126
  # Arrival-date: Thu, 29 Apr 2014 23:34:45 +0000 (GMT)
124
- v['date'] ||= cv[1]
127
+ v['date'] ||= e[e.index(':') + 2, e.size]
125
128
 
126
- elsif cv = e.match(/\AReporting-MTA:[ ]*(?:DNS|dns);[ ]*(.+)\z/)
129
+ elsif e.start_with?('Reporting-MTA: ')
127
130
  # Reporting-MTA: dns;mr21p30im-asmtp004.me.com (tcp-daemon)
128
- localhost = cv[1]
131
+ localhost = e[e.index(';') + 1, e.size]
129
132
  v['lhost'] ||= localhost
130
- v['lhost'] = localhost unless v['lhost'] =~ /[^.]+[.][^ ]+/
133
+ v['lhost'] = localhost unless v['lhost'].index('.') > 0
131
134
  end
132
135
  end
133
136
  end
@@ -143,7 +146,7 @@ module Sisimai::Lhost
143
146
  end
144
147
  end
145
148
 
146
- return { 'ds' => dscontents, 'rfc822' => emailsteak[1] }
149
+ return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
147
150
  end
148
151
  def description; return 'Oracle Communications Messaging Server'; end
149
152
  end
@@ -1,44 +1,43 @@
1
1
  module Sisimai::Lhost
2
- # Sisimai::Lhost::mFILTER parses a bounce email which created by
3
- # Digital Arts m-FILTER.
4
- # Methods in the module are called from only Sisimai::Message.
2
+ # Sisimai::Lhost::mFILTER parses a bounce email which created by Digital Arts m-FILTER. Methods in
3
+ # the module are called from only Sisimai::Message.
5
4
  module MFILTER
6
5
  class << self
7
- # Imported from p5-Sisimail/lib/Sisimai/Lhost/mFILTER.pm
8
6
  require 'sisimai/lhost'
9
7
 
10
8
  Indicators = Sisimai::Lhost.INDICATORS
11
- ReBackbone = %r/^-------original[ ](?:message|mail[ ]info)/.freeze
9
+ Boundaries = ['-------original message', '-------original mail info'].freeze
12
10
  StartingOf = {
13
11
  error: ['-------server message'],
14
12
  command: ['-------SMTP command'],
15
13
  }.freeze
16
- MarkingsOf = { message: %r/\A[^ ]+[@][^ ]+[.][a-zA-Z]+\z/ }.freeze
17
14
 
18
15
  # Parse bounce messages from Digital Arts m-FILTER
19
16
  # @param [Hash] mhead Message headers of a bounce email
20
17
  # @param [String] mbody Message body of a bounce email
21
18
  # @return [Hash] Bounce data list and message/rfc822 part
22
19
  # @return [Nil] it failed to parse or the arguments are missing
23
- def make(mhead, mbody)
20
+ def inquire(mhead, mbody)
24
21
  # X-Mailer: m-FILTER
25
22
  return nil unless mhead['x-mailer'].to_s == 'm-FILTER'
26
23
  return nil unless mhead['subject'] == 'failure notice'
27
24
 
28
25
  dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
29
- emailsteak = Sisimai::RFC5322.fillet(mbody, ReBackbone)
30
- bodyslices = emailsteak[0].split("\n")
26
+ emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
27
+ bodyslices = emailparts[0].split("\n")
31
28
  readcursor = 0 # (Integer) Points the current cursor position
32
29
  recipients = 0 # (Integer) The number of 'Final-Recipient' header
33
30
  markingset = { 'diagnosis' => false, 'command' => false }
34
31
  v = nil
35
32
 
36
33
  while e = bodyslices.shift do
37
- # Read error messages and delivery status lines from the head of the email
38
- # to the previous line of the beginning of the original message.
34
+ # Read error messages and delivery status lines from the head of the email to the previous
35
+ # line of the beginning of the original message.
39
36
  if readcursor == 0
40
37
  # Beginning of the bounce message or delivery status part
41
- readcursor |= Indicators[:deliverystatus] if e =~ MarkingsOf[:message]
38
+ if e.include?('@') && e.include?(' ') == false && Sisimai::Address.is_emailaddress(e)
39
+ readcursor |= Indicators[:deliverystatus]
40
+ end
42
41
  end
43
42
  next if (readcursor & Indicators[:deliverystatus]) == 0
44
43
  next if e.empty?
@@ -60,7 +59,7 @@ module Sisimai::Lhost
60
59
  # -------original message
61
60
  v = dscontents[-1]
62
61
 
63
- if cv = e.match(/\A([^ ]+[@][^ ]+)\z/)
62
+ if e.include?('@') && e.include?(' ') == false
64
63
  # 以下のメールアドレスへの送信に失敗しました。
65
64
  # kijitora@example.jp
66
65
  if v['recipient']
@@ -68,10 +67,10 @@ module Sisimai::Lhost
68
67
  dscontents << Sisimai::Lhost.DELIVERYSTATUS
69
68
  v = dscontents[-1]
70
69
  end
71
- v['recipient'] = cv[1]
70
+ v['recipient'] = e
72
71
  recipients += 1
73
72
 
74
- elsif e =~ /\A[A-Z]{4}/
73
+ elsif e.size == 4 && e.index(' ').nil?
75
74
  # -------SMTP command
76
75
  # DATA
77
76
  next if v['command']
@@ -111,7 +110,7 @@ module Sisimai::Lhost
111
110
  e['rhost'] = ee
112
111
  end
113
112
  end
114
- return { 'ds' => dscontents, 'rfc822' => emailsteak[1] }
113
+ return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
115
114
  end
116
115
  def description; return 'Digital Arts m-FILTER'; end
117
116
  end
@@ -1,22 +1,20 @@
1
1
  module Sisimai::Lhost
2
- # Sisimai::Lhost::MXLogic parses a bounce email which created by
3
- # McAfee SaaS (formerly MX Logic).
2
+ # Sisimai::Lhost::MXLogic parses a bounce email which created by McAfee SaaS (formerly MX Logic).
4
3
  # Methods in the module are called from only Sisimai::Message.
5
4
  module MXLogic
6
5
  class << self
7
- # Imported from p5-Sisimail/lib/Sisimai/Lhost/MXLogic.pm
8
6
  # Based on Sisimai::Lhost::Exim
9
7
  require 'sisimai/lhost'
10
8
 
11
9
  Indicators = Sisimai::Lhost.INDICATORS
12
- ReBackbone = %r|^Included is a copy of the message header:|.freeze
10
+ Boundaries = ['Included is a copy of the message header:'].freeze
13
11
  StartingOf = { message: ['This message was created automatically by mail delivery software.'] }.freeze
14
12
  ReCommands = [
15
13
  %r/SMTP error from remote (?:mail server|mailer) after ([A-Za-z]{4})/,
16
14
  %r/SMTP error from remote (?:mail server|mailer) after end of ([A-Za-z]{4})/,
17
15
  ].freeze
18
16
  MessagesOf = {
19
- # find exim/ -type f -exec grep 'message = US' {} /dev/null \;
17
+ # % find exim/ -type f -exec grep 'message = US' {} /dev/null \;
20
18
  # route.c:1158| DEBUG(D_uid) debug_printf("getpwnam() returned NULL (user not found)\n");
21
19
  'userunknown' => ['user not found'],
22
20
  # transports/smtp.c:3524| addr->message = US"all host address lookups failed permanently";
@@ -74,7 +72,7 @@ module Sisimai::Lhost
74
72
  # @param [String] mbody Message body of a bounce email
75
73
  # @return [Hash] Bounce data list and message/rfc822 part
76
74
  # @return [Nil] it failed to parse or the arguments are missing
77
- def make(mhead, mbody)
75
+ def inquire(mhead, mbody)
78
76
  # X-MX-Bounce: mta/src/queue/bounce
79
77
  # X-MXL-NoteHash: ffffffffffffffff-0000000000000000000000000000000000000000
80
78
  # X-MXL-Hash: 4c9d4d411993da17-bbd4212b6c887f6c23bab7db4bd87ef5edc00758
@@ -83,25 +81,20 @@ module Sisimai::Lhost
83
81
  match += 1 if mhead['x-mxl-hash']
84
82
  match += 1 if mhead['x-mxl-notehash']
85
83
  match += 1 if mhead['from'].start_with?('Mail Delivery System')
86
- match += 1 if mhead['subject'] =~ %r{(?:
87
- Mail[ ]delivery[ ]failed(:[ ]returning[ ]message[ ]to[ ]sender)?
88
- |Warning:[ ]message[ ][^ ]+[ ]delayed[ ]+
89
- |Delivery[ ]Status[ ]Notification
90
- )
91
- }x
84
+ match += 1 if ['Delivery Status Notification', 'Mail delivery failed', 'Warning: message '].any? { |a| mhead['subject'].include?(a) }
92
85
  return nil unless match > 0
93
86
 
94
87
  dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
95
- emailsteak = Sisimai::RFC5322.fillet(mbody, ReBackbone)
96
- bodyslices = emailsteak[0].split("\n")
88
+ emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
89
+ bodyslices = emailparts[0].split("\n")
97
90
  readcursor = 0 # (Integer) Points the current cursor position
98
91
  recipients = 0 # (Integer) The number of 'Final-Recipient' header
99
92
  localhost0 = '' # (String) Local MTA
100
93
  v = nil
101
94
 
102
95
  while e = bodyslices.shift do
103
- # Read error messages and delivery status lines from the head of the email
104
- # to the previous line of the beginning of the original message.
96
+ # Read error messages and delivery status lines from the head of the email to the previous
97
+ # line of the beginning of the original message.
105
98
  if readcursor == 0
106
99
  # Beginning of the bounce message or delivery status part
107
100
  readcursor |= Indicators[:deliverystatus] if e == StartingOf[:message][0]
@@ -120,7 +113,7 @@ module Sisimai::Lhost
120
113
  # host neko.example.jp [192.0.2.222]: 550 5.1.1 <kijitora@example.jp>... User Unknown
121
114
  v = dscontents[-1]
122
115
 
123
- if cv = e.match(/\A[ \t]*[<]([^ ]+[@][^ ]+)[>]:(.+)\z/)
116
+ if e.start_with?(' <') && e.include?('@') && e.include?('>:')
124
117
  # A message that you have sent could not be delivered to one or more
125
118
  # recipients. This is a permanent error. The following address failed:
126
119
  #
@@ -130,8 +123,8 @@ module Sisimai::Lhost
130
123
  dscontents << Sisimai::Lhost.DELIVERYSTATUS
131
124
  v = dscontents[-1]
132
125
  end
133
- v['recipient'] = cv[1]
134
- v['diagnosis'] = cv[2]
126
+ v['recipient'] = e[3, e.index('>:') - 3]
127
+ v['diagnosis'] = e[e.index('>:') + 3, e.size]
135
128
  recipients += 1
136
129
 
137
130
  elsif dscontents.size == recipients
@@ -144,8 +137,13 @@ module Sisimai::Lhost
144
137
 
145
138
  unless mhead['received'].empty?
146
139
  # Get the name of local MTA
147
- # Received: from marutamachi.example.org (c192128.example.net [192.0.2.128])
148
- if cv = mhead['received'][-1].match(/from[ ]([^ ]+) /) then localhost0 = cv[1] end
140
+ p1 = mhead['received'][-1].downcase.index('from ')
141
+ p2 = mhead['received'][-1].index(' ', p1 + 5)
142
+
143
+ if (p1 + 1) * (p2 + 1) > 0
144
+ # Received: from marutamachi.example.org (c192128.example.net [192.0.2.128])
145
+ localhost0 = mhead['received'][-1][p1 + 5, p2 - p1 - 5]
146
+ end
149
147
  end
150
148
 
151
149
  dscontents.each do |e|
@@ -154,8 +152,11 @@ module Sisimai::Lhost
154
152
 
155
153
  unless e['rhost']
156
154
  # Get the remote host name
155
+ p1 = e['diagnosis'].index('host ') || -1
156
+ p2 = e['diagnosis'].index(' ', p1 + 5)
157
+
157
158
  # host neko.example.jp [192.0.2.222]: 550 5.1.1 <kijitora@example.jp>... User Unknown
158
- if cv = e['diagnosis'].match(/host[ ]+([^ \t]+)[ ]\[.+\]:[ ]/) then e['rhost'] = cv[1] end
159
+ e['rhost'] = e['diagnosis'][p1 + 5, p2 - p1 - 5] if p1 > -1
159
160
 
160
161
  unless e['rhost']
161
162
  # Get localhost and remote host name from Received header.
@@ -198,7 +199,7 @@ module Sisimai::Lhost
198
199
  end
199
200
  end
200
201
 
201
- return { 'ds' => dscontents, 'rfc822' => emailsteak[1] }
202
+ return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
202
203
  end
203
204
  def description; return 'McAfee SaaS'; end
204
205
  end
@@ -1,13 +1,12 @@
1
1
  module Sisimai::Lhost
2
- # Sisimai::Lhost::Notes parses a bounce email which created by Lotus
3
- # Notes Server. Methods in the module are called from only Sisimai::Message.
2
+ # Sisimai::Lhost::Notes parses a bounce email which created by Lotus Notes Server. Methods in the
3
+ # module are called from only Sisimai::Message.
4
4
  module Notes
5
5
  class << self
6
- # Imported from p5-Sisimail/lib/Sisimai/Lhost/Notes.pm
7
6
  require 'sisimai/lhost'
8
7
 
9
8
  Indicators = Sisimai::Lhost.INDICATORS
10
- ReBackbone = %r|^-------[ ]Returned[ ]Message[ ]--------|.freeze
9
+ Boundaries = ['------- Returned Message --------'].freeze
11
10
  StartingOf = { message: ['------- Failure Reasons '] }.freeze
12
11
  MessagesOf = {
13
12
  'userunknown' => [
@@ -22,12 +21,12 @@ module Sisimai::Lhost
22
21
  # @param [String] mbody Message body of a bounce email
23
22
  # @return [Hash] Bounce data list and message/rfc822 part
24
23
  # @return [Nil] it failed to parse or the arguments are missing
25
- def make(mhead, mbody)
24
+ def inquire(mhead, mbody)
26
25
  return nil unless mhead['subject'].start_with?('Undeliverable message')
27
26
 
28
27
  dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
29
- emailsteak = Sisimai::RFC5322.fillet(mbody, ReBackbone)
30
- bodyslices = emailsteak[0].split("\n")
28
+ emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
29
+ bodyslices = emailparts[0].split("\n")
31
30
  readcursor = 0 # (Integer) Points the current cursor position
32
31
  recipients = 0 # (Integer) The number of 'Final-Recipient' header
33
32
  characters = '' # (String) Character set name of the bounce mail
@@ -35,15 +34,14 @@ module Sisimai::Lhost
35
34
  encodedmsg = ''
36
35
  v = nil
37
36
 
38
- if cv = mhead['content-type'].match(/\A.+;[ ]*charset=(.+)\z/)
39
- # Get character set name
40
- # Content-Type: text/plain; charset=ISO-2022-JP
41
- characters = cv[1].downcase
37
+ if mhead['content-type'].include?('charset=')
38
+ # Get character set name, Content-Type: text/plain; charset=ISO-2022-JP
39
+ characters = mhead['content-type'][mhead['content-type'].index('charset=') + 8, mhead['content-type'].size].downcase
42
40
  end
43
41
 
44
42
  while e = bodyslices.shift do
45
- # Read error messages and delivery status lines from the head of the email
46
- # to the previous line of the beginning of the original message.
43
+ # Read error messages and delivery status lines from the head of the email to the previous
44
+ # line of the beginning of the original message.
47
45
  if readcursor == 0
48
46
  # Beginning of the bounce message or delivery status part
49
47
  readcursor |= Indicators[:deliverystatus] if e.start_with?(StartingOf[:message][0])
@@ -58,7 +56,7 @@ module Sisimai::Lhost
58
56
  #
59
57
  # ------- Returned Message --------
60
58
  v = dscontents[-1]
61
- if e =~ /\A[^ ]+[@][^ ]+/
59
+ if e.include?('@') && e.index(' ').nil?
62
60
  # kijitora@notes.example.jp
63
61
  if v['recipient']
64
62
  # There are multiple recipient addresses in the message body.
@@ -97,8 +95,10 @@ module Sisimai::Lhost
97
95
 
98
96
  unless recipients > 0
99
97
  # Fallback: Get the recpient address from RFC822 part
100
- if cv = emailsteak[1].match(/^To:[ ]*(.+)$/)
101
- v['recipient'] = Sisimai::Address.s3s4(cv[1])
98
+ p1 = emailparts[1].index("\nTo: ") || -1
99
+ p2 = emailparts[1].index("\n", p1 + 6) || -1
100
+ if p1 > 0
101
+ v['recipient'] = Sisimai::Address.s3s4(emailparts[1][p1 + 5, p2 - p1 - 5]) || ''
102
102
  recipients += 1 unless v['recipient'].empty?
103
103
  end
104
104
  end
@@ -117,7 +117,7 @@ module Sisimai::Lhost
117
117
  end
118
118
  end
119
119
 
120
- return { 'ds' => dscontents, 'rfc822' => emailsteak[1] }
120
+ return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
121
121
  end
122
122
  def description; return 'Lotus Notes'; end
123
123
  end
@@ -1,25 +1,44 @@
1
1
  module Sisimai::Lhost
2
- # Sisimai::Lhost::Office365 parses a bounce email which created by
3
- # Microsoft Office 365.
4
- # Methods in the module are called from only Sisimai::Message.
2
+ # Sisimai::Lhost::Office365 parses a bounce email which created by Microsoft Office 365. Methods in
3
+ # the module are called from only Sisimai::Message.
5
4
  module Office365
6
5
  class << self
7
- # Imported from p5-Sisimail/lib/Sisimai/Lhost/Office365.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', 'Original message headers:'].freeze
12
10
  StartingOf = {
13
11
  error: ['Diagnostic information for administrators:'],
14
12
  eoerr: ['Original message headers:'],
15
13
  }.freeze
16
14
  MarkingsOf = {
17
- eoe: %r/\A(?:Original[ ][Mm]essage[ ][Hh]eaders:?|Message[ ]Hops)/,
18
- error: %r/\A(?:Diagnostic[ ]information[ ]for[ ]administrators:|Error[ ]Details)/,
15
+ eoe: %r{\A(?:
16
+ Original[ ][Mm]essage[ ][Hh]eaders:?
17
+ |Message[ ]Hops
18
+ |Cabe.+alhos[ ]originais[ ]da[ ]mensagem:
19
+ |Oorspronkelijke[ ]berichtkoppen:
20
+ )
21
+ }x,
22
+ rfc3464: %r|\AContent-Type:[ ]message/delivery-status|,
23
+ lhost: %r{\A(?:
24
+ Generating[ ]server
25
+ |Bronserver
26
+ |Servidor[ ]de[ ]origem
27
+ ):[ ](.+)\z
28
+ }x,
29
+ error: %r{\A(?:
30
+ Diagnostic[ ]information[ ]for[ ]administrators:
31
+ |Error[ ]Details
32
+ |Diagnostische[ ]gegevens[ ]voor[ ]beheerders:
33
+ |Informa.+es[ ]de[ ]diagn.+stico[ ]para[ ]administradores:
34
+ )
35
+ }x,
19
36
  message: %r{\A(?:
20
37
  Delivery[ ]has[ ]failed[ ]to[ ]these[ ]recipients[ ]or[ ]groups:
21
38
  |Original[ ]Message[ ]Details
22
39
  |.+[ ]rejected[ ]your[ ]message[ ]to[ ]the[ ]following[ ]e[-]?mail[ ]addresses:
40
+ |Falha[ ]na[ ]entrega[ ]a[ ]estes[ ]destinat.+rios[ ]ou[ ]grupos:
41
+ |Uw[ ]bericht[ ]kan[ ]niet[ ]worden[ ]bezorgd[ ]bij[ ]de[ ]volgende[ ]geadresseerden[ ]of[ ]groepen:
23
42
  )
24
43
  }x,
25
44
  }.freeze
@@ -37,7 +56,7 @@ module Sisimai::Lhost
37
56
  %r/\A4[.]4[.]7\z/ => 'expired',
38
57
  %r/\A4[.]4[.]312\z/ => 'networkerror',
39
58
  %r/\A4[.]4[.]316\z/ => 'expired',
40
- %r/\A4[.]7[.]26\z/ => 'securityerror',
59
+ %r/\A4[.]7[.]26\z/ => 'authfailure',
41
60
  %r/\A4[.]7[.][56]\d\d\z/ => 'blocked',
42
61
  %r/\A4[.]7[.]8[5-9]\d\z/ => 'blocked',
43
62
  %r/\A5[.]0[.]350\z/ => 'contenterror',
@@ -57,10 +76,10 @@ module Sisimai::Lhost
57
76
  %r/\A5[.]7[.]50[4-5]\z/ => 'filtered',
58
77
  %r/\A5[.]7[.]50[6-7]\z/ => 'blocked',
59
78
  %r/\A5[.]7[.]508\z/ => 'toomanyconn',
60
- %r/\A5[.]7[.]509\z/ => 'securityerror',
79
+ %r/\A5[.]7[.]509\z/ => 'authfailure',
61
80
  %r/\A5[.]7[.]510\z/ => 'notaccept',
62
81
  %r/\A5[.]7[.]511\z/ => 'rejected',
63
- %r/\A5[.]7[.]512\z/ => 'securityerror',
82
+ %r/\A5[.]7[.]512\z/ => 'authfailure',
64
83
  %r/\A5[.]7[.]57\z/ => 'securityerror',
65
84
  %r/\A5[.]7[.]60[6-9]\z/ => 'blocked',
66
85
  %r/\A5[.]7[.]6[1-4]\d\z/ => 'blocked',
@@ -75,7 +94,7 @@ module Sisimai::Lhost
75
94
  # @param [String] mbody Message body of a bounce email
76
95
  # @return [Hash] Bounce data list and message/rfc822 part
77
96
  # @return [Nil] it failed to parse or the arguments are missing
78
- def make(mhead, mbody)
97
+ def inquire(mhead, mbody)
79
98
  # X-MS-Exchange-Message-Is-Ndr:
80
99
  # X-Microsoft-Antispam-PRVS: <....@...outlook.com>
81
100
  # X-Exchange-Antispam-Report-Test: UriScan:;
@@ -86,6 +105,9 @@ module Sisimai::Lhost
86
105
  tryto = %r/.+[.](?:outbound[.]protection|prod)[.]outlook[.]com\b/
87
106
  match = 0
88
107
  match += 1 if mhead['subject'].include?('Undeliverable:')
108
+ match += 1 if mhead['subject'].include?('Onbestelbaar:')
109
+ match += 1 if mhead['subject'].include?('Não_entregue:')
110
+
89
111
  Headers365.each do |e|
90
112
  next if mhead[e].nil?
91
113
  next if mhead[e].empty?
@@ -102,8 +124,8 @@ module Sisimai::Lhost
102
124
  fieldtable = Sisimai::RFC1894.FIELDTABLE
103
125
  permessage = {} # (Hash) Store values of each Per-Message field
104
126
  dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
105
- emailsteak = Sisimai::RFC5322.fillet(mbody, ReBackbone)
106
- bodyslices = emailsteak[0].split("\n")
127
+ emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
128
+ bodyslices = emailparts[0].split("\n")
107
129
  readcursor = 0 # (Integer) Points the current cursor position
108
130
  recipients = 0 # (Integer) The number of 'Final-Recipient' header
109
131
  connheader = {}
@@ -112,8 +134,8 @@ module Sisimai::Lhost
112
134
  v = nil
113
135
 
114
136
  while e = bodyslices.shift do
115
- # Read error messages and delivery status lines from the head of the email
116
- # to the previous line of the beginning of the original message.
137
+ # Read error messages and delivery status lines from the head of the email to the previous
138
+ # line of the beginning of the original message.
117
139
  if readcursor == 0
118
140
  # Beginning of the bounce message or delivery status part
119
141
  readcursor |= Indicators[:deliverystatus] if e =~ MarkingsOf[:message]
@@ -145,7 +167,7 @@ module Sisimai::Lhost
145
167
  v['recipient'] = cv[1]
146
168
  recipients += 1
147
169
 
148
- elsif cv = e.match(/\AGenerating server: (.+)\z/)
170
+ elsif cv = e.match(MarkingsOf[:lhost])
149
171
  # Generating server: FFFFFFFFFFFF.e0.prod.outlook.com
150
172
  connheader['lhost'] = cv[1].downcase
151
173
  else
@@ -154,11 +176,20 @@ module Sisimai::Lhost
154
176
  next unless f = Sisimai::RFC1894.match(e)
155
177
  next unless o = Sisimai::RFC1894.field(e)
156
178
  next unless fieldtable[o[0]]
157
- next if o[0] =~ /\A(?:diagnostic-code|final-recipient)\z/
158
- v[fieldtable[o[0]]] = o[2]
159
179
 
160
- next unless f == 1
161
- permessage[fieldtable[o[0]]] = o[2]
180
+ if v['diagnosis']
181
+ # Do not capture "Diagnostic-Code:" field because error message have already
182
+ # been captured
183
+ next if o[0] =~ /\A(?:diagnostic-code|final-recipient)\z/
184
+ v[fieldtable[o[0]]] = o[2]
185
+
186
+ next unless f
187
+ permessage[fieldtable[o[0]]] = o[2]
188
+ else
189
+ # Capture "Diagnostic-Code:" field because no error messages have been captured
190
+ v[fieldtable[o[0]]] = o[2]
191
+ permessage[fieldtable[o[0]]] = o[2]
192
+ end
162
193
  else
163
194
  if e =~ MarkingsOf[:error]
164
195
  # Diagnostic information for administrators:
@@ -167,13 +198,18 @@ module Sisimai::Lhost
167
198
  # kijitora@example.com
168
199
  # Remote Server returned '550 5.1.10 RESOLVER.ADR.RecipientNotFound; Recipien=
169
200
  # t not found by SMTP address lookup'
170
- next unless v['diagnosis']
171
- if e =~ MarkingsOf[:eoe]
172
- # Original message headers:
173
- endoferror = true
174
- next
201
+ if v['diagnosis']
202
+ # The error message text have already captured
203
+ if e =~ MarkingsOf[:eoe]
204
+ # Original message headers:
205
+ endoferror = true
206
+ next
207
+ end
208
+ v['diagnosis'] << ' ' << e
209
+ else
210
+ # The error message text has not been captured yet
211
+ endoferror = true if e =~ MarkingsOf[:rfc3464]
175
212
  end
176
- v['diagnosis'] << ' ' << e
177
213
  end
178
214
  end
179
215
  end
@@ -207,7 +243,7 @@ module Sisimai::Lhost
207
243
  end
208
244
  end
209
245
 
210
- return { 'ds' => dscontents, 'rfc822' => emailsteak[1] }
246
+ return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
211
247
  end
212
248
  def description; return 'Microsoft Office 365: https://office.microsoft.com/'; end
213
249
  end