mail 2.6.5 → 2.7.1

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 (163) hide show
  1. checksums.yaml +5 -5
  2. data/MIT-LICENSE +1 -1
  3. data/README.md +75 -102
  4. data/lib/mail/attachments_list.rb +8 -4
  5. data/lib/mail/body.rb +50 -38
  6. data/lib/mail/check_delivery_params.rb +49 -10
  7. data/lib/mail/configuration.rb +2 -0
  8. data/lib/mail/constants.rb +1 -1
  9. data/lib/mail/core_extensions/smtp.rb +19 -16
  10. data/lib/mail/core_extensions/string.rb +0 -4
  11. data/lib/mail/elements/address.rb +28 -22
  12. data/lib/mail/elements/address_list.rb +10 -18
  13. data/lib/mail/elements/content_disposition_element.rb +8 -15
  14. data/lib/mail/elements/content_location_element.rb +5 -10
  15. data/lib/mail/elements/content_transfer_encoding_element.rb +5 -10
  16. data/lib/mail/elements/content_type_element.rb +8 -19
  17. data/lib/mail/elements/date_time_element.rb +6 -14
  18. data/lib/mail/elements/envelope_from_element.rb +14 -21
  19. data/lib/mail/elements/message_ids_element.rb +8 -12
  20. data/lib/mail/elements/mime_version_element.rb +6 -14
  21. data/lib/mail/elements/phrase_list.rb +6 -9
  22. data/lib/mail/elements/received_element.rb +9 -15
  23. data/lib/mail/encodings/7bit.rb +5 -15
  24. data/lib/mail/encodings/8bit.rb +2 -21
  25. data/lib/mail/encodings/base64.rb +11 -12
  26. data/lib/mail/encodings/binary.rb +3 -22
  27. data/lib/mail/encodings/identity.rb +24 -0
  28. data/lib/mail/encodings/quoted_printable.rb +6 -6
  29. data/lib/mail/encodings/transfer_encoding.rb +38 -29
  30. data/lib/mail/encodings/unix_to_unix.rb +3 -1
  31. data/lib/mail/encodings.rb +99 -43
  32. data/lib/mail/envelope.rb +1 -1
  33. data/lib/mail/field.rb +96 -59
  34. data/lib/mail/fields/bcc_field.rb +2 -2
  35. data/lib/mail/fields/cc_field.rb +1 -1
  36. data/lib/mail/fields/comments_field.rb +1 -1
  37. data/lib/mail/fields/common/common_address.rb +32 -7
  38. data/lib/mail/fields/common/common_field.rb +1 -10
  39. data/lib/mail/fields/common/parameter_hash.rb +1 -1
  40. data/lib/mail/fields/content_description_field.rb +1 -1
  41. data/lib/mail/fields/content_disposition_field.rb +3 -3
  42. data/lib/mail/fields/content_id_field.rb +2 -2
  43. data/lib/mail/fields/content_location_field.rb +1 -1
  44. data/lib/mail/fields/content_transfer_encoding_field.rb +1 -1
  45. data/lib/mail/fields/content_type_field.rb +4 -9
  46. data/lib/mail/fields/date_field.rb +2 -3
  47. data/lib/mail/fields/from_field.rb +1 -1
  48. data/lib/mail/fields/in_reply_to_field.rb +1 -1
  49. data/lib/mail/fields/keywords_field.rb +1 -1
  50. data/lib/mail/fields/message_id_field.rb +1 -1
  51. data/lib/mail/fields/mime_version_field.rb +1 -1
  52. data/lib/mail/fields/optional_field.rb +4 -1
  53. data/lib/mail/fields/received_field.rb +1 -1
  54. data/lib/mail/fields/references_field.rb +1 -1
  55. data/lib/mail/fields/reply_to_field.rb +1 -1
  56. data/lib/mail/fields/resent_bcc_field.rb +1 -1
  57. data/lib/mail/fields/resent_cc_field.rb +1 -1
  58. data/lib/mail/fields/resent_date_field.rb +0 -1
  59. data/lib/mail/fields/resent_from_field.rb +1 -1
  60. data/lib/mail/fields/resent_message_id_field.rb +1 -1
  61. data/lib/mail/fields/resent_sender_field.rb +1 -1
  62. data/lib/mail/fields/resent_to_field.rb +1 -1
  63. data/lib/mail/fields/return_path_field.rb +1 -1
  64. data/lib/mail/fields/sender_field.rb +1 -1
  65. data/lib/mail/fields/subject_field.rb +1 -1
  66. data/lib/mail/fields/to_field.rb +1 -1
  67. data/lib/mail/fields/unstructured_field.rb +21 -4
  68. data/lib/mail/header.rb +10 -8
  69. data/lib/mail/mail.rb +2 -10
  70. data/lib/mail/matchers/has_sent_mail.rb +21 -1
  71. data/lib/mail/message.rb +78 -68
  72. data/lib/mail/multibyte/chars.rb +29 -28
  73. data/lib/mail/multibyte/unicode.rb +10 -10
  74. data/lib/mail/multibyte.rb +64 -15
  75. data/lib/mail/network/delivery_methods/exim.rb +6 -10
  76. data/lib/mail/network/delivery_methods/file_delivery.rb +4 -8
  77. data/lib/mail/network/delivery_methods/logger_delivery.rb +37 -0
  78. data/lib/mail/network/delivery_methods/sendmail.rb +16 -11
  79. data/lib/mail/network/delivery_methods/smtp.rb +59 -53
  80. data/lib/mail/network/delivery_methods/smtp_connection.rb +10 -6
  81. data/lib/mail/network/delivery_methods/test_mailer.rb +5 -8
  82. data/lib/mail/network/retriever_methods/imap.rb +18 -5
  83. data/lib/mail/network/retriever_methods/pop3.rb +3 -1
  84. data/lib/mail/network.rb +1 -0
  85. data/lib/mail/parser_tools.rb +15 -0
  86. data/lib/mail/parsers/address_lists_parser.rb +33207 -104
  87. data/lib/mail/parsers/address_lists_parser.rl +172 -0
  88. data/lib/mail/parsers/content_disposition_parser.rb +876 -49
  89. data/lib/mail/parsers/content_disposition_parser.rl +82 -0
  90. data/lib/mail/parsers/content_location_parser.rb +803 -23
  91. data/lib/mail/parsers/content_location_parser.rl +71 -0
  92. data/lib/mail/parsers/content_transfer_encoding_parser.rb +501 -19
  93. data/lib/mail/parsers/content_transfer_encoding_parser.rl +64 -0
  94. data/lib/mail/parsers/content_type_parser.rb +1023 -48
  95. data/lib/mail/parsers/content_type_parser.rl +83 -0
  96. data/lib/mail/parsers/date_time_parser.rb +870 -24
  97. data/lib/mail/parsers/date_time_parser.rl +62 -0
  98. data/lib/mail/parsers/envelope_from_parser.rb +3569 -34
  99. data/lib/mail/parsers/envelope_from_parser.rl +82 -0
  100. data/lib/mail/parsers/message_ids_parser.rb +2839 -25
  101. data/lib/mail/parsers/message_ids_parser.rl +82 -0
  102. data/lib/mail/parsers/mime_version_parser.rb +491 -26
  103. data/lib/mail/parsers/mime_version_parser.rl +61 -0
  104. data/lib/mail/parsers/phrase_lists_parser.rb +860 -18
  105. data/lib/mail/parsers/phrase_lists_parser.rl +83 -0
  106. data/lib/mail/parsers/received_parser.rb +8764 -37
  107. data/lib/mail/parsers/received_parser.rl +84 -0
  108. data/lib/mail/parsers/rfc2045_content_transfer_encoding.rl +13 -0
  109. data/lib/mail/parsers/rfc2045_content_type.rl +25 -0
  110. data/lib/mail/parsers/rfc2045_mime.rl +16 -0
  111. data/lib/mail/parsers/rfc2183_content_disposition.rl +15 -0
  112. data/lib/mail/parsers/rfc3629_utf8.rl +19 -0
  113. data/lib/mail/parsers/rfc5234_abnf_core_rules.rl +22 -0
  114. data/lib/mail/parsers/rfc5322.rl +59 -0
  115. data/lib/mail/parsers/rfc5322_address.rl +72 -0
  116. data/lib/mail/parsers/{ragel/date_time.rl → rfc5322_date_time.rl} +8 -1
  117. data/lib/mail/parsers/rfc5322_lexical_tokens.rl +60 -0
  118. data/lib/mail/parsers.rb +16 -24
  119. data/lib/mail/part.rb +3 -3
  120. data/lib/mail/parts_list.rb +5 -6
  121. data/lib/mail/utilities.rb +59 -28
  122. data/lib/mail/version.rb +2 -2
  123. data/lib/mail/version_specific/ruby_1_8.rb +40 -3
  124. data/lib/mail/version_specific/ruby_1_9.rb +61 -9
  125. data/lib/mail.rb +3 -16
  126. metadata +44 -53
  127. data/CHANGELOG.rdoc +0 -795
  128. data/CONTRIBUTING.md +0 -60
  129. data/Dependencies.txt +0 -2
  130. data/Gemfile +0 -14
  131. data/Rakefile +0 -29
  132. data/TODO.rdoc +0 -9
  133. data/lib/mail/core_extensions/string/access.rb +0 -146
  134. data/lib/mail/core_extensions/string/multibyte.rb +0 -79
  135. data/lib/mail/multibyte/exceptions.rb +0 -9
  136. data/lib/mail/parsers/ragel/common.rl +0 -185
  137. data/lib/mail/parsers/ragel/parser_info.rb +0 -61
  138. data/lib/mail/parsers/ragel/ruby/machines/address_lists_machine.rb +0 -14864
  139. data/lib/mail/parsers/ragel/ruby/machines/address_lists_machine.rb.rl +0 -37
  140. data/lib/mail/parsers/ragel/ruby/machines/content_disposition_machine.rb +0 -751
  141. data/lib/mail/parsers/ragel/ruby/machines/content_disposition_machine.rb.rl +0 -37
  142. data/lib/mail/parsers/ragel/ruby/machines/content_location_machine.rb +0 -614
  143. data/lib/mail/parsers/ragel/ruby/machines/content_location_machine.rb.rl +0 -37
  144. data/lib/mail/parsers/ragel/ruby/machines/content_transfer_encoding_machine.rb +0 -447
  145. data/lib/mail/parsers/ragel/ruby/machines/content_transfer_encoding_machine.rb.rl +0 -37
  146. data/lib/mail/parsers/ragel/ruby/machines/content_type_machine.rb +0 -825
  147. data/lib/mail/parsers/ragel/ruby/machines/content_type_machine.rb.rl +0 -37
  148. data/lib/mail/parsers/ragel/ruby/machines/date_time_machine.rb +0 -817
  149. data/lib/mail/parsers/ragel/ruby/machines/date_time_machine.rb.rl +0 -37
  150. data/lib/mail/parsers/ragel/ruby/machines/envelope_from_machine.rb +0 -2149
  151. data/lib/mail/parsers/ragel/ruby/machines/envelope_from_machine.rb.rl +0 -37
  152. data/lib/mail/parsers/ragel/ruby/machines/message_ids_machine.rb +0 -1570
  153. data/lib/mail/parsers/ragel/ruby/machines/message_ids_machine.rb.rl +0 -37
  154. data/lib/mail/parsers/ragel/ruby/machines/mime_version_machine.rb +0 -440
  155. data/lib/mail/parsers/ragel/ruby/machines/mime_version_machine.rb.rl +0 -37
  156. data/lib/mail/parsers/ragel/ruby/machines/phrase_lists_machine.rb +0 -564
  157. data/lib/mail/parsers/ragel/ruby/machines/phrase_lists_machine.rb.rl +0 -37
  158. data/lib/mail/parsers/ragel/ruby/machines/rb_actions.rl +0 -51
  159. data/lib/mail/parsers/ragel/ruby/machines/received_machine.rb +0 -5144
  160. data/lib/mail/parsers/ragel/ruby/machines/received_machine.rb.rl +0 -37
  161. data/lib/mail/parsers/ragel/ruby/parser.rb.rl.erb +0 -37
  162. data/lib/mail/parsers/ragel/ruby.rb +0 -40
  163. data/lib/mail/parsers/ragel.rb +0 -18
@@ -37,17 +37,13 @@ module Mail
37
37
  #
38
38
  # mail.deliver!
39
39
  class Exim < Sendmail
40
- def initialize(values)
41
- self.settings = { :location => '/usr/sbin/exim',
42
- :arguments => '-i -t' }.merge(values)
43
- end
40
+ DEFAULTS = {
41
+ :location => '/usr/sbin/exim',
42
+ :arguments => '-i -t'
43
+ }
44
44
 
45
- def self.call(path, arguments, destinations, mail)
46
- popen "#{path} #{arguments}" do |io|
47
- io.puts ::Mail::Utilities.to_lf(mail.encoded)
48
- io.flush
49
- end
45
+ def self.call(path, arguments, destinations, encoded_message)
46
+ super path, arguments, nil, encoded_message
50
47
  end
51
-
52
48
  end
53
49
  end
@@ -2,7 +2,6 @@
2
2
  require 'mail/check_delivery_params'
3
3
 
4
4
  module Mail
5
-
6
5
  # FileDelivery class delivers emails into multiple files based on the destination
7
6
  # address. Each file is appended to if it already exists.
8
7
  #
@@ -14,22 +13,20 @@ module Mail
14
13
  # Make sure the path you specify with :location is writable by the Ruby process
15
14
  # running Mail.
16
15
  class FileDelivery
17
- include Mail::CheckDeliveryParams
18
-
19
16
  if RUBY_VERSION >= '1.9.1'
20
17
  require 'fileutils'
21
18
  else
22
19
  require 'ftools'
23
20
  end
24
21
 
22
+ attr_accessor :settings
23
+
25
24
  def initialize(values)
26
25
  self.settings = { :location => './mails' }.merge!(values)
27
26
  end
28
-
29
- attr_accessor :settings
30
-
27
+
31
28
  def deliver!(mail)
32
- check_delivery_params(mail)
29
+ Mail::CheckDeliveryParams.check(mail)
33
30
 
34
31
  if ::File.respond_to?(:makedirs)
35
32
  ::File.makedirs settings[:location]
@@ -41,6 +38,5 @@ module Mail
41
38
  ::File.open(::File.join(settings[:location], File.basename(to.to_s)), 'a') { |f| "#{f.write(mail.encoded)}\r\n\r\n" }
42
39
  end
43
40
  end
44
-
45
41
  end
46
42
  end
@@ -0,0 +1,37 @@
1
+ require 'mail/check_delivery_params'
2
+
3
+ module Mail
4
+ class LoggerDelivery
5
+ include Mail::CheckDeliveryParams
6
+
7
+ attr_reader :logger, :severity, :settings
8
+
9
+ def initialize(settings)
10
+ @settings = settings
11
+ @logger = settings.fetch(:logger) { default_logger }
12
+ @severity = derive_severity(settings[:severity])
13
+ end
14
+
15
+ def deliver!(mail)
16
+ Mail::CheckDeliveryParams.check(mail)
17
+ logger.log(severity) { mail.encoded }
18
+ end
19
+
20
+ private
21
+ def default_logger
22
+ require 'logger'
23
+ ::Logger.new($stdout)
24
+ end
25
+
26
+ def derive_severity(severity)
27
+ case severity
28
+ when nil
29
+ Logger::INFO
30
+ when Integer
31
+ severity
32
+ else
33
+ Logger.const_get(severity.to_s.upcase)
34
+ end
35
+ end
36
+ end
37
+ end
@@ -38,19 +38,21 @@ module Mail
38
38
  #
39
39
  # mail.deliver!
40
40
  class Sendmail
41
- include Mail::CheckDeliveryParams
41
+ DEFAULTS = {
42
+ :location => '/usr/sbin/sendmail',
43
+ :arguments => '-i'
44
+ }
45
+
46
+ attr_accessor :settings
42
47
 
43
48
  def initialize(values)
44
- self.settings = { :location => '/usr/sbin/sendmail',
45
- :arguments => '-i' }.merge(values)
49
+ self.settings = self.class::DEFAULTS.merge(values)
46
50
  end
47
51
 
48
- attr_accessor :settings
49
-
50
52
  def deliver!(mail)
51
- smtp_from, smtp_to, message = check_delivery_params(mail)
53
+ smtp_from, smtp_to, message = Mail::CheckDeliveryParams.check(mail)
52
54
 
53
- from = "-f #{self.class.shellquote(smtp_from)}"
55
+ from = "-f #{self.class.shellquote(smtp_from)}" if smtp_from
54
56
  to = smtp_to.map { |_to| self.class.shellquote(_to) }.join(' ')
55
57
 
56
58
  arguments = "#{settings[:arguments]} #{from} --"
@@ -59,7 +61,7 @@ module Mail
59
61
 
60
62
  def self.call(path, arguments, destinations, encoded_message)
61
63
  popen "#{path} #{arguments} #{destinations}" do |io|
62
- io.puts ::Mail::Utilities.to_lf(encoded_message)
64
+ io.puts ::Mail::Utilities.binary_unsafe_to_lf(encoded_message)
63
65
  io.flush
64
66
  end
65
67
  end
@@ -75,15 +77,18 @@ module Mail
75
77
  end
76
78
 
77
79
  # The following is an adaptation of ruby 1.9.2's shellwords.rb file,
78
- # it is modified to include '+' in the allowed list to allow for
79
- # sendmail to accept email addresses as the sender with a + in them.
80
+ # with the following modifications:
81
+ #
82
+ # - Wraps in double quotes
83
+ # - Allows '+' to accept email addresses with them
84
+ # - Allows '~' as it is not unescaped in double quotes
80
85
  def self.shellquote(address)
81
86
  # Process as a single byte sequence because not all shell
82
87
  # implementations are multibyte aware.
83
88
  #
84
89
  # A LF cannot be escaped with a backslash because a backslash + LF
85
90
  # combo is regarded as line continuation and simply ignored. Strip it.
86
- escaped = address.gsub(/([^A-Za-z0-9_\s\+\-.,:\/@])/n, "\\\\\\1").gsub("\n", '')
91
+ escaped = address.gsub(/([^A-Za-z0-9_\s\+\-.,:\/@~])/n, "\\\\\\1").gsub("\n", '')
87
92
  %("#{escaped}")
88
93
  end
89
94
  end
@@ -45,9 +45,8 @@ module Mail
45
45
  # hostname or update the certificate authorities trusted by your ruby. If
46
46
  # that isn't possible, you can control this behavior with
47
47
  # an :openssl_verify_mode setting. Its value may be either an OpenSSL
48
- # verify mode constant (OpenSSL::SSL::VERIFY_NONE), or a string containing
49
- # the name of an OpenSSL verify mode (none, peer, client_once,
50
- # fail_if_no_peer_cert).
48
+ # verify mode constant (OpenSSL::SSL::VERIFY_NONE, OpenSSL::SSL::VERIFY_PEER),
49
+ # or a string containing the name of an OpenSSL verify mode (none, peer).
51
50
  #
52
51
  # === Others
53
52
  #
@@ -75,69 +74,76 @@ module Mail
75
74
  #
76
75
  # mail.deliver!
77
76
  class SMTP
78
- include Mail::CheckDeliveryParams
77
+ attr_accessor :settings
78
+
79
+ DEFAULTS = {
80
+ :address => 'localhost',
81
+ :port => 25,
82
+ :domain => 'localhost.localdomain',
83
+ :user_name => nil,
84
+ :password => nil,
85
+ :authentication => nil,
86
+ :enable_starttls => nil,
87
+ :enable_starttls_auto => true,
88
+ :openssl_verify_mode => nil,
89
+ :ssl => nil,
90
+ :tls => nil,
91
+ :open_timeout => nil,
92
+ :read_timeout => nil
93
+ }
79
94
 
80
95
  def initialize(values)
81
- self.settings = { :address => "localhost",
82
- :port => 25,
83
- :domain => 'localhost.localdomain',
84
- :user_name => nil,
85
- :password => nil,
86
- :authentication => nil,
87
- :enable_starttls_auto => true,
88
- :openssl_verify_mode => nil,
89
- :ssl => nil,
90
- :tls => nil
91
- }.merge!(values)
96
+ self.settings = DEFAULTS.merge(values)
92
97
  end
93
98
 
94
- attr_accessor :settings
95
-
96
- # Send the message via SMTP.
97
- # The from and to attributes are optional. If not set, they are retrieve from the Message.
98
99
  def deliver!(mail)
99
- smtp_from, smtp_to, message = check_delivery_params(mail)
100
-
101
- smtp = Net::SMTP.new(settings[:address], settings[:port])
102
- if settings[:tls] || settings[:ssl]
103
- if smtp.respond_to?(:enable_tls)
104
- smtp.enable_tls(ssl_context)
105
- end
106
- elsif settings[:enable_starttls_auto]
107
- if smtp.respond_to?(:enable_starttls_auto)
108
- smtp.enable_starttls_auto(ssl_context)
109
- end
110
- end
111
-
112
- response = nil
113
- smtp.start(settings[:domain], settings[:user_name], settings[:password], settings[:authentication]) do |smtp_obj|
114
- response = smtp_obj.sendmail(message, smtp_from, smtp_to)
100
+ response = start_smtp_session do |smtp|
101
+ Mail::SMTPConnection.new(:connection => smtp, :return_response => true).deliver!(mail)
115
102
  end
116
103
 
117
- if settings[:return_response]
118
- response
119
- else
120
- self
121
- end
104
+ settings[:return_response] ? response : self
122
105
  end
123
-
124
106
 
125
107
  private
108
+ def start_smtp_session(&block)
109
+ build_smtp_session.start(settings[:domain], settings[:user_name], settings[:password], settings[:authentication], &block)
110
+ end
126
111
 
127
- # Allow SSL context to be configured via settings, for Ruby >= 1.9
128
- # Just returns openssl verify mode for Ruby 1.8.x
129
- def ssl_context
130
- openssl_verify_mode = settings[:openssl_verify_mode]
112
+ def build_smtp_session
113
+ Net::SMTP.new(settings[:address], settings[:port]).tap do |smtp|
114
+ if settings[:tls] || settings[:ssl]
115
+ if smtp.respond_to?(:enable_tls)
116
+ smtp.enable_tls(ssl_context)
117
+ end
118
+ elsif settings[:enable_starttls]
119
+ if smtp.respond_to?(:enable_starttls)
120
+ smtp.enable_starttls(ssl_context)
121
+ end
122
+ elsif settings[:enable_starttls_auto]
123
+ if smtp.respond_to?(:enable_starttls_auto)
124
+ smtp.enable_starttls_auto(ssl_context)
125
+ end
126
+ end
131
127
 
132
- if openssl_verify_mode.kind_of?(String)
133
- openssl_verify_mode = "OpenSSL::SSL::VERIFY_#{openssl_verify_mode.upcase}".constantize
128
+ smtp.open_timeout = settings[:open_timeout] if settings[:open_timeout]
129
+ smtp.read_timeout = settings[:read_timeout] if settings[:read_timeout]
130
+ end
134
131
  end
135
132
 
136
- context = Net::SMTP.default_ssl_context
137
- context.verify_mode = openssl_verify_mode
138
- context.ca_path = settings[:ca_path] if settings[:ca_path]
139
- context.ca_file = settings[:ca_file] if settings[:ca_file]
140
- context
141
- end
133
+ # Allow SSL context to be configured via settings, for Ruby >= 1.9
134
+ # Just returns openssl verify mode for Ruby 1.8.x
135
+ def ssl_context
136
+ openssl_verify_mode = settings[:openssl_verify_mode]
137
+
138
+ if openssl_verify_mode.kind_of?(String)
139
+ openssl_verify_mode = OpenSSL::SSL.const_get("VERIFY_#{openssl_verify_mode.upcase}")
140
+ end
141
+
142
+ context = Net::SMTP.default_ssl_context
143
+ context.verify_mode = openssl_verify_mode if openssl_verify_mode
144
+ context.ca_path = settings[:ca_path] if settings[:ca_path]
145
+ context.ca_file = settings[:ca_file] if settings[:ca_file]
146
+ context
147
+ end
142
148
  end
143
149
  end
@@ -38,7 +38,7 @@ module Mail
38
38
  #
39
39
  # mail.deliver!
40
40
  class SMTPConnection
41
- include Mail::CheckDeliveryParams
41
+ attr_accessor :smtp, :settings
42
42
 
43
43
  def initialize(values)
44
44
  raise ArgumentError.new('A Net::SMTP object is required for this delivery method') if values[:connection].nil?
@@ -46,17 +46,21 @@ module Mail
46
46
  self.settings = values
47
47
  end
48
48
 
49
- attr_accessor :smtp
50
- attr_accessor :settings
51
-
52
49
  # Send the message via SMTP.
53
50
  # The from and to attributes are optional. If not set, they are retrieve from the Message.
54
51
  def deliver!(mail)
55
- smtp_from, smtp_to, message = check_delivery_params(mail)
56
- response = smtp.sendmail(message, smtp_from, smtp_to)
52
+ smtp_from, smtp_to, message = Mail::CheckDeliveryParams.check(mail)
53
+
54
+ response = smtp.sendmail(dot_stuff(message), smtp_from, smtp_to)
57
55
 
58
56
  settings[:return_response] ? response : self
59
57
  end
60
58
 
59
+ private
60
+ # This is Net::SMTP's job, but before Ruby 2.x it does not dot-stuff
61
+ # an unterminated last line: https://bugs.ruby-lang.org/issues/9627
62
+ def dot_stuff(message)
63
+ message.gsub(/(\r\n\.)(\r\n|$)/, '\1.\2')
64
+ end
61
65
  end
62
66
  end
@@ -8,10 +8,8 @@ module Mail
8
8
  # It also provides a template of the minimum methods you require to implement
9
9
  # if you want to make a custom mailer for Mail
10
10
  class TestMailer
11
- include Mail::CheckDeliveryParams
12
-
13
11
  # Provides a store of all the emails sent with the TestMailer so you can check them.
14
- def TestMailer.deliveries
12
+ def self.deliveries
15
13
  @@deliveries ||= []
16
14
  end
17
15
 
@@ -26,20 +24,19 @@ module Mail
26
24
  # * length
27
25
  # * size
28
26
  # * and other common Array methods
29
- def TestMailer.deliveries=(val)
27
+ def self.deliveries=(val)
30
28
  @@deliveries = val
31
29
  end
32
30
 
31
+ attr_accessor :settings
32
+
33
33
  def initialize(values)
34
34
  @settings = values.dup
35
35
  end
36
-
37
- attr_accessor :settings
38
36
 
39
37
  def deliver!(mail)
40
- check_delivery_params(mail)
38
+ Mail::CheckDeliveryParams.check(mail)
41
39
  Mail::TestMailer.deliveries << mail
42
40
  end
43
-
44
41
  end
45
42
  end
@@ -45,7 +45,8 @@ module Mail
45
45
  :user_name => nil,
46
46
  :password => nil,
47
47
  :authentication => nil,
48
- :enable_ssl => false }.merge!(values)
48
+ :enable_ssl => false,
49
+ :enable_starttls => false }.merge!(values)
49
50
  end
50
51
 
51
52
  attr_accessor :settings
@@ -67,14 +68,14 @@ module Mail
67
68
  # keys: are passed as criteria to the SEARCH command. They can either be a string holding the entire search string,
68
69
  # or a single-dimension array of search keywords and arguments. Refer to [IMAP] section 6.4.4 for a full list
69
70
  # The default is 'ALL'
71
+ # search_charset: charset to pass to IMAP server search. Omitted by default. Example: 'UTF-8' or 'ASCII'.
70
72
  #
71
73
  def find(options={}, &block)
72
74
  options = validate_options(options)
73
75
 
74
76
  start do |imap|
75
77
  options[:read_only] ? imap.examine(options[:mailbox]) : imap.select(options[:mailbox])
76
-
77
- uids = imap.uid_search(options[:keys])
78
+ uids = imap.uid_search(options[:keys], options[:search_charset])
78
79
  uids.reverse! if options[:what].to_sym == :last
79
80
  uids = uids.first(options[:count]) if options[:count].is_a?(Integer)
80
81
  uids.reverse! if (options[:what].to_sym == :last && options[:order].to_sym == :asc) ||
@@ -83,14 +84,18 @@ module Mail
83
84
  if block_given?
84
85
  uids.each do |uid|
85
86
  uid = options[:uid].to_i unless options[:uid].nil?
86
- fetchdata = imap.uid_fetch(uid, ['RFC822'])[0]
87
+ fetchdata = imap.uid_fetch(uid, ['RFC822', 'FLAGS'])[0]
87
88
  new_message = Mail.new(fetchdata.attr['RFC822'])
88
89
  new_message.mark_for_delete = true if options[:delete_after_find]
89
- if block.arity == 3
90
+
91
+ if block.arity == 4
92
+ yield new_message, imap, uid, fetchdata.attr['FLAGS']
93
+ elsif block.arity == 3
90
94
  yield new_message, imap, uid
91
95
  else
92
96
  yield new_message
93
97
  end
98
+
94
99
  imap.uid_store(uid, "+FLAGS", [Net::IMAP::DELETED]) if options[:delete_after_find] && new_message.is_marked_for_delete?
95
100
  break unless options[:uid].nil?
96
101
  end
@@ -116,6 +121,7 @@ module Mail
116
121
  mailbox = Net::IMAP.encode_utf7(mailbox)
117
122
 
118
123
  start do |imap|
124
+ imap.select(mailbox)
119
125
  imap.uid_search(['ALL']).each do |uid|
120
126
  imap.uid_store(uid, "+FLAGS", [Net::IMAP::DELETED])
121
127
  end
@@ -154,7 +160,14 @@ module Mail
154
160
  def start(config=Mail::Configuration.instance, &block)
155
161
  raise ArgumentError.new("Mail::Retrievable#imap_start takes a block") unless block_given?
156
162
 
163
+ if settings[:enable_starttls] && settings[:enable_ssl]
164
+ raise ArgumentError, ":enable_starttls and :enable_ssl are mutually exclusive. Set :enable_ssl if you're on an IMAPS connection. Set :enable_starttls if you're on an IMAP connection and using STARTTLS for secure TLS upgrade."
165
+ end
166
+
157
167
  imap = Net::IMAP.new(settings[:address], settings[:port], settings[:enable_ssl], nil, false)
168
+
169
+ imap.starttls if settings[:enable_starttls]
170
+
158
171
  if settings[:authentication].nil?
159
172
  imap.login(settings[:user_name], settings[:password])
160
173
  else
@@ -41,7 +41,8 @@ module Mail
41
41
  :user_name => nil,
42
42
  :password => nil,
43
43
  :authentication => nil,
44
- :enable_ssl => false }.merge!(values)
44
+ :enable_ssl => false,
45
+ :read_timeout => nil }.merge!(values)
45
46
  end
46
47
 
47
48
  attr_accessor :settings
@@ -128,6 +129,7 @@ module Mail
128
129
 
129
130
  pop3 = Net::POP3.new(settings[:address], settings[:port], false)
130
131
  pop3.enable_ssl(OpenSSL::SSL::VERIFY_NONE) if settings[:enable_ssl]
132
+ pop3.read_timeout = settings[:read_timeout] if settings[:read_timeout]
131
133
  pop3.start(settings[:user_name], settings[:password])
132
134
 
133
135
  yield pop3
data/lib/mail/network.rb CHANGED
@@ -4,6 +4,7 @@ require 'mail/network/retriever_methods/base'
4
4
  module Mail
5
5
  register_autoload :SMTP, 'mail/network/delivery_methods/smtp'
6
6
  register_autoload :FileDelivery, 'mail/network/delivery_methods/file_delivery'
7
+ register_autoload :LoggerDelivery, 'mail/network/delivery_methods/logger_delivery'
7
8
  register_autoload :Sendmail, 'mail/network/delivery_methods/sendmail'
8
9
  register_autoload :Exim, 'mail/network/delivery_methods/exim'
9
10
  register_autoload :SMTPConnection, 'mail/network/delivery_methods/smtp_connection'
@@ -0,0 +1,15 @@
1
+ module Mail
2
+ # Extends each field parser with utility methods.
3
+ module ParserTools #:nodoc:
4
+ # Slice bytes from ASCII-8BIT data and mark as UTF-8.
5
+ if 'string'.respond_to?(:force_encoding)
6
+ def chars(data, from_bytes, to_bytes)
7
+ data.slice(from_bytes..to_bytes).force_encoding(Encoding::UTF_8)
8
+ end
9
+ else
10
+ def chars(data, from_bytes, to_bytes)
11
+ data.slice(from_bytes..to_bytes)
12
+ end
13
+ end
14
+ end
15
+ end