sisimai 4.25.16-java → 5.0.0-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (177) 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 +412 -393
  7. data/Developers.mk +5 -6
  8. data/Gemfile +1 -1
  9. data/Makefile +15 -15
  10. data/README-JA.md +140 -78
  11. data/README.md +290 -143
  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 +23 -18
  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 -326
  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 +12 -12
  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 -22
  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/bsd/{rfc3464-41.eml → rfc3834-05.eml} +0 -0
  170. /data/set-of-emails/maildir/bsd/{rhost-googleapps-01.eml → rhost-google-01.eml} +0 -0
  171. /data/set-of-emails/maildir/bsd/{rhost-googleapps-02.eml → rhost-google-02.eml} +0 -0
  172. /data/set-of-emails/maildir/bsd/{rhost-exchangeonline-01.eml → rhost-microsoft-01.eml} +0 -0
  173. /data/set-of-emails/maildir/bsd/{rhost-exchangeonline-02.eml → rhost-microsoft-02.eml} +0 -0
  174. /data/set-of-emails/maildir/bsd/{rhost-exchangeonline-03.eml → rhost-microsoft-03.eml} +0 -0
  175. /data/set-of-emails/maildir/bsd/{rhost-tencentqq-01.eml → rhost-tencent-01.eml} +0 -0
  176. /data/set-of-emails/maildir/bsd/{rhost-tencentqq-02.eml → rhost-tencent-02.eml} +0 -0
  177. /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