sisimai 4.25.17 → 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (178) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +3 -3
  3. data/ANALYTICAL-PRECISION +2 -2
  4. data/Benchmarks.mk +3 -3
  5. data/CONTRIBUTING +1 -1
  6. data/ChangeLog.md +406 -407
  7. data/Developers.mk +5 -6
  8. data/Gemfile +1 -1
  9. data/Makefile +12 -12
  10. data/README-JA.md +142 -94
  11. data/README.md +282 -150
  12. data/Rakefile +9 -3
  13. data/Repository.mk +2 -3
  14. data/lib/sisimai/address.rb +118 -74
  15. data/lib/sisimai/arf.rb +84 -82
  16. data/lib/sisimai/datetime.rb +5 -52
  17. data/lib/sisimai/{data → fact}/json.rb +7 -9
  18. data/lib/sisimai/fact/yaml.rb +31 -0
  19. data/lib/sisimai/fact.rb +468 -0
  20. data/lib/sisimai/lhost/activehunter.rb +12 -14
  21. data/lib/sisimai/lhost/amavis.rb +11 -14
  22. data/lib/sisimai/lhost/amazonses.rb +37 -41
  23. data/lib/sisimai/lhost/amazonworkmail.rb +15 -18
  24. data/lib/sisimai/lhost/aol.rb +12 -14
  25. data/lib/sisimai/lhost/apachejames.rb +19 -21
  26. data/lib/sisimai/lhost/barracuda.rb +10 -12
  27. data/lib/sisimai/lhost/bigfoot.rb +21 -21
  28. data/lib/sisimai/lhost/biglobe.rb +15 -16
  29. data/lib/sisimai/lhost/courier.rb +20 -20
  30. data/lib/sisimai/lhost/domino.rb +23 -19
  31. data/lib/sisimai/lhost/einsundeins.rb +20 -16
  32. data/lib/sisimai/lhost/exchange2003.rb +30 -29
  33. data/lib/sisimai/lhost/exchange2007.rb +70 -58
  34. data/lib/sisimai/lhost/exim.rb +175 -161
  35. data/lib/sisimai/lhost/ezweb.rb +31 -56
  36. data/lib/sisimai/lhost/facebook.rb +21 -33
  37. data/lib/sisimai/lhost/fml.rb +43 -48
  38. data/lib/sisimai/lhost/gmail.rb +29 -29
  39. data/lib/sisimai/lhost/gmx.rb +18 -17
  40. data/lib/sisimai/lhost/googlegroups.rb +9 -10
  41. data/lib/sisimai/lhost/gsuite.rb +21 -27
  42. data/lib/sisimai/lhost/imailserver.rb +25 -39
  43. data/lib/sisimai/lhost/interscanmss.rb +28 -31
  44. data/lib/sisimai/lhost/kddi.rb +22 -28
  45. data/lib/sisimai/lhost/mailfoundry.rb +11 -12
  46. data/lib/sisimai/lhost/mailmarshalsmtp.rb +25 -29
  47. data/lib/sisimai/lhost/mailru.rb +33 -27
  48. data/lib/sisimai/lhost/mcafee.rb +21 -31
  49. data/lib/sisimai/lhost/messagelabs.rb +17 -20
  50. data/lib/sisimai/lhost/messagingserver.rb +40 -37
  51. data/lib/sisimai/lhost/mfilter.rb +15 -16
  52. data/lib/sisimai/lhost/mxlogic.rb +24 -23
  53. data/lib/sisimai/lhost/notes.rb +17 -17
  54. data/lib/sisimai/lhost/office365.rb +63 -27
  55. data/lib/sisimai/lhost/opensmtpd.rb +12 -13
  56. data/lib/sisimai/lhost/outlook.rb +12 -15
  57. data/lib/sisimai/lhost/postfix.rb +179 -129
  58. data/lib/sisimai/lhost/powermta.rb +12 -14
  59. data/lib/sisimai/lhost/qmail.rb +44 -47
  60. data/lib/sisimai/lhost/receivingses.rb +15 -20
  61. data/lib/sisimai/lhost/sendgrid.rb +34 -32
  62. data/lib/sisimai/lhost/sendmail.rb +66 -53
  63. data/lib/sisimai/lhost/surfcontrol.rb +19 -19
  64. data/lib/sisimai/lhost/v5sendmail.rb +45 -39
  65. data/lib/sisimai/lhost/verizon.rb +35 -39
  66. data/lib/sisimai/lhost/x1.rb +18 -17
  67. data/lib/sisimai/lhost/x2.rb +17 -14
  68. data/lib/sisimai/lhost/x3.rb +19 -19
  69. data/lib/sisimai/lhost/x4.rb +72 -57
  70. data/lib/sisimai/lhost/x5.rb +17 -19
  71. data/lib/sisimai/lhost/x6.rb +41 -17
  72. data/lib/sisimai/lhost/yahoo.rb +17 -16
  73. data/lib/sisimai/lhost/yandex.rb +16 -20
  74. data/lib/sisimai/lhost/zoho.rb +16 -15
  75. data/lib/sisimai/lhost.rb +8 -10
  76. data/lib/sisimai/mail/maildir.rb +1 -3
  77. data/lib/sisimai/mail/mbox.rb +3 -4
  78. data/lib/sisimai/mail/memory.rb +0 -1
  79. data/lib/sisimai/mail/stdin.rb +1 -3
  80. data/lib/sisimai/mail.rb +3 -7
  81. data/lib/sisimai/mda.rb +28 -42
  82. data/lib/sisimai/message.rb +435 -325
  83. data/lib/sisimai/order.rb +5 -5
  84. data/lib/sisimai/reason/authfailure.rb +64 -0
  85. data/lib/sisimai/reason/badreputation.rb +53 -0
  86. data/lib/sisimai/reason/blocked.rb +94 -160
  87. data/lib/sisimai/reason/contenterror.rb +8 -9
  88. data/lib/sisimai/reason/delivered.rb +4 -6
  89. data/lib/sisimai/reason/exceedlimit.rb +10 -12
  90. data/lib/sisimai/reason/expired.rb +6 -8
  91. data/lib/sisimai/reason/feedback.rb +2 -3
  92. data/lib/sisimai/reason/filtered.rb +17 -19
  93. data/lib/sisimai/reason/hasmoved.rb +9 -10
  94. data/lib/sisimai/reason/hostunknown.rb +15 -15
  95. data/lib/sisimai/reason/mailboxfull.rb +10 -12
  96. data/lib/sisimai/reason/mailererror.rb +18 -20
  97. data/lib/sisimai/reason/mesgtoobig.rb +9 -11
  98. data/lib/sisimai/reason/networkerror.rb +5 -8
  99. data/lib/sisimai/reason/norelaying.rb +8 -11
  100. data/lib/sisimai/reason/notaccept.rb +13 -14
  101. data/lib/sisimai/reason/notcompliantrfc.rb +43 -0
  102. data/lib/sisimai/reason/onhold.rb +6 -9
  103. data/lib/sisimai/reason/policyviolation.rb +14 -12
  104. data/lib/sisimai/reason/rejected.rb +26 -24
  105. data/lib/sisimai/reason/requireptr.rb +69 -0
  106. data/lib/sisimai/reason/securityerror.rb +33 -36
  107. data/lib/sisimai/reason/spamdetected.rb +114 -147
  108. data/lib/sisimai/reason/speeding.rb +49 -0
  109. data/lib/sisimai/reason/suspend.rb +11 -11
  110. data/lib/sisimai/reason/syntaxerror.rb +11 -10
  111. data/lib/sisimai/reason/systemerror.rb +7 -9
  112. data/lib/sisimai/reason/systemfull.rb +7 -8
  113. data/lib/sisimai/reason/toomanyconn.rb +9 -11
  114. data/lib/sisimai/reason/undefined.rb +2 -3
  115. data/lib/sisimai/reason/userunknown.rb +129 -146
  116. data/lib/sisimai/reason/vacation.rb +3 -4
  117. data/lib/sisimai/reason/virusdetected.rb +10 -11
  118. data/lib/sisimai/reason.rb +59 -64
  119. data/lib/sisimai/rfc1894.rb +55 -28
  120. data/lib/sisimai/rfc2045.rb +373 -0
  121. data/lib/sisimai/rfc3464.rb +250 -308
  122. data/lib/sisimai/rfc3834.rb +42 -45
  123. data/lib/sisimai/rfc5322.rb +75 -100
  124. data/lib/sisimai/rfc5965.rb +31 -0
  125. data/lib/sisimai/rhost/cox.rb +5 -6
  126. data/lib/sisimai/rhost/franceptt.rb +6 -8
  127. data/lib/sisimai/rhost/godaddy.rb +12 -12
  128. data/lib/sisimai/rhost/{googleapps.rb → google.rb} +80 -72
  129. data/lib/sisimai/rhost/iua.rb +9 -10
  130. data/lib/sisimai/rhost/kddi.rb +6 -8
  131. data/lib/sisimai/rhost/{exchangeonline.rb → microsoft.rb} +115 -114
  132. data/lib/sisimai/rhost/mimecast.rb +42 -40
  133. data/lib/sisimai/rhost/nttdocomo.rb +13 -18
  134. data/lib/sisimai/rhost/spectrum.rb +10 -12
  135. data/lib/sisimai/rhost/{tencentqq.rb → tencent.rb} +7 -8
  136. data/lib/sisimai/rhost.rb +23 -31
  137. data/lib/sisimai/smtp/command.rb +59 -0
  138. data/lib/sisimai/smtp/error.rb +4 -7
  139. data/lib/sisimai/smtp/reply.rb +161 -74
  140. data/lib/sisimai/smtp/status.rb +504 -393
  141. data/lib/sisimai/smtp/transcript.rb +124 -0
  142. data/lib/sisimai/smtp.rb +0 -1
  143. data/lib/sisimai/string.rb +74 -5
  144. data/lib/sisimai/time.rb +1 -2
  145. data/lib/sisimai/version.rb +1 -1
  146. data/lib/sisimai.rb +35 -21
  147. data/set-of-emails/maildir/bsd/lhost-domino-02.eml +6 -3
  148. data/set-of-emails/maildir/bsd/lhost-googlegroups-15.eml +174 -0
  149. data/set-of-emails/maildir/bsd/lhost-gsuite-15.eml +229 -0
  150. data/set-of-emails/maildir/bsd/lhost-postfix-75.eml +51 -0
  151. data/set-of-emails/maildir/bsd/lhost-postfix-76.eml +101 -0
  152. data/set-of-emails/maildir/bsd/lhost-postfix-77.eml +74 -0
  153. data/set-of-emails/maildir/bsd/lhost-postfix-78.eml +91 -0
  154. data/set-of-emails/maildir/bsd/lhost-receivingses-08.eml +88 -0
  155. data/set-of-emails/maildir/bsd/rfc3464-43.eml +88 -0
  156. data/set-of-emails/maildir/bsd/rhost-google-03.eml +101 -0
  157. data/set-of-emails/maildir/bsd/rhost-google-04.eml +102 -0
  158. data/set-of-emails/maildir/bsd/rhost-google-05.eml +82 -0
  159. data/set-of-emails/maildir/bsd/rhost-google-06.eml +102 -0
  160. data/set-of-emails/maildir/bsd/rhost-google-07.eml +69 -0
  161. data/set-of-emails/maildir/bsd/rhost-google-08.eml +99 -0
  162. data/sisimai-java.gemspec +1 -1
  163. data/sisimai.gemspec +1 -1
  164. metadata +41 -21
  165. data/.rspec +0 -2
  166. data/lib/sisimai/data/yaml.rb +0 -33
  167. data/lib/sisimai/data.rb +0 -411
  168. data/lib/sisimai/mime.rb +0 -456
  169. data/set-of-emails/maildir/mac/reported-from-nick4tech-san-01.eml +0 -6
  170. /data/set-of-emails/maildir/bsd/{rfc3464-41.eml → rfc3834-05.eml} +0 -0
  171. /data/set-of-emails/maildir/bsd/{rhost-googleapps-01.eml → rhost-google-01.eml} +0 -0
  172. /data/set-of-emails/maildir/bsd/{rhost-googleapps-02.eml → rhost-google-02.eml} +0 -0
  173. /data/set-of-emails/maildir/bsd/{rhost-exchangeonline-01.eml → rhost-microsoft-01.eml} +0 -0
  174. /data/set-of-emails/maildir/bsd/{rhost-exchangeonline-02.eml → rhost-microsoft-02.eml} +0 -0
  175. /data/set-of-emails/maildir/bsd/{rhost-exchangeonline-03.eml → rhost-microsoft-03.eml} +0 -0
  176. /data/set-of-emails/maildir/bsd/{rhost-tencentqq-01.eml → rhost-tencent-01.eml} +0 -0
  177. /data/set-of-emails/maildir/bsd/{rhost-tencentqq-02.eml → rhost-tencent-02.eml} +0 -0
  178. /data/set-of-emails/maildir/bsd/{rhost-tencentqq-03.eml → rhost-tencent-03.eml} +0 -0
@@ -1,13 +1,12 @@
1
1
  module Sisimai::Lhost
2
- # Sisimai::Lhost::Yandex parses a bounce email which created by Yandex.Mail.
3
- # Methods in the module are called from only Sisimai::Message.
2
+ # Sisimai::Lhost::Yandex parses a bounce email which created by Yandex.Mail. Methods in the module
3
+ # are called from only Sisimai::Message.
4
4
  module Yandex
5
5
  class << self
6
- # Imported from p5-Sisimail/lib/Sisimai/Lhost/Yandex.pm
7
6
  require 'sisimai/lhost'
8
7
 
9
8
  Indicators = Sisimai::Lhost.INDICATORS
10
- ReBackbone = %r|^Content-Type:[ ]message/rfc822|.freeze
9
+ Boundaries = ['Content-Type: message/rfc822'].freeze
11
10
  StartingOf = { message: ['This is the mail system at host yandex.ru.'] }.freeze
12
11
 
13
12
  # Parse bounce messages from Yandex.Mail
@@ -15,7 +14,7 @@ module Sisimai::Lhost
15
14
  # @param [String] mbody Message body of a bounce email
16
15
  # @return [Hash] Bounce data list and message/rfc822 part
17
16
  # @return [Nil] it failed to parse or the arguments are missing
18
- def make(mhead, mbody)
17
+ def inquire(mhead, mbody)
19
18
  # X-Yandex-Front: mxback1h.mail.yandex.net
20
19
  # X-Yandex-TimeMark: 1417885948
21
20
  # X-Yandex-Uniq: 92309766-f1c8-4bd4-92bc-657c75766587
@@ -26,13 +25,12 @@ module Sisimai::Lhost
26
25
  return nil unless mhead['x-yandex-uniq']
27
26
  return nil unless mhead['from'] == 'mailer-daemon@yandex.ru'
28
27
 
29
- require 'sisimai/rfc1894'
30
28
  fieldtable = Sisimai::RFC1894.FIELDTABLE
31
29
  permessage = {} # (Hash) Store values of each Per-Message field
32
30
 
33
31
  dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
34
- emailsteak = Sisimai::RFC5322.fillet(mbody, ReBackbone)
35
- bodyslices = emailsteak[0].split("\n")
32
+ emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
33
+ bodyslices = emailparts[0].split("\n")
36
34
  readslices = ['']
37
35
  readcursor = 0 # (Integer) Points the current cursor position
38
36
  recipients = 0 # (Integer) The number of 'Final-Recipient' header
@@ -40,8 +38,8 @@ module Sisimai::Lhost
40
38
  v = nil
41
39
 
42
40
  while e = bodyslices.shift do
43
- # Read error messages and delivery status lines from the head of the email
44
- # to the previous line of the beginning of the original message.
41
+ # Read error messages and delivery status lines from the head of the email to the previous
42
+ # line of the beginning of the original message.
45
43
  readslices << e # Save the current line for the next loop
46
44
 
47
45
  if readcursor == 0
@@ -82,23 +80,21 @@ module Sisimai::Lhost
82
80
  next unless fieldtable[o[0]]
83
81
  v[fieldtable[o[0]]] = o[2]
84
82
 
85
- next unless f == 1
83
+ next unless f
86
84
  permessage[fieldtable[o[0]]] = o[2]
87
85
  end
88
86
  else
89
87
  # The line does not begin with a DSN field defined in RFC3464
90
- if cv = e.match(/[ \t][(]in reply to .*([A-Z]{4}).*/)
88
+ if e.include?(' (in reply to ') || e.include?('command)')
91
89
  # 5.1.1 <userunknown@example.co.jp>... User Unknown (in reply to RCPT TO
92
- commandset << cv[1]
90
+ cv = Sisimai::SMTP::Command.find(e)
91
+ commandset << cv if cv
93
92
 
94
- elsif cv = e.match(/([A-Z]{4})[ \t]*.*command[)]\z/)
95
- # to MAIL command)
96
- commandset << cv[1]
97
93
  else
98
94
  # Continued line of the value of Diagnostic-Code field
99
95
  next unless readslices[-2].start_with?('Diagnostic-Code:')
100
- next unless cv = e.match(/\A[ \t]+(.+)\z/)
101
- v['diagnosis'] << ' ' << cv[1]
96
+ next unless e.start_with?(' ')
97
+ v['diagnosis'] << ' ' << Sisimai::String.sweep(e)
102
98
  readslices[-1] = 'Diagnostic-Code: ' << e
103
99
  end
104
100
  end
@@ -110,11 +106,11 @@ module Sisimai::Lhost
110
106
  e['lhost'] ||= permessage['rhost']
111
107
  permessage.each_key { |a| e[a] ||= permessage[a] || '' }
112
108
 
113
- e['command'] = commandset.shift || ''
114
109
  e['diagnosis'] = Sisimai::String.sweep(e['diagnosis'].tr("\n", ' '))
110
+ e['command'] ||= commandset.shift || Sisimai::SMTP::Command.find(e['diagnosis']) || ''
115
111
  end
116
112
 
117
- return { 'ds' => dscontents, 'rfc822' => emailsteak[1] }
113
+ return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
118
114
  end
119
115
  def description; return 'Yandex.Mail: https://www.yandex.ru'; end
120
116
  end
@@ -1,13 +1,12 @@
1
1
  module Sisimai::Lhost
2
- # Sisimai::Lhost::Zoho parses a bounce email which created by Zoho Mail.
3
- # Methods in the module are called from only Sisimai::Message.
2
+ # Sisimai::Lhost::Zoho parses a bounce email which created by Zoho Mail. Methods in the module are
3
+ # called from only Sisimai::Message.
4
4
  module Zoho
5
5
  class << self
6
- # Imported from p5-Sisimail/lib/Sisimai/Lhost/Zoho.pm
7
6
  require 'sisimai/lhost'
8
7
 
9
8
  Indicators = Sisimai::Lhost.INDICATORS
10
- ReBackbone = %r|^Received:[ ]*from[ ]mail[.]zoho[.]com[ ]by[ ]mx[.]zohomail[.]com|.freeze
9
+ Boundaries = ['Received: from mail.zoho.com by mx.zohomail.com'].freeze
11
10
  StartingOf = { message: ['This message was created automatically by mail delivery'] }.freeze
12
11
  MessagesOf = { 'expired' => ['Host not reachable'] }.freeze
13
12
 
@@ -16,23 +15,23 @@ module Sisimai::Lhost
16
15
  # @param [String] mbody Message body of a bounce email
17
16
  # @return [Hash] Bounce data list and message/rfc822 part
18
17
  # @return [Nil] it failed to parse or the arguments are missing
19
- def make(mhead, mbody)
18
+ def inquire(mhead, mbody)
20
19
  # X-ZohoMail: Si CHF_MF_NL SS_10 UW48 UB48 FMWL UW48 UB48 SGR3_1_09124_42
21
20
  # X-Zoho-Virus-Status: 2
22
21
  # X-Mailer: Zoho Mail
23
22
  return nil unless mhead['x-zohomail']
24
23
 
25
24
  dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
26
- emailsteak = Sisimai::RFC5322.fillet(mbody, ReBackbone)
27
- bodyslices = emailsteak[0].split("\n")
25
+ emailparts = Sisimai::RFC5322.part(mbody, Boundaries)
26
+ bodyslices = emailparts[0].split("\n")
28
27
  readcursor = 0 # (Integer) Points the current cursor position
29
28
  recipients = 0 # (Integer) The number of 'Final-Recipient' header
30
29
  qprintable = false
31
30
  v = nil
32
31
 
33
32
  while e = bodyslices.shift do
34
- # Read error messages and delivery status lines from the head of the email
35
- # to the previous line of the beginning of the original message.
33
+ # Read error messages and delivery status lines from the head of the email to the previous
34
+ # line of the beginning of the original message.
36
35
  if readcursor == 0
37
36
  # Beginning of the bounce message or delivery status part
38
37
  readcursor |= Indicators[:deliverystatus] if e.start_with?(StartingOf[:message][0])
@@ -54,15 +53,15 @@ module Sisimai::Lhost
54
53
  # shironeko@example.org Invalid Address, ERROR_CODE :550, ERROR_CODE :Requested action not taken: mailbox unavailable
55
54
  v = dscontents[-1]
56
55
 
57
- if cv = e.match(/\A([^ ]+[@][^ ]+)[ \t]+(.+)\z/)
56
+ if Sisimai::String.aligned(e, ['@', ' ', 'ERROR_CODE :'])
58
57
  # kijitora@example.co.jp Invalid Address, ERROR_CODE :550, ERROR_CODE :5.1.=
59
58
  if v['recipient']
60
59
  # There are multiple recipient addresses in the message body.
61
60
  dscontents << Sisimai::Lhost.DELIVERYSTATUS
62
61
  v = dscontents[-1]
63
62
  end
64
- v['recipient'] = cv[1]
65
- v['diagnosis'] = cv[2]
63
+ v['recipient'] = e[0, e.index(' ')]
64
+ v['diagnosis'] = e[e.index(' ') + 1, e.size]
66
65
 
67
66
  if v['diagnosis'].end_with?('=')
68
67
  # Quoted printable
@@ -71,7 +70,7 @@ module Sisimai::Lhost
71
70
  end
72
71
  recipients += 1
73
72
 
74
- elsif cv = e.match(/\A\[Status: .+[<]([^ ]+[@][^ ]+)[>],/)
73
+ elsif e.start_with?('[Status: ')
75
74
  # Expired
76
75
  # [Status: Error, Address: <kijitora@6kaku.example.co.jp>, ResponseCode 421, , Host not reachable.]
77
76
  if v['recipient']
@@ -79,7 +78,9 @@ module Sisimai::Lhost
79
78
  dscontents << Sisimai::Lhost.DELIVERYSTATUS
80
79
  v = dscontents[-1]
81
80
  end
82
- v['recipient'] = cv[1]
81
+ p1 = e.index('<')
82
+ p2 = e.index('>', p1 + 2)
83
+ v['recipient'] = Sisimai::Address.s3s4(e[p1, p2 - p1])
83
84
  v['diagnosis'] = e
84
85
  recipients += 1
85
86
  else
@@ -100,7 +101,7 @@ module Sisimai::Lhost
100
101
  end
101
102
  end
102
103
 
103
- return { 'ds' => dscontents, 'rfc822' => emailsteak[1] }
104
+ return { 'ds' => dscontents, 'rfc822' => emailparts[1] }
104
105
  end
105
106
  def description; return 'Zoho Mail: https://www.zoho.com'; end
106
107
  end
data/lib/sisimai/lhost.rb CHANGED
@@ -2,7 +2,6 @@ module Sisimai
2
2
  # Sisimai::Lhost - Base class for Sisimai::Lhost::*
3
3
  module Lhost
4
4
  class << self
5
- # Imported from p5-Sisimail/lib/Sisimai/Lhost.pm
6
5
  require 'sisimai/rfc5322'
7
6
 
8
7
  # Data structure for parsed bounce messages
@@ -23,7 +22,7 @@ module Sisimai
23
22
  'replycode' => nil, # SMTP Reply code
24
23
  'diagnosis' => nil, # The value of Diagnostic-Code header
25
24
  'recipient' => nil, # The value of Final-Recipient header
26
- 'softbounce' => nil, # Soft bounce or not
25
+ 'hardbounce' => nil, # Hard bounce or not
27
26
  'feedbacktype' => nil, # Feedback Type
28
27
  }
29
28
  end
@@ -42,13 +41,12 @@ module Sisimai
42
41
  # @return [Array] MTA list with order
43
42
  def index
44
43
  return %w[
45
- Activehunter Amavis AmazonSES AmazonWorkMail Aol ApacheJames Barracuda Bigfoot
46
- Biglobe Courier Domino EZweb EinsUndEins Exchange2003 Exchange2007 Exim FML
47
- Facebook GMX GSuite GoogleGroups Gmail IMailServer InterScanMSS KDDI MXLogic
48
- MailFoundry MailMarshalSMTP MailRu McAfee MessageLabs MessagingServer Notes
49
- Office365 OpenSMTPD Outlook Postfix PowerMTA ReceivingSES SendGrid Sendmail
50
- SurfControl V5sendmail Verizon X1 X2 X3 X4 X5 X6 Yahoo Yandex Zoho MFILTER
51
- Qmail
44
+ Activehunter Amavis AmazonSES AmazonWorkMail Aol ApacheJames Barracuda Bigfoot Biglobe
45
+ Courier Domino EZweb EinsUndEins Exchange2003 Exchange2007 Exim FML Facebook GMX GSuite
46
+ GoogleGroups Gmail IMailServer InterScanMSS KDDI MXLogic MailFoundry MailMarshalSMTP
47
+ MailRu McAfee MessageLabs MessagingServer Notes Office365 OpenSMTPD Outlook Postfix
48
+ PowerMTA ReceivingSES SendGrid Sendmail SurfControl V5sendmail Verizon X1 X2 X3 X4 X5 X6
49
+ Yahoo Yandex Zoho MFILTER Qmail
52
50
  ]
53
51
  end
54
52
 
@@ -71,7 +69,7 @@ module Sisimai
71
69
  # @param [String] mbody Message body of a bounce email
72
70
  # @return [Hash] Bounce data list and message/rfc822 part
73
71
  # @return [Nil] it failed to parse or the arguments are missing
74
- def make; return nil; end
72
+ def inquire; return nil; end
75
73
  def description; return ''; end
76
74
  end
77
75
  end
@@ -1,9 +1,7 @@
1
1
  module Sisimai
2
2
  class Mail
3
- # Sisimai::Mail::Maildir is a reader for getting contents of each email in
4
- # the Maildir/ directory.
3
+ # Sisimai::Mail::Maildir is a reader for getting contents of each email in the Maildir/ directory.
5
4
  class Maildir
6
- # Imported from p5-Sisimail/lib/Sisimai/Mail/Maildir.pm
7
5
  # :dir [String] Path to Maildir/
8
6
  # :size [Integer] The number of files/directories in the Maildir/
9
7
  # :path [String] Path to each file
@@ -2,7 +2,6 @@ module Sisimai
2
2
  class Mail
3
3
  # Sisimai::Mail::Mbox is a mailbox file (UNIX mbox) reader.
4
4
  class Mbox
5
- # Imported from p5-Sisimail/lib/Sisimai/Mail/Mbox.pm
6
5
  # :dir [String] Directory name of the mbox
7
6
  # :file [String] File name of the mbox
8
7
  # :path [String] Path to mbox
@@ -13,9 +12,9 @@ module Sisimai
13
12
  attr_accessor :offset, :handle
14
13
 
15
14
  # Constructor of Sisimai::Mail::Mbox
16
- # @param [String] argv1 Path to mbox
17
- # @return [Sisimai::Mail::Mbox,Nil] Object or nil if the argument is not
18
- # specified or does not exist
15
+ # @param [String] argv1 Path to mbox
16
+ # @return [Sisimai::Mail::Mbox] Object
17
+ # [Nil] is not specified or does not exist
19
18
  def initialize(argv1)
20
19
  raise Errno::ENOENT unless File.exist?(argv1)
21
20
  raise 'is not a file' unless File.ftype(argv1) == 'file'
@@ -2,7 +2,6 @@ module Sisimai
2
2
  class Mail
3
3
  # Sisimai::Mail::Memory is a class for reading an email string
4
4
  class Memory
5
- # Imported from p5-Sisimail/lib/Sisimai/Mail/Memory.pm
6
5
  # :path [String] Fixed string "<MEMORY>"
7
6
  # :size [Integer] data size of the email text
8
7
  # :payload [Array] Entire bounce mail message
@@ -1,9 +1,7 @@
1
1
  module Sisimai
2
2
  class Mail
3
- # Sisimai::Mail::STDIN is a reader for getting contents of each email from
4
- # STDIN
3
+ # Sisimai::Mail::STDIN is a reader for getting contents of each email from STDIN
5
4
  class STDIN
6
- # Imported from p5-Sisimail/lib/Sisimai/Mail/STDIN.pm
7
5
  # :path [String] Fixed string "<STDIN>"
8
6
  # :size [Integer] Data size which has been read
9
7
  # :offset [Integer] The number of emails which have neen read
data/lib/sisimai/mail.rb CHANGED
@@ -1,10 +1,7 @@
1
1
  module Sisimai
2
- # Sisimai::Mail is a handler of UNIX mbox or Maildir for reading each mail.
3
- # It is a wrapper class of Sisimai::Mail::Mbox, Sisimai::Mail::Maildir, and
4
- # Sisimai::Mail::Memory classes.
2
+ # Sisimai::Mail is a handler of UNIX mbox or Maildir for reading each mail. It is a wrapper class
3
+ # of Sisimai::Mail::Mbox, Sisimai::Mail::Maildir, and Sisimai::Mail::Memory classes.
5
4
  class Mail
6
- # Imported from p5-Sisimail/lib/Sisimai/Mail.pm
7
-
8
5
  # :path [String] path to mbox or Maildir/
9
6
  # :kind [String] Data type: mailbox, maildir, or stdin
10
7
  # :data [Sisimai::Mail::[Mbox,Maildir,Memory,STDIN]] Object
@@ -47,8 +44,7 @@ module Sisimai
47
44
  end
48
45
  end
49
46
  elsif argv1.is_a?(IO)
50
- # Read from STDIN
51
- # The argument neither a mailbox nor a Maildir/.
47
+ # Read from STDIN, The argument neither a mailbox nor a Maildir/.
52
48
  classname = self.class.to_s << '::STDIN'
53
49
  parameter['kind'] = 'stdin'
54
50
  parameter['path'] = '<STDIN>'
data/lib/sisimai/mda.rb CHANGED
@@ -1,25 +1,17 @@
1
1
  module Sisimai
2
2
  # Sisimai::MDA - Error message parser for MDA
3
3
  module MDA
4
- # Imported from p5-Sisimail/lib/Sisimai/MDA.pm
5
4
  class << self
6
5
  AgentNames = {
7
6
  # dovecot/src/deliver/deliver.c
8
7
  # 11: #define DEFAULT_MAIL_REJECTION_HUMAN_REASON \
9
8
  # 12: "Your message to <%t> was automatically rejected:%n%r"
10
- 'dovecot' => %r/\AYour message to [^ ]+ was automatically rejected:\z/,
11
- 'mail.local' => %r/\Amail[.]local: /,
12
- 'procmail' => %r/\Aprocmail: /,
13
- 'maildrop' => %r/\Amaildrop: /,
14
- 'vpopmail' => %r/\Avdelivermail: /,
15
- 'vmailmgr' => %r/\Avdeliver: /,
16
- }.freeze
17
- MarkingsOf = {
18
- message: %r{\A(?>
19
- Your[ ]message[ ]to[ ][^ ]+[ ]was[ ]automatically[ ]rejected:\z
20
- |(?:mail[.]local|procmail|maildrop|vdelivermail|vdeliver):[ ]
21
- )
22
- }x
9
+ 'dovecot' => ['Your message to ', ' was automatically rejected:'],
10
+ 'mail.local' => ['mail.local: '],
11
+ 'procmail' => ['procmail: '],
12
+ 'maildrop' => ['maildrop: '],
13
+ 'vpopmail' => ['vdelivermail: '],
14
+ 'vmailmgr' => ['vdeliver: '],
23
15
  }.freeze
24
16
 
25
17
  # dovecot/src/deliver/mail-send.c:94
@@ -79,43 +71,37 @@ module Sisimai
79
71
  # @param [String] mbody Message body of a bounce email
80
72
  # @return [Hash] Bounce data list and message/rfc822 part
81
73
  # @return [Nil] it failed to parse or the arguments are missing
82
- def make(mhead, mbody)
74
+ def inquire(mhead, mbody)
75
+ return nil unless mhead
76
+ return nil unless mbody.size > 0
83
77
  return nil unless mhead['from'].downcase.start_with?('mail delivery subsystem','mailer-daemon', 'postmaster')
84
78
 
85
- agentname0 = '' # [String] MDA name
79
+ deliversby = '' # [String] Mail Delivery Agent name
86
80
  reasonname = '' # [String] Error reason
87
81
  bouncemesg = '' # [String] Error message
88
- bodyslices = mbody.split("\n")
89
- linebuffer = []
82
+ linebuffer = mbody.split("\n")
90
83
 
91
- while e = bodyslices.shift do
92
- # Check each line with each MDA's symbol regular expression.
93
- if agentname0 == ''
94
- # Try to match with each regular expression
95
- next if e.empty?
96
- next unless e =~ MarkingsOf[:message]
84
+ AgentNames.each_key do |e|
85
+ # Find a mail delivery agent name from the entire message body
86
+ p = mbody.index(AgentNames[e][0])
87
+ next unless p
97
88
 
98
- AgentNames.each_key do |f|
99
- # Detect the agent name from the line
100
- next unless e =~ AgentNames[f]
101
- agentname0 = f
102
- break
103
- end
89
+ if AgentNames[e].size > 1
90
+ # Try to find the 2nd argument
91
+ q = mbody.index(AgentNames[e][1])
92
+ next unless q
93
+ next if p > q
104
94
  end
105
-
106
- # Append error message lines to @linebuffer
107
- linebuffer << e
108
- break if e.empty?
95
+ deliversby = e
96
+ break
109
97
  end
110
- return nil if agentname0.empty?
111
- return nil if linebuffer.empty?
98
+ return nil if deliversby.empty?
112
99
 
113
- MessagesOf[agentname0].each_key do |e|
100
+ MessagesOf[deliversby].each_key do |e|
114
101
  # Detect an error reason from message patterns of the MDA.
115
- duplicated = linebuffer.dup
116
- while f = duplicated.shift do
117
- # Whether the error message include each message defined in $MessagesOf
118
- next unless MessagesOf[agentname0][e].any? { |a| f.downcase.include?(a) }
102
+ linebuffer.each do |f|
103
+ # Whether the error message include each message defined in MessagesOf
104
+ next unless MessagesOf[deliversby][e].any? { |a| f.downcase.include?(a) }
119
105
  reasonname = e
120
106
  bouncemesg = f
121
107
  break
@@ -124,7 +110,7 @@ module Sisimai
124
110
  end
125
111
 
126
112
  return {
127
- 'mda' => agentname0,
113
+ 'mda' => deliversby,
128
114
  'reason' => reasonname || '',
129
115
  'message' => bouncemesg || '',
130
116
  }