mail 2.6.6 → 2.8.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 (180) hide show
  1. checksums.yaml +5 -5
  2. data/MIT-LICENSE +1 -1
  3. data/README.md +134 -119
  4. data/lib/mail/attachments_list.rb +10 -9
  5. data/lib/mail/body.rb +73 -84
  6. data/lib/mail/check_delivery_params.rb +28 -21
  7. data/lib/mail/configuration.rb +2 -0
  8. data/lib/mail/constants.rb +27 -5
  9. data/lib/mail/elements/address.rb +53 -47
  10. data/lib/mail/elements/address_list.rb +11 -19
  11. data/lib/mail/elements/content_disposition_element.rb +9 -16
  12. data/lib/mail/elements/content_location_element.rb +6 -11
  13. data/lib/mail/elements/content_transfer_encoding_element.rb +6 -11
  14. data/lib/mail/elements/content_type_element.rb +16 -23
  15. data/lib/mail/elements/date_time_element.rb +7 -15
  16. data/lib/mail/elements/envelope_from_element.rb +22 -23
  17. data/lib/mail/elements/message_ids_element.rb +18 -13
  18. data/lib/mail/elements/mime_version_element.rb +7 -15
  19. data/lib/mail/elements/phrase_list.rb +12 -10
  20. data/lib/mail/elements/received_element.rb +27 -19
  21. data/lib/mail/encodings/7bit.rb +9 -14
  22. data/lib/mail/encodings/8bit.rb +2 -21
  23. data/lib/mail/encodings/base64.rb +11 -12
  24. data/lib/mail/encodings/binary.rb +3 -22
  25. data/lib/mail/encodings/identity.rb +24 -0
  26. data/lib/mail/encodings/quoted_printable.rb +6 -6
  27. data/lib/mail/encodings/transfer_encoding.rb +38 -29
  28. data/lib/mail/encodings/unix_to_unix.rb +3 -1
  29. data/lib/mail/encodings.rb +81 -54
  30. data/lib/mail/envelope.rb +11 -14
  31. data/lib/mail/field.rb +119 -98
  32. data/lib/mail/field_list.rb +60 -7
  33. data/lib/mail/fields/bcc_field.rb +34 -52
  34. data/lib/mail/fields/cc_field.rb +28 -49
  35. data/lib/mail/fields/comments_field.rb +27 -37
  36. data/lib/mail/fields/common_address_field.rb +170 -0
  37. data/lib/mail/fields/common_date_field.rb +58 -0
  38. data/lib/mail/fields/common_field.rb +77 -0
  39. data/lib/mail/fields/common_message_id_field.rb +42 -0
  40. data/lib/mail/fields/content_description_field.rb +7 -14
  41. data/lib/mail/fields/content_disposition_field.rb +13 -38
  42. data/lib/mail/fields/content_id_field.rb +24 -51
  43. data/lib/mail/fields/content_location_field.rb +11 -25
  44. data/lib/mail/fields/content_transfer_encoding_field.rb +31 -31
  45. data/lib/mail/fields/content_type_field.rb +50 -80
  46. data/lib/mail/fields/date_field.rb +23 -52
  47. data/lib/mail/fields/from_field.rb +28 -49
  48. data/lib/mail/fields/in_reply_to_field.rb +38 -49
  49. data/lib/mail/fields/keywords_field.rb +18 -31
  50. data/lib/mail/fields/message_id_field.rb +25 -71
  51. data/lib/mail/fields/mime_version_field.rb +19 -30
  52. data/lib/mail/fields/named_structured_field.rb +11 -0
  53. data/lib/mail/fields/named_unstructured_field.rb +11 -0
  54. data/lib/mail/fields/optional_field.rb +9 -7
  55. data/lib/mail/fields/{common/parameter_hash.rb → parameter_hash.rb} +13 -11
  56. data/lib/mail/fields/received_field.rb +43 -57
  57. data/lib/mail/fields/references_field.rb +35 -49
  58. data/lib/mail/fields/reply_to_field.rb +28 -49
  59. data/lib/mail/fields/resent_bcc_field.rb +28 -49
  60. data/lib/mail/fields/resent_cc_field.rb +28 -49
  61. data/lib/mail/fields/resent_date_field.rb +5 -30
  62. data/lib/mail/fields/resent_from_field.rb +28 -49
  63. data/lib/mail/fields/resent_message_id_field.rb +5 -29
  64. data/lib/mail/fields/resent_sender_field.rb +27 -56
  65. data/lib/mail/fields/resent_to_field.rb +28 -49
  66. data/lib/mail/fields/return_path_field.rb +50 -54
  67. data/lib/mail/fields/sender_field.rb +34 -55
  68. data/lib/mail/fields/structured_field.rb +3 -30
  69. data/lib/mail/fields/subject_field.rb +9 -11
  70. data/lib/mail/fields/to_field.rb +28 -49
  71. data/lib/mail/fields/unstructured_field.rb +32 -47
  72. data/lib/mail/header.rb +71 -110
  73. data/lib/mail/mail.rb +2 -10
  74. data/lib/mail/matchers/attachment_matchers.rb +15 -0
  75. data/lib/mail/matchers/has_sent_mail.rb +21 -1
  76. data/lib/mail/message.rb +113 -117
  77. data/lib/mail/multibyte/chars.rb +21 -178
  78. data/lib/mail/multibyte/unicode.rb +10 -10
  79. data/lib/mail/multibyte/utils.rb +26 -43
  80. data/lib/mail/multibyte.rb +55 -16
  81. data/lib/mail/network/delivery_methods/exim.rb +5 -4
  82. data/lib/mail/network/delivery_methods/file_delivery.rb +11 -10
  83. data/lib/mail/network/delivery_methods/logger_delivery.rb +34 -0
  84. data/lib/mail/network/delivery_methods/sendmail.rb +62 -21
  85. data/lib/mail/network/delivery_methods/smtp.rb +75 -50
  86. data/lib/mail/network/delivery_methods/smtp_connection.rb +3 -4
  87. data/lib/mail/network/delivery_methods/test_mailer.rb +4 -2
  88. data/lib/mail/network/retriever_methods/base.rb +8 -8
  89. data/lib/mail/network/retriever_methods/imap.rb +20 -7
  90. data/lib/mail/network/retriever_methods/pop3.rb +5 -3
  91. data/lib/mail/network/retriever_methods/test_retriever.rb +2 -1
  92. data/lib/mail/network.rb +1 -0
  93. data/lib/mail/parser_tools.rb +15 -0
  94. data/lib/mail/parsers/address_lists_parser.rb +33225 -116
  95. data/lib/mail/parsers/address_lists_parser.rl +179 -0
  96. data/lib/mail/parsers/content_disposition_parser.rb +882 -49
  97. data/lib/mail/parsers/content_disposition_parser.rl +89 -0
  98. data/lib/mail/parsers/content_location_parser.rb +809 -23
  99. data/lib/mail/parsers/content_location_parser.rl +78 -0
  100. data/lib/mail/parsers/content_transfer_encoding_parser.rb +509 -21
  101. data/lib/mail/parsers/content_transfer_encoding_parser.rl +71 -0
  102. data/lib/mail/parsers/content_type_parser.rb +1037 -56
  103. data/lib/mail/parsers/content_type_parser.rl +90 -0
  104. data/lib/mail/parsers/date_time_parser.rb +877 -25
  105. data/lib/mail/parsers/date_time_parser.rl +69 -0
  106. data/lib/mail/parsers/envelope_from_parser.rb +3669 -40
  107. data/lib/mail/parsers/envelope_from_parser.rl +89 -0
  108. data/lib/mail/parsers/message_ids_parser.rb +5146 -25
  109. data/lib/mail/parsers/message_ids_parser.rl +93 -0
  110. data/lib/mail/parsers/mime_version_parser.rb +497 -26
  111. data/lib/mail/parsers/mime_version_parser.rl +68 -0
  112. data/lib/mail/parsers/phrase_lists_parser.rb +870 -22
  113. data/lib/mail/parsers/phrase_lists_parser.rl +90 -0
  114. data/lib/mail/parsers/received_parser.rb +8776 -43
  115. data/lib/mail/parsers/received_parser.rl +91 -0
  116. data/lib/mail/parsers/rfc2045_content_transfer_encoding.rl +13 -0
  117. data/lib/mail/parsers/rfc2045_content_type.rl +25 -0
  118. data/lib/mail/parsers/rfc2045_mime.rl +16 -0
  119. data/lib/mail/parsers/rfc2183_content_disposition.rl +15 -0
  120. data/lib/mail/parsers/rfc3629_utf8.rl +19 -0
  121. data/lib/mail/parsers/rfc5234_abnf_core_rules.rl +22 -0
  122. data/lib/mail/parsers/rfc5322.rl +74 -0
  123. data/lib/mail/parsers/rfc5322_address.rl +72 -0
  124. data/lib/mail/parsers/{ragel/date_time.rl → rfc5322_date_time.rl} +8 -1
  125. data/lib/mail/parsers/rfc5322_lexical_tokens.rl +60 -0
  126. data/lib/mail/parsers.rb +11 -25
  127. data/lib/mail/part.rb +6 -10
  128. data/lib/mail/parts_list.rb +62 -6
  129. data/lib/mail/smtp_envelope.rb +57 -0
  130. data/lib/mail/utilities.rb +343 -74
  131. data/lib/mail/version.rb +2 -2
  132. data/lib/mail/yaml.rb +30 -0
  133. data/lib/mail.rb +5 -35
  134. metadata +111 -66
  135. data/CHANGELOG.rdoc +0 -803
  136. data/CONTRIBUTING.md +0 -60
  137. data/Dependencies.txt +0 -2
  138. data/Gemfile +0 -14
  139. data/Rakefile +0 -29
  140. data/TODO.rdoc +0 -9
  141. data/lib/mail/core_extensions/smtp.rb +0 -25
  142. data/lib/mail/core_extensions/string/access.rb +0 -146
  143. data/lib/mail/core_extensions/string/multibyte.rb +0 -79
  144. data/lib/mail/core_extensions/string.rb +0 -21
  145. data/lib/mail/fields/common/address_container.rb +0 -17
  146. data/lib/mail/fields/common/common_address.rb +0 -136
  147. data/lib/mail/fields/common/common_date.rb +0 -36
  148. data/lib/mail/fields/common/common_field.rb +0 -61
  149. data/lib/mail/fields/common/common_message_id.rb +0 -49
  150. data/lib/mail/multibyte/exceptions.rb +0 -9
  151. data/lib/mail/parsers/ragel/common.rl +0 -185
  152. data/lib/mail/parsers/ragel/parser_info.rb +0 -61
  153. data/lib/mail/parsers/ragel/ruby/machines/address_lists_machine.rb +0 -14864
  154. data/lib/mail/parsers/ragel/ruby/machines/address_lists_machine.rb.rl +0 -37
  155. data/lib/mail/parsers/ragel/ruby/machines/content_disposition_machine.rb +0 -751
  156. data/lib/mail/parsers/ragel/ruby/machines/content_disposition_machine.rb.rl +0 -37
  157. data/lib/mail/parsers/ragel/ruby/machines/content_location_machine.rb +0 -614
  158. data/lib/mail/parsers/ragel/ruby/machines/content_location_machine.rb.rl +0 -37
  159. data/lib/mail/parsers/ragel/ruby/machines/content_transfer_encoding_machine.rb +0 -447
  160. data/lib/mail/parsers/ragel/ruby/machines/content_transfer_encoding_machine.rb.rl +0 -37
  161. data/lib/mail/parsers/ragel/ruby/machines/content_type_machine.rb +0 -825
  162. data/lib/mail/parsers/ragel/ruby/machines/content_type_machine.rb.rl +0 -37
  163. data/lib/mail/parsers/ragel/ruby/machines/date_time_machine.rb +0 -817
  164. data/lib/mail/parsers/ragel/ruby/machines/date_time_machine.rb.rl +0 -37
  165. data/lib/mail/parsers/ragel/ruby/machines/envelope_from_machine.rb +0 -2149
  166. data/lib/mail/parsers/ragel/ruby/machines/envelope_from_machine.rb.rl +0 -37
  167. data/lib/mail/parsers/ragel/ruby/machines/message_ids_machine.rb +0 -1570
  168. data/lib/mail/parsers/ragel/ruby/machines/message_ids_machine.rb.rl +0 -37
  169. data/lib/mail/parsers/ragel/ruby/machines/mime_version_machine.rb +0 -440
  170. data/lib/mail/parsers/ragel/ruby/machines/mime_version_machine.rb.rl +0 -37
  171. data/lib/mail/parsers/ragel/ruby/machines/phrase_lists_machine.rb +0 -564
  172. data/lib/mail/parsers/ragel/ruby/machines/phrase_lists_machine.rb.rl +0 -37
  173. data/lib/mail/parsers/ragel/ruby/machines/rb_actions.rl +0 -51
  174. data/lib/mail/parsers/ragel/ruby/machines/received_machine.rb +0 -5144
  175. data/lib/mail/parsers/ragel/ruby/machines/received_machine.rb.rl +0 -37
  176. data/lib/mail/parsers/ragel/ruby/parser.rb.rl.erb +0 -37
  177. data/lib/mail/parsers/ragel/ruby.rb +0 -40
  178. data/lib/mail/parsers/ragel.rb +0 -18
  179. data/lib/mail/version_specific/ruby_1_8.rb +0 -126
  180. data/lib/mail/version_specific/ruby_1_9.rb +0 -226
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
- require 'mail/check_delivery_params'
2
+ require 'mail/smtp_envelope'
3
3
 
4
4
  module Mail
5
5
  # A delivery method implementation which sends via sendmail.
@@ -40,53 +40,94 @@ module Mail
40
40
  class Sendmail
41
41
  DEFAULTS = {
42
42
  :location => '/usr/sbin/sendmail',
43
- :arguments => '-i'
43
+ :arguments => %w[ -i ]
44
44
  }
45
45
 
46
46
  attr_accessor :settings
47
47
 
48
+ class DeliveryError < StandardError
49
+ end
50
+
48
51
  def initialize(values)
52
+ if values[:arguments].is_a?(String)
53
+ deprecation_warn.call \
54
+ 'Initializing Mail::Sendmail with :arguments of type String is deprecated.' \
55
+ ' Instead ensure :arguments is an array of strings, e.g. ["-i", "-t"]'
56
+ end
49
57
  self.settings = self.class::DEFAULTS.merge(values)
50
58
  end
51
59
 
60
+ def destinations_for(envelope)
61
+ envelope.to
62
+ end
63
+
52
64
  def deliver!(mail)
53
- smtp_from, smtp_to, message = Mail::CheckDeliveryParams.check(mail)
65
+ envelope = Mail::SmtpEnvelope.new(mail)
54
66
 
55
- from = "-f #{self.class.shellquote(smtp_from)}"
56
- to = smtp_to.map { |_to| self.class.shellquote(_to) }.join(' ')
67
+ arguments = settings[:arguments]
68
+ if arguments.is_a? String
69
+ return old_deliver(envelope)
70
+ end
57
71
 
58
- arguments = "#{settings[:arguments]} #{from} --"
59
- self.class.call(settings[:location], arguments, to, message)
60
- end
72
+ command = [settings[:location]]
73
+ command.concat Array(arguments)
74
+ command.concat [ '-f', envelope.from ] if envelope.from
61
75
 
62
- def self.call(path, arguments, destinations, encoded_message)
63
- popen "#{path} #{arguments} #{destinations}" do |io|
64
- io.puts ::Mail::Utilities.to_lf(encoded_message)
76
+ if destinations = destinations_for(envelope)
77
+ command.push '--'
78
+ command.concat destinations
79
+ end
80
+
81
+ popen(command) do |io|
82
+ io.puts ::Mail::Utilities.binary_unsafe_to_lf(envelope.message)
65
83
  io.flush
66
84
  end
67
85
  end
68
86
 
69
- if RUBY_VERSION < '1.9.0'
70
- def self.popen(command, &block)
71
- IO.popen "#{command} 2>&1", 'w+', &block
87
+ private
88
+ def popen(command, &block)
89
+ IO.popen(command, 'w+', :err => :out, &block).tap do
90
+ if $?.exitstatus != 0
91
+ raise DeliveryError, "Delivery failed with exitstatus #{$?.exitstatus}: #{command.inspect}"
92
+ end
93
+ end
72
94
  end
73
- else
74
- def self.popen(command, &block)
75
- IO.popen command, 'w+', :err => :out, &block
95
+
96
+ #+ support for delivery using string arguments (deprecated)
97
+ def old_deliver(envelope)
98
+ smtp_from = envelope.from
99
+ smtp_to = destinations_for(envelope)
100
+
101
+ from = "-f #{shellquote(smtp_from)}" if smtp_from
102
+ destination = smtp_to.map { |to| shellquote(to) }.join(' ')
103
+
104
+ arguments = "#{settings[:arguments]} #{from} --"
105
+ command = "#{settings[:location]} #{arguments} #{destination}"
106
+ popen command do |io|
107
+ io.puts ::Mail::Utilities.binary_unsafe_to_lf(envelope.message)
108
+ io.flush
76
109
  end
77
110
  end
78
111
 
79
112
  # The following is an adaptation of ruby 1.9.2's shellwords.rb file,
80
- # it is modified to include '+' in the allowed list to allow for
81
- # sendmail to accept email addresses as the sender with a + in them.
82
- def self.shellquote(address)
113
+ # with the following modifications:
114
+ #
115
+ # - Wraps in double quotes
116
+ # - Allows '+' to accept email addresses with them
117
+ # - Allows '~' as it is not unescaped in double quotes
118
+ def shellquote(address)
83
119
  # Process as a single byte sequence because not all shell
84
120
  # implementations are multibyte aware.
85
121
  #
86
122
  # A LF cannot be escaped with a backslash because a backslash + LF
87
123
  # combo is regarded as line continuation and simply ignored. Strip it.
88
- escaped = address.gsub(/([^A-Za-z0-9_\s\+\-.,:\/@])/n, "\\\\\\1").gsub("\n", '')
124
+ escaped = address.gsub(/([^A-Za-z0-9_\s\+\-.,:\/@~])/n, "\\\\\\1").gsub("\n", '')
89
125
  %("#{escaped}")
90
126
  end
127
+ #- support for delivery using string arguments
128
+
129
+ def deprecation_warn
130
+ defined?(ActiveSupport::Deprecation.warn) ? ActiveSupport::Deprecation.method(:warn) : Kernel.method(:warn)
131
+ end
91
132
  end
92
133
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
- require 'mail/check_delivery_params'
2
+ require 'mail/smtp_envelope'
3
3
 
4
4
  module Mail
5
5
  # == Sending Email with SMTP
@@ -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
  #
@@ -77,64 +76,90 @@ module Mail
77
76
  class SMTP
78
77
  attr_accessor :settings
79
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 => 5,
92
+ :read_timeout => 5
93
+ }
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
- # Send the message via SMTP.
95
- # The from and to attributes are optional. If not set, they are retrieve from the Message.
96
99
  def deliver!(mail)
97
- smtp_from, smtp_to, message = Mail::CheckDeliveryParams.check(mail)
98
-
99
- smtp = Net::SMTP.new(settings[:address], settings[:port])
100
- if settings[:tls] || settings[:ssl]
101
- if smtp.respond_to?(:enable_tls)
102
- smtp.enable_tls(ssl_context)
103
- end
104
- elsif settings[:enable_starttls_auto]
105
- if smtp.respond_to?(:enable_starttls_auto)
106
- smtp.enable_starttls_auto(ssl_context)
107
- end
100
+ response = start_smtp_session do |smtp|
101
+ Mail::SMTPConnection.new(:connection => smtp, :return_response => true).deliver!(mail)
108
102
  end
109
103
 
110
- response = nil
111
- smtp.start(settings[:domain], settings[:user_name], settings[:password], settings[:authentication]) do |smtp_obj|
112
- response = smtp_obj.sendmail(message, smtp_from, smtp_to)
113
- end
114
-
115
- if settings[:return_response]
116
- response
117
- else
118
- self
119
- end
104
+ settings[:return_response] ? response : self
120
105
  end
121
106
 
122
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
123
111
 
124
- # Allow SSL context to be configured via settings, for Ruby >= 1.9
125
- # Just returns openssl verify mode for Ruby 1.8.x
126
- def ssl_context
127
- openssl_verify_mode = settings[:openssl_verify_mode]
112
+ def build_smtp_session
113
+ Net::SMTP.new(settings[:address], settings[:port]).tap do |smtp|
114
+ tls = settings[:tls] || settings[:ssl]
115
+ if !tls.nil?
116
+ case tls
117
+ when true
118
+ smtp.enable_tls(ssl_context)
119
+ when false
120
+ smtp.disable_tls
121
+ else
122
+ raise ArgumentError, "Unrecognized :tls value #{settings[:tls].inspect}; expected true, false, or nil"
123
+ end
124
+ elsif settings.include?(:enable_starttls) && !settings[:enable_starttls].nil?
125
+ case settings[:enable_starttls]
126
+ when true
127
+ smtp.enable_starttls(ssl_context)
128
+ when false
129
+ smtp.disable_starttls
130
+ else
131
+ raise ArgumentError, "Unrecognized :enable_starttls value #{settings[:enable_starttls].inspect}; expected true, false, or nil"
132
+ end
133
+ elsif settings.include?(:enable_starttls_auto) && !settings[:enable_starttls_auto].nil?
134
+ case settings[:enable_starttls_auto]
135
+ when true
136
+ smtp.enable_starttls_auto(ssl_context)
137
+ when false
138
+ smtp.disable_starttls
139
+ else
140
+ raise ArgumentError, "Unrecognized :enable_starttls_auto value #{settings[:enable_starttls_auto].inspect}; expected true, false, or nil"
141
+ end
142
+ end
128
143
 
129
- if openssl_verify_mode.kind_of?(String)
130
- openssl_verify_mode = "OpenSSL::SSL::VERIFY_#{openssl_verify_mode.upcase}".constantize
144
+ smtp.open_timeout = settings[:open_timeout] if settings[:open_timeout]
145
+ smtp.read_timeout = settings[:read_timeout] if settings[:read_timeout]
146
+ end
131
147
  end
132
148
 
133
- context = Net::SMTP.default_ssl_context
134
- context.verify_mode = openssl_verify_mode
135
- context.ca_path = settings[:ca_path] if settings[:ca_path]
136
- context.ca_file = settings[:ca_file] if settings[:ca_file]
137
- context
138
- end
149
+ # Allow SSL context to be configured via settings, for Ruby >= 1.9
150
+ # Just returns openssl verify mode for Ruby 1.8.x
151
+ def ssl_context
152
+ openssl_verify_mode = settings[:openssl_verify_mode]
153
+
154
+ if openssl_verify_mode.kind_of?(String)
155
+ openssl_verify_mode = OpenSSL::SSL.const_get("VERIFY_#{openssl_verify_mode.upcase}")
156
+ end
157
+
158
+ context = Net::SMTP.default_ssl_context
159
+ context.verify_mode = openssl_verify_mode if openssl_verify_mode
160
+ context.ca_path = settings[:ca_path] if settings[:ca_path]
161
+ context.ca_file = settings[:ca_file] if settings[:ca_file]
162
+ context
163
+ end
139
164
  end
140
165
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
- require 'mail/check_delivery_params'
2
+ require 'mail/smtp_envelope'
3
3
 
4
4
  module Mail
5
5
  # == Sending Email with SMTP
@@ -49,9 +49,8 @@ module Mail
49
49
  # Send the message via SMTP.
50
50
  # The from and to attributes are optional. If not set, they are retrieve from the Message.
51
51
  def deliver!(mail)
52
- smtp_from, smtp_to, message = Mail::CheckDeliveryParams.check(mail)
53
- response = smtp.sendmail(message, smtp_from, smtp_to)
54
-
52
+ envelope = Mail::SmtpEnvelope.new(mail)
53
+ response = smtp.sendmail(envelope.message, envelope.from, envelope.to)
55
54
  settings[:return_response] ? response : self
56
55
  end
57
56
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
- require 'mail/check_delivery_params'
2
+ require 'mail/smtp_envelope'
3
3
 
4
4
  module Mail
5
5
  # The TestMailer is a bare bones mailer that does nothing. It is useful
@@ -35,7 +35,9 @@ module Mail
35
35
  end
36
36
 
37
37
  def deliver!(mail)
38
- Mail::CheckDeliveryParams.check(mail)
38
+ # Create the envelope to validate it
39
+ Mail::SmtpEnvelope.new(mail)
40
+
39
41
  Mail::TestMailer.deliveries << mail
40
42
  end
41
43
  end
@@ -11,8 +11,8 @@ module Mail
11
11
  # count: number of emails to retrieve. The default value is 1.
12
12
  # order: order of emails returned. Possible values are :asc or :desc. Default value is :asc.
13
13
  #
14
- def first(options = {}, &block)
15
- options ||= {}
14
+ def first(options = nil, &block)
15
+ options = options ? Hash[options] : {}
16
16
  options[:what] = :first
17
17
  options[:count] ||= 1
18
18
  find(options, &block)
@@ -24,8 +24,8 @@ module Mail
24
24
  # count: number of emails to retrieve. The default value is 1.
25
25
  # order: order of emails returned. Possible values are :asc or :desc. Default value is :asc.
26
26
  #
27
- def last(options = {}, &block)
28
- options ||= {}
27
+ def last(options = nil, &block)
28
+ options = options ? Hash[options] : {}
29
29
  options[:what] = :last
30
30
  options[:count] ||= 1
31
31
  find(options, &block)
@@ -36,8 +36,8 @@ module Mail
36
36
  # Possible options:
37
37
  # order: order of emails returned. Possible values are :asc or :desc. Default value is :asc.
38
38
  #
39
- def all(options = {}, &block)
40
- options ||= {}
39
+ def all(options = nil, &block)
40
+ options = options ? Hash[options] : {}
41
41
  options[:count] = :all
42
42
  find(options, &block)
43
43
  end
@@ -53,8 +53,8 @@ module Mail
53
53
  # delete_after_find: flag for whether to delete each retreived email after find. Default
54
54
  # is true. Call #find if you would like this to default to false.
55
55
  #
56
- def find_and_delete(options = {}, &block)
57
- options ||= {}
56
+ def find_and_delete(options = nil, &block)
57
+ options = options ? Hash[options] : {}
58
58
  options[:delete_after_find] ||= true
59
59
  find(options, &block)
60
60
  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
- def find(options={}, &block)
73
+ def find(options=nil, &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
@@ -136,7 +142,7 @@ module Mail
136
142
 
137
143
  # Set default options
138
144
  def validate_options(options)
139
- options ||= {}
145
+ options = options ? Hash[options] : {}
140
146
  options[:mailbox] ||= 'INBOX'
141
147
  options[:count] ||= 10
142
148
  options[:order] ||= :asc
@@ -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
@@ -56,7 +57,7 @@ module Mail
56
57
  # delete_after_find: flag for whether to delete each retreived email after find. Default
57
58
  # is false. Use #find_and_delete if you would like this to default to true.
58
59
  #
59
- def find(options = {}, &block)
60
+ def find(options = nil, &block)
60
61
  options = validate_options(options)
61
62
 
62
63
  start do |pop3|
@@ -112,7 +113,7 @@ module Mail
112
113
 
113
114
  # Set default options
114
115
  def validate_options(options)
115
- options ||= {}
116
+ options = options ? Hash[options] : {}
116
117
  options[:count] ||= 10
117
118
  options[:order] ||= :asc
118
119
  options[:what] ||= :first
@@ -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
@@ -17,7 +17,8 @@ module Mail
17
17
  @@emails = []
18
18
  end
19
19
 
20
- def find(options = {}, &block)
20
+ def find(options = nil, &block)
21
+ options = options ? Hash[options] : {}
21
22
  options[:count] ||= :all
22
23
  options[:order] ||= :asc
23
24
  options[:what] ||= :first
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