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,41 +1,28 @@
1
1
  module Sisimai::Lhost
2
- # Sisimai::Lhost::EZweb parses a bounce email which created by au EZweb.
3
- # Methods in the module are called from only Sisimai::Message.
2
+ # Sisimai::Lhost::EZweb parses a bounce email which created by au EZweb. Methods in the module are
3
+ # called from only Sisimai::Message.
4
4
  module EZweb
5
5
  class << self
6
- # Imported from p5-Sisimail/lib/Sisimai/Lhost/EZweb.pm
7
6
  require 'sisimai/lhost'
8
7
 
9
8
  Indicators = Sisimai::Lhost.INDICATORS
10
- ReBackbone = %r<^(?:[-]{50}|Content-Type:[ ]*message/rfc822)>.freeze
11
- MarkingsOf = {
12
- message: %r{\A(?:
13
- The[ ]user[(]s[)][ ]
14
- |Your[ ]message[ ]
15
- |Each[ ]of[ ]the[ ]following
16
- |[<][^ ]+[@][^ ]+[>]\z
17
- )
18
- }x,
19
- }.freeze
9
+ Boundaries = ['--------------------------------------------------', 'Content-Type: message/rfc822'].freeze
10
+ MarkingsOf = { message: ['The user(s) ', 'Your message ', 'Each of the following', '<'] }.freeze
20
11
  ReFailures = {
21
- # notaccept: [ %r/The following recipients did not receive this message:/ ],
22
- 'mailboxfull' => [
23
- %r/The user[(]s[)] account is temporarily over quota/,
24
- ],
12
+ # notaccept: ['The following recipients did not receive this message:'],
13
+ 'mailboxfull' => ['The user(s) account is temporarily over quota'],
25
14
  'suspend' => [
26
15
  # http://www.naruhodo-au.kddi.com/qa3429203.html
27
16
  # The recipient may be unpaid user...?
28
- %r/The user[(]s[)] account is disabled[.]/,
29
- %r/The user[(]s[)] account is temporarily limited[.]/,
17
+ 'The user(s) account is disabled.',
18
+ 'The user(s) account is temporarily limited.',
30
19
  ],
31
20
  'expired' => [
32
21
  # Your message was not delivered within 0 days and 1 hours.
33
22
  # Remote host is not responding.
34
- %r/Your message was not delivered within /,
35
- ],
36
- 'onhold' => [
37
- %r/Each of the following recipients was rejected by a remote mail server/,
23
+ 'Your message was not delivered within ',
38
24
  ],
25
+ 'onhold' => ['Each of the following recipients was rejected by a remote mail server'],
39
26
  }.freeze
40
27
 
41
28
  # Parse bounce messages from au EZweb
@@ -43,7 +30,7 @@ module Sisimai::Lhost
43
30
  # @param [String] mbody Message body of a bounce email
44
31
  # @return [Hash] Bounce data list and message/rfc822 part
45
32
  # @return [Nil] it failed to parse or the arguments are missing
46
- def make(mhead, mbody)
33
+ def inquire(mhead, mbody)
47
34
  match = 0
48
35
  match += 1 if mhead['from'].include?('Postmaster@ezweb.ne.jp')
49
36
  match += 1 if mhead['from'].include?('Postmaster@au.com')
@@ -55,31 +42,21 @@ module Sisimai::Lhost
55
42
  end
56
43
  return nil if match < 2
57
44
 
58
- require 'sisimai/rfc1894'
59
45
  fieldtable = Sisimai::RFC1894.FIELDTABLE
60
46
  dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
61
- emailsteak = Sisimai::RFC5322.fillet(mbody, ReBackbone)
62
- bodyslices = emailsteak[0].split("\n")
47
+ emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
48
+ bodyslices = emailparts[0].split("\n")
63
49
  readcursor = 0 # (Integer) Points the current cursor position
64
50
  recipients = 0 # (Integer) The number of 'Final-Recipient' header
65
- rxboundary = %r/\A__SISIMAI_PSEUDO_BOUNDARY__\z/
51
+ rxmessages = []; ReFailures.each_value { |a| rxmessages << a }
66
52
  v = nil
67
53
 
68
- if mhead['content-type']
69
- # Get the boundary string and set regular expression for matching with
70
- # the boundary string.
71
- b0 = Sisimai::MIME.boundary(mhead['content-type'], 1)
72
- rxboundary = Regexp.new('\A' << Regexp.escape(b0) << '\z') unless b0.empty?
73
- end
74
- rxmessages = []
75
- ReFailures.each_value { |a| rxmessages << a }
76
-
77
54
  while e = bodyslices.shift do
78
- # Read error messages and delivery status lines from the head of the email
79
- # to the previous line of the beginning of the original message.
55
+ # Read error messages and delivery status lines from the head of the email to the previous
56
+ # line of the beginning of the original message.
80
57
  if readcursor == 0
81
58
  # Beginning of the bounce message or delivery status part
82
- readcursor |= Indicators[:deliverystatus] if e =~ MarkingsOf[:message]
59
+ readcursor |= Indicators[:deliverystatus] if MarkingsOf[:message].any? { |a| e.include?(a) }
83
60
  end
84
61
  next if (readcursor & Indicators[:deliverystatus]) == 0
85
62
  next if e.empty?
@@ -97,18 +74,17 @@ module Sisimai::Lhost
97
74
  # <<< 550 <******@ezweb.ne.jp>: User unknown
98
75
  v = dscontents[-1]
99
76
 
100
- if cv = e.match(/\A[<]([^ ]+[@][^ ]+)[>]\z/) ||
101
- e.match(/\A[<]([^ ]+[@][^ ]+)[>]:?(.*)\z/) ||
102
- e.match(/\A[ \t]+Recipient: [<]([^ ]+[@][^ ]+)[>]/)
77
+ if Sisimai::String.aligned(e, ['<', '@', '>']) && (e.include?('Recipient: <') || e.start_with?('<'))
78
+ # Recipient: <******@ezweb.ne.jp> OR <***@ezweb.ne.jp>: 550 user unknown ...
79
+ p1 = e.index('<') || -1
80
+ p2 = e.index('>') || -1
103
81
 
104
82
  if v['recipient']
105
83
  # There are multiple recipient addresses in the message body.
106
84
  dscontents << Sisimai::Lhost.DELIVERYSTATUS
107
85
  v = dscontents[-1]
108
86
  end
109
-
110
- r = Sisimai::Address.s3s4(cv[1])
111
- v['recipient'] = r
87
+ v['recipient'] = Sisimai::Address.s3s4(e[p1, p2 - p1])
112
88
  recipients += 1
113
89
 
114
90
  elsif f = Sisimai::RFC1894.match(e)
@@ -120,12 +96,12 @@ module Sisimai::Lhost
120
96
  else
121
97
  # The line does not begin with a DSN field defined in RFC3464
122
98
  next if Sisimai::String.is_8bit(e)
123
- if cv = e.match(/\A[ \t]+[>]{3}[ \t]+([A-Z]{4})/)
99
+ if e.include?('>>> ')
124
100
  # >>> RCPT TO:<******@ezweb.ne.jp>
125
- v['command'] = cv[1]
101
+ v['command'] = Sisimai::SMTP::Command.find(e) || ''
126
102
  else
127
103
  # Check error message
128
- if rxmessages.any? { |messages| messages.any? { |message| e =~ message } }
104
+ if rxmessages.any? { |messages| messages.any? { |message| e.include?(message) } }
129
105
  # Check with regular expressions of each error
130
106
  v['diagnosis'] ||= ''
131
107
  v['diagnosis'] << ' ' << e
@@ -149,7 +125,7 @@ module Sisimai::Lhost
149
125
  end
150
126
  e.delete('alterrors')
151
127
  end
152
- e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'])
128
+ e['diagnosis'] = Sisimai::String.sweep(e['diagnosis']) || ''
153
129
 
154
130
  if mhead['x-spasign'].to_s == 'NG'
155
131
  # Content-Type: text/plain; ..., X-SPASIGN: NG (spamghetti, au by EZweb)
@@ -157,17 +133,16 @@ module Sisimai::Lhost
157
133
  e['reason'] = 'filtered'
158
134
  else
159
135
  if e['command'] == 'RCPT'
160
- # set "userunknown" when the remote server rejected after RCPT
161
- # command.
136
+ # set "userunknown" when the remote server rejected after RCPT command.
162
137
  e['reason'] = 'userunknown'
163
138
  else
164
139
  # SMTP command is not RCPT
165
140
  catch :SESSION do
166
141
  ReFailures.each_key do |r|
167
- # Verify each regular expression of session errors
142
+ # Try to match with each session error message
168
143
  ReFailures[r].each do |rr|
169
- # Check each regular expression
170
- next unless e['diagnosis'] =~ rr
144
+ # Check each error message pattern
145
+ next unless e['diagnosis'].include?(rr)
171
146
  e['reason'] = r
172
147
  throw :SESSION
173
148
  end
@@ -181,7 +156,7 @@ module Sisimai::Lhost
181
156
  e['reason'] = 'userunknown'
182
157
  end
183
158
 
184
- return { 'ds' => dscontents, 'rfc822' => emailsteak[1] }
159
+ return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
185
160
  end
186
161
  def description; return 'au EZweb: http://www.au.kddi.com/mobile/'; end
187
162
  end
@@ -1,13 +1,12 @@
1
1
  module Sisimai::Lhost
2
- # Sisimai::Lhost::Facebook parses a bounce email which created by Facebook.
3
- # Methods in the module are called from only Sisimai::Message.
2
+ # Sisimai::Lhost::Facebook parses a bounce email which created by Facebook. Methods in the module
3
+ # are called from only Sisimai::Message.
4
4
  module Facebook
5
5
  class << self
6
- # Imported from p5-Sisimail/lib/Sisimai/Lhost/Facebook.pm
7
6
  require 'sisimai/lhost'
8
7
 
9
8
  Indicators = Sisimai::Lhost.INDICATORS
10
- ReBackbone = %r|^Content-Disposition:[ ]inline|.freeze
9
+ Boundaries = ['Content-Disposition: inline'].freeze
11
10
  StartingOf = { message: ['This message was created automatically by Facebook.'] }.freeze
12
11
  ReFailures = {
13
12
  # http://postmaster.facebook.com/response_codes
@@ -22,21 +21,20 @@ module Sisimai::Lhost
22
21
  'RCP-P2', # The attempted recipient's preferences prevent messages from being delivered.
23
22
  'RCP-P3', # The attempted recipient's privacy settings blocked the delivery.
24
23
  ],
25
- 'blocked' => [
26
- 'POL-P1', # Your mail server's IP Address is listed on the Spamhaus PBL.
27
- 'POL-P2', # Facebook will no longer accept mail from your mail server's IP Address.
28
- ],
29
24
  'mesgtoobig' => [
30
25
  'MSG-P1', # The message exceeds Facebook's maximum allowed size.
31
26
  'INT-P2', # The message exceeds Facebook's maximum allowed size.
32
27
  ],
33
28
  'contenterror' => [
34
29
  'MSG-P2', # The message contains an attachment type that Facebook does not accept.
35
- 'MSG-P3', # The message contains multiple instances of a header field that can only be present once.
30
+ 'MSG-P3', # The message contains multiple instances of a header field that can only be present once. Please see RFC 5322, section 3.6 for more information
36
31
  'POL-P6', # The message contains a url that has been blocked by Facebook.
37
32
  'POL-P7', # The message does not comply with Facebook's abuse policies and will not be accepted.
38
33
  ],
39
34
  'securityerror' => [
35
+ 'POL-P1', # Your mail server's IP Address is listed on the Spamhaus PBL.
36
+ 'POL-P2', # Facebook will no longer accept mail from your mail server's IP Address.
37
+ 'POL-P5', # The message contains a virus.
40
38
  'POL-P7', # The message does not comply with Facebook's Domain Authentication requirements.
41
39
  ],
42
40
  'notaccept' => [
@@ -55,20 +53,17 @@ module Sisimai::Lhost
55
53
  ],
56
54
  'systemerror' => [
57
55
  'CON-T1', # Facebook's mail server currently has too many connections open to allow another one.
58
- 'RCP-T1', # The attempted recipient address is not currently available due to an internal system issue. This is a temporary condition.
59
- ],
60
- 'virusdetected' => [
61
- 'POL-P5', # The message contains a virus.
62
56
  ],
63
57
  'toomanyconn' => [
64
- 'CON-T2', # Your mail server currently has too many connections open to Facebook's mail servers.
65
58
  'CON-T3', # Your mail server has opened too many new connections to Facebook's mail servers in a short period of time.
66
59
  ],
67
60
  'suspend' => [
68
61
  'RCP-T4', # The attempted recipient address is currently deactivated. The user may or may not reactivate it.
69
62
  ],
70
63
  'undefined' => [
64
+ 'RCP-T1', # The attempted recipient address is not currently available due to an internal system issue. This is a temporary condition.
71
65
  'MSG-T1', # The number of recipients on the message exceeds Facebook's allowed maximum.
66
+ 'CON-T2', # Your mail server currently has too many connections open to Facebook's mail servers.
72
67
  'CON-T4', # Your mail server has exceeded the maximum number of recipients for its current connection.
73
68
  ],
74
69
  }.freeze
@@ -78,17 +73,16 @@ module Sisimai::Lhost
78
73
  # @param [String] mbody Message body of a bounce email
79
74
  # @return [Hash] Bounce data list and message/rfc822 part
80
75
  # @return [Nil] it failed to parse or the arguments are missing
81
- def make(mhead, mbody)
76
+ def inquire(mhead, mbody)
82
77
  return nil unless mhead['from'] == 'Facebook <mailer-daemon@mx.facebook.com>'
83
78
  return nil unless mhead['subject'] == 'Sorry, your message could not be delivered'
84
79
 
85
- require 'sisimai/rfc1894'
86
80
  fieldtable = Sisimai::RFC1894.FIELDTABLE
87
81
  permessage = {} # (Hash) Store values of each Per-Message field
88
82
 
89
83
  dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
90
- emailsteak = Sisimai::RFC5322.fillet(mbody, ReBackbone)
91
- bodyslices = emailsteak[0].split("\n")
84
+ emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
85
+ bodyslices = emailparts[0].split("\n")
92
86
  readslices = ['']
93
87
  readcursor = 0 # (Integer) Points the current cursor position
94
88
  recipients = 0 # (Integer) The number of 'Final-Recipient' header
@@ -96,8 +90,8 @@ module Sisimai::Lhost
96
90
  v = nil
97
91
 
98
92
  while e = bodyslices.shift do
99
- # Read error messages and delivery status lines from the head of the email
100
- # to the previous line of the beginning of the original message.
93
+ # Read error messages and delivery status lines from the head of the email to the previous
94
+ # line of the beginning of the original message.
101
95
  readslices << e # Save the current line for the next loop
102
96
 
103
97
  if readcursor == 0
@@ -138,14 +132,14 @@ module Sisimai::Lhost
138
132
  next unless fieldtable[o[0]]
139
133
  v[fieldtable[o[0]]] = o[2]
140
134
 
141
- next unless f == 1
135
+ next unless f
142
136
  permessage[fieldtable[o[0]]] = o[2]
143
137
  end
144
138
  else
145
139
  # Continued line of the value of Diagnostic-Code field
146
140
  next unless readslices[-2].start_with?('Diagnostic-Code:')
147
- next unless cv = e.match(/\A[ \t]+(.+)\z/)
148
- v['diagnosis'] << ' ' << cv[1]
141
+ next unless e.start_with?(' ')
142
+ v['diagnosis'] << ' ' << e[e.rindex(' ') + 1, e.size]
149
143
  readslices[-1] = 'Diagnostic-Code: ' << e
150
144
  end
151
145
  end
@@ -155,14 +149,8 @@ module Sisimai::Lhost
155
149
  e['lhost'] ||= permessage['lhost']
156
150
  e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'])
157
151
 
158
- if cv = e['diagnosis'].match(/\b([A-Z]{3})[-]([A-Z])(\d)\b/)
159
- # Diagnostic-Code: smtp; 550 5.1.1 RCP-P2
160
- lhs = cv[1]
161
- rhs = cv[2]
162
- num = cv[3]
163
-
164
- fbresponse = sprintf('%s-%s%d', lhs, rhs, num)
165
- end
152
+ p0 = e['diagnosis'].index('-') || -1
153
+ fbresponse = e['diagnosis'][p0 - 3, 6] if p0 > 0
166
154
 
167
155
  catch :SESSION do
168
156
  ReFailures.each_key do |r|
@@ -188,11 +176,11 @@ module Sisimai::Lhost
188
176
  # https://groups.google.com/forum/#!topic/cdmix/eXfi4ddgYLQ
189
177
  # This block has not been tested because we have no email sample
190
178
  # including "INT-T?" error code.
191
- next unless fbresponse =~ /\AINT-T\d+\z/
179
+ next unless fbresponse.start_with?('INT-T')
192
180
  e['reason'] = 'systemerror'
193
181
  end
194
182
 
195
- return { 'ds' => dscontents, 'rfc822' => emailsteak[1] }
183
+ return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
196
184
  end
197
185
  def description; return 'Facebook: https://www.facebook.com'; end
198
186
  end
@@ -1,48 +1,41 @@
1
1
  module Sisimai::Lhost
2
- # Sisimai::Lhost::FML parses a bounce email which created by fml.
3
- # Methods in the module are called from only Sisimai::Message.
2
+ # Sisimai::Lhost::FML parses a bounce email which created by fml. Methods in the module are called
3
+ # from only Sisimai::Message.
4
4
  module FML
5
5
  class << self
6
- # Imported from p5-Sisimail/lib/Sisimai/Lhost/FML.pm
7
6
  require 'sisimai/lhost'
8
7
 
9
8
  Indicators = Sisimai::Lhost.INDICATORS
10
- ReBackbone = %r|^Original[ ]mail[ ]as[ ]follows:|.freeze
9
+ Boundaries = ['Original mail as follows:'].freeze
11
10
  ErrorTitle = {
12
- 'rejected' => %r{(?>
13
- (?:Ignored[ ])*NOT[ ]MEMBER[ ]article[ ]from[ ]
14
- |reject[ ]mail[ ](?:.+:|from)[ ],
15
- |Spam[ ]mail[ ]from[ ]a[ ]spammer[ ]is[ ]rejected
16
- |You[ ].+[ ]are[ ]not[ ]member
17
- )
18
- }x,
19
- 'systemerror' => %r{(?:
20
- fml[ ]system[ ]error[ ]message
21
- |Loop[ ]Alert:[ ]
22
- |Loop[ ]Back[ ]Warning:[ ]
23
- |WARNING:[ ]UNIX[ ]FROM[ ]Loop
24
- )
25
- }x,
26
- 'securityerror' => %r/Security Alert/,
11
+ 'rejected' => [
12
+ ' are not member',
13
+ 'NOT MEMBER article from ',
14
+ 'reject mail ',
15
+ 'Spam mail from a spammer is rejected',
16
+ ],
17
+ 'systemerror' => [
18
+ 'fml system error message',
19
+ 'Loop Alert: ',
20
+ 'Loop Back Warning: ',
21
+ 'WARNING: UNIX FROM Loop',
22
+ ],
23
+ 'securityerror' => ['Security Alert'],
27
24
  }.freeze
28
25
  ErrorTable = {
29
- 'rejected' => %r{(?>
30
- (?:Ignored[ ])*NOT[ ]MEMBER[ ]article[ ]from[ ]
31
- |reject[ ](?:
32
- mail[ ]from[ ].+[@].+
33
- |since[ ].+[ ]header[ ]may[ ]cause[ ]mail[ ]loop
34
- |spammers:
35
- )
36
- |You[ ]are[ ]not[ ]a[ ]member[ ]of[ ]this[ ]mailing[ ]list
37
- )
38
- }x,
39
- 'systemerror' => %r{(?:
40
- Duplicated[ ]Message-ID
41
- |fml[ ].+[ ]has[ ]detected[ ]a[ ]loop[ ]condition[ ]so[ ]that
42
- |Loop[ ]Back[ ]Warning:
43
- )
44
- }x,
45
- 'securityerror' => %r/Security alert:/,
26
+ 'rejected' => [
27
+ ' header may cause mail loop',
28
+ 'NOT MEMBER article from ',
29
+ 'reject mail from ',
30
+ 'reject spammers:',
31
+ 'You are not a member of this mailing list',
32
+ ],
33
+ 'systemerror' => [
34
+ ' has detected a loop condition so that',
35
+ 'Duplicated Message-ID',
36
+ 'Loop Back Warning:',
37
+ ],
38
+ 'securityerror' => ['Security alert:'],
46
39
  }.freeze
47
40
 
48
41
  # Parse bounce messages from fml mailling list server/manager
@@ -51,34 +44,36 @@ module Sisimai::Lhost
51
44
  # @return [Hash] Bounce data list and message/rfc822 part
52
45
  # @return [Nil] it failed to parse or the arguments are missing
53
46
  # @since v4.22.3
54
- def make(mhead, mbody)
47
+ def inquire(mhead, mbody)
55
48
  return nil unless mhead['x-mlserver']
56
- return nil unless mhead['from'] =~ /.+[-]admin[@].+/
57
- return nil unless mhead['message-id'] =~ /\A[<]\d+[.]FML.+[@].+[>]\z/
49
+ return nil unless mhead['from'].include?('-admin@')
50
+ return nil unless mhead['message-id'].index('.FML') > 1
58
51
 
59
52
  dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
60
- emailsteak = Sisimai::RFC5322.fillet(mbody, ReBackbone)
61
- bodyslices = emailsteak[0].split("\n")
53
+ emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
54
+ bodyslices = emailparts[0].split("\n")
62
55
  recipients = 0 # (Integer) The number of 'Final-Recipient' header
63
56
  v = nil
64
57
 
65
58
  while e = bodyslices.shift do
66
- # Read error messages and delivery status lines from the head of the email
67
- # to the previous line of the beginning of the original message.
59
+ # Read error messages and delivery status lines from the head of the email to the previous
60
+ # line of the beginning of the original message.
68
61
  next if e.empty?
69
62
 
70
63
  # Duplicated Message-ID in <2ndml@example.com>.
71
64
  # Original mail as follows:
72
65
  v = dscontents[-1]
73
66
 
74
- if cv = e.match(/[<]([^ ]+?[@][^ ]+?)[>][.]\z/)
75
- # Duplicated Message-ID in <2ndml@example.com>.
67
+ p1 = e.index('<') || -1
68
+ p2 = e.rindex('>') || -1
69
+ if p1 > 0 && p2 > 0
70
+ # You are not a member of this mailing list <neko-nyaan@example.org>.
76
71
  if v['recipient']
77
72
  # There are multiple recipient addresses in the message body.
78
73
  dscontents << Sisimai::Lhost.DELIVERYSTATUS
79
74
  v = dscontents[-1]
80
75
  end
81
- v['recipient'] = cv[1]
76
+ v['recipient'] = e[p1 + 1, p2 - p1 - 1]
82
77
  v['diagnosis'] = e
83
78
  recipients += 1
84
79
  else
@@ -94,7 +89,7 @@ module Sisimai::Lhost
94
89
  e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'])
95
90
  ErrorTable.each_key do |f|
96
91
  # Try to match with error messages defined in ErrorTable
97
- next unless e['diagnosis'] =~ ErrorTable[f]
92
+ next unless ErrorTable[f].any? { |a| e['diagnosis'].include?(a) }
98
93
  e['reason'] = f
99
94
  break
100
95
  end
@@ -110,7 +105,7 @@ module Sisimai::Lhost
110
105
  end
111
106
  end
112
107
 
113
- return { 'ds' => dscontents, 'rfc822' => emailsteak[1] }
108
+ return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
114
109
  end
115
110
  def description; return 'fml mailing list server/manager'; end
116
111
  end
@@ -1,18 +1,16 @@
1
1
  module Sisimai::Lhost
2
- # Sisimai::Lhost::Gmail parses a bounce email which created by Gmail.
3
- # Methods in the module are called from only Sisimai::Message.
2
+ # Sisimai::Lhost::Gmail parses a bounce email which created by Gmail. Methods in the module are
3
+ # called from only Sisimai::Message.
4
4
  module Gmail
5
5
  class << self
6
- # Imported from p5-Sisimail/lib/Sisimai/Lhost/Gmail.pm
7
6
  require 'sisimai/lhost'
8
7
 
9
8
  Indicators = Sisimai::Lhost.INDICATORS
10
- ReBackbone = %r/^[ ]*-----[ ](?:Original[ ]message|Message[ ]header[ ]follows)[ ]-----/.freeze
9
+ Boundaries = ['----- Original message -----', '----- Message header follows -----'].freeze
11
10
  StartingOf = {
12
11
  message: ['Delivery to the following recipient'],
13
12
  error: ['The error that the other server returned was:'],
14
13
  }.freeze
15
- MarkingsOf = { start: %r/Technical details of (?:permanent|temporary) failure:/ }.freeze
16
14
  MessagesOf = {
17
15
  'expired' => [
18
16
  'DNS Error: Could not contact DNS servers',
@@ -103,7 +101,7 @@ module Sisimai::Lhost
103
101
  # @param [String] mbody Message body of a bounce email
104
102
  # @return [Hash] Bounce data list and message/rfc822 part
105
103
  # @return [Nil] it failed to parse or the arguments are missing
106
- def make(mhead, mbody)
104
+ def inquire(mhead, mbody)
107
105
  # From: Mail Delivery Subsystem <mailer-daemon@googlemail.com>
108
106
  # Received: from vw-in-f109.1e100.net [74.125.113.109] by ...
109
107
  #
@@ -154,16 +152,15 @@ module Sisimai::Lhost
154
152
  return nil unless mhead['subject'].start_with?('Delivery Status Notification')
155
153
 
156
154
  dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
157
- emailsteak = Sisimai::RFC5322.fillet(mbody, ReBackbone)
158
- bodyslices = emailsteak[0].split("\n")
155
+ emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
156
+ bodyslices = emailparts[0].split("\n")
159
157
  readcursor = 0 # (Integer) Points the current cursor position
160
158
  recipients = 0 # (Integer) The number of 'Final-Recipient' header
161
- statecode0 = 0 # (Integer) The value of (state *) in the error message
162
159
  v = nil
163
160
 
164
161
  while e = bodyslices.shift do
165
- # Read error messages and delivery status lines from the head of the email
166
- # to the previous line of the beginning of the original message.
162
+ # Read error messages and delivery status lines from the head of the email to the previous
163
+ # line of the beginning of the original message.
167
164
  if readcursor == 0
168
165
  # Beginning of the bounce message or delivery status part
169
166
  readcursor |= Indicators[:deliverystatus] if e.start_with?(StartingOf[:message][0])
@@ -188,7 +185,7 @@ module Sisimai::Lhost
188
185
  #
189
186
  v = dscontents[-1]
190
187
 
191
- if cv = e.match(/\A[ \t]+([^ ]+[@][^ ]+)\z/)
188
+ if e.start_with?(' ') && e.include?('@')
192
189
  # kijitora@example.jp: 550 5.2.2 <kijitora@example>... Mailbox Full
193
190
  if v['recipient']
194
191
  # There are multiple recipient addresses in the message body.
@@ -196,8 +193,8 @@ module Sisimai::Lhost
196
193
  v = dscontents[-1]
197
194
  end
198
195
 
199
- r = Sisimai::Address.s3s4(cv[1])
200
- next unless Sisimai::RFC5322.is_emailaddress(r)
196
+ r = Sisimai::Address.s3s4(e[e.rindex(' ') + 1, e.size])
197
+ next unless Sisimai::Address.is_emailaddress(r)
201
198
  v['recipient'] = r
202
199
  recipients += 1
203
200
  else
@@ -212,22 +209,24 @@ module Sisimai::Lhost
212
209
 
213
210
  unless e['rhost']
214
211
  # Get the value of remote host
215
- if cv = e['diagnosis'].match(/[ \t]+by[ \t]+([^ ]+)[.][ \t]+\[(\d+[.]\d+[.]\d+[.]\d+)\][.]/)
216
- # Google tried to deliver your message, but it was rejected by
217
- # the server for the recipient domain example.jp by mx.example.jp. [192.0.2.153].
218
- hostname = cv[1]
219
- ipv4addr = cv[2]
220
- e['rhost'] = if hostname =~ /[-0-9a-zA-Z]+[.][a-zA-Z]+\z/
221
- # Maybe valid hostname
222
- hostname.downcase
223
- else
224
- # Use IP address instead
225
- ipv4addr
226
- end
212
+ if Sisimai::String.aligned(e['diagnosis'], [' by ', '. [', ']. '])
213
+ # Google tried to deliver your message, but it was rejected by the server for the recipient
214
+ # domain example.jp by mx.example.jp. [192.0.2.153].
215
+ p1 = e['diagnosis'].rindex(' by ') || -1
216
+ p2 = e['diagnosis'].rindex('. [' ) || -1
217
+ hostname = e['diagnosis'][p1 + 4, p2 - p1 - 4]
218
+ ipv4addr = e['diagnosis'][p2 + 3, e['diagnosis'].rindex(']. ') - p2 - 3]
219
+ lastchar = hostname[-1, 1].upcase.ord
220
+
221
+ e['rhost'] = hostname if lastchar > 64 && lastchar < 91
222
+ e['rhost'] ||= ipv4addr
227
223
  end
228
224
  end
229
225
 
230
- if cv = e['diagnosis'].match(/[(]state[ ](\d+)[)][.]/) then statecode0 = cv[1] end
226
+ p1 = e['diagnosis'].rindex(' ') || -1
227
+ p2 = e['diagnosis'].rindex(')') || -1
228
+ statecode0 = e['diagnosis'][p1 + 1, p2 - p1 - 1] || 0
229
+
231
230
  if StateTable[statecode0]
232
231
  # (state *)
233
232
  e['reason'] = StateTable[statecode0]['reason']
@@ -245,10 +244,11 @@ module Sisimai::Lhost
245
244
 
246
245
  # Set pseudo status code
247
246
  e['status'] = Sisimai::SMTP::Status.find(e['diagnosis']) || ''
248
- e['reason'] = Sisimai::SMTP::Status.name(e['status']).to_s if e['status'] =~ /\A[45][.][1-7][.][1-9]\z/
247
+ next if e['status'].size == 0 || e['status'].include?('.0')
248
+ e['reason'] = Sisimai::SMTP::Status.name(e['status']).to_s || ''
249
249
  end
250
250
 
251
- return { 'ds' => dscontents, 'rfc822' => emailsteak[1] }
251
+ return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
252
252
  end
253
253
  def description; return 'Gmail: https://mail.google.com'; end
254
254
  end