mail 2.5.3 → 2.5.4

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of mail might be problematic. Click here for more details.

Files changed (66) hide show
  1. data/CHANGELOG.rdoc +65 -0
  2. data/CONTRIBUTING.md +4 -4
  3. data/Gemfile +7 -20
  4. data/MIT-LICENSE +20 -0
  5. data/README.md +10 -9
  6. data/Rakefile +3 -20
  7. data/lib/VERSION +1 -1
  8. data/lib/mail.rb +0 -1
  9. data/lib/mail/attachments_list.rb +2 -2
  10. data/lib/mail/body.rb +4 -4
  11. data/lib/mail/check_delivery_params.rb +12 -22
  12. data/lib/mail/core_extensions/object.rb +8 -8
  13. data/lib/mail/core_extensions/smtp.rb +12 -13
  14. data/lib/mail/core_extensions/string.rb +4 -4
  15. data/lib/mail/elements/address.rb +13 -5
  16. data/lib/mail/elements/envelope_from_element.rb +15 -2
  17. data/lib/mail/encodings.rb +61 -28
  18. data/lib/mail/encodings/quoted_printable.rb +4 -3
  19. data/lib/mail/field.rb +10 -11
  20. data/lib/mail/fields/bcc_field.rb +2 -2
  21. data/lib/mail/fields/cc_field.rb +2 -2
  22. data/lib/mail/fields/comments_field.rb +1 -1
  23. data/lib/mail/fields/common/common_address.rb +13 -3
  24. data/lib/mail/fields/common/common_field.rb +4 -4
  25. data/lib/mail/fields/content_id_field.rb +1 -2
  26. data/lib/mail/fields/content_transfer_encoding_field.rb +2 -2
  27. data/lib/mail/fields/content_type_field.rb +1 -1
  28. data/lib/mail/fields/date_field.rb +1 -1
  29. data/lib/mail/fields/from_field.rb +2 -2
  30. data/lib/mail/fields/in_reply_to_field.rb +2 -1
  31. data/lib/mail/fields/message_id_field.rb +2 -3
  32. data/lib/mail/fields/references_field.rb +2 -1
  33. data/lib/mail/fields/reply_to_field.rb +2 -2
  34. data/lib/mail/fields/resent_bcc_field.rb +2 -2
  35. data/lib/mail/fields/resent_cc_field.rb +2 -2
  36. data/lib/mail/fields/resent_from_field.rb +2 -2
  37. data/lib/mail/fields/resent_sender_field.rb +2 -2
  38. data/lib/mail/fields/resent_to_field.rb +2 -2
  39. data/lib/mail/fields/sender_field.rb +7 -7
  40. data/lib/mail/fields/to_field.rb +2 -2
  41. data/lib/mail/fields/unstructured_field.rb +1 -1
  42. data/lib/mail/header.rb +5 -1
  43. data/lib/mail/message.rb +133 -37
  44. data/lib/mail/multibyte/chars.rb +2 -2
  45. data/lib/mail/multibyte/unicode.rb +5 -3
  46. data/lib/mail/network/delivery_methods/exim.rb +1 -6
  47. data/lib/mail/network/delivery_methods/file_delivery.rb +1 -1
  48. data/lib/mail/network/delivery_methods/sendmail.rb +32 -10
  49. data/lib/mail/network/delivery_methods/smtp.rb +35 -34
  50. data/lib/mail/network/delivery_methods/smtp_connection.rb +6 -6
  51. data/lib/mail/network/delivery_methods/test_mailer.rb +2 -2
  52. data/lib/mail/parsers/content_transfer_encoding.rb +81 -42
  53. data/lib/mail/parsers/content_transfer_encoding.treetop +4 -6
  54. data/lib/mail/parsers/content_type.rb +16 -12
  55. data/lib/mail/parsers/content_type.treetop +2 -2
  56. data/lib/mail/parsers/rfc2045.rb +12 -55
  57. data/lib/mail/parsers/rfc2045.treetop +1 -2
  58. data/lib/mail/parsers/rfc2822.rb +50 -50
  59. data/lib/mail/parsers/rfc2822.treetop +19 -21
  60. data/lib/mail/part.rb +6 -2
  61. data/lib/mail/patterns.rb +1 -0
  62. data/lib/mail/utilities.rb +25 -17
  63. data/lib/mail/version_specific/ruby_1_8.rb +5 -1
  64. data/lib/mail/version_specific/ruby_1_9.rb +46 -21
  65. metadata +57 -8
  66. data/lib/mail/core_extensions/shell_escape.rb +0 -56
@@ -364,7 +364,7 @@ module Mail #:nodoc:
364
364
  # "ÉL QUE SE ENTERÓ".mb_chars.titleize # => "Él Que Se Enteró"
365
365
  # "日本語".mb_chars.titleize # => "日本語"
366
366
  def titleize
367
- chars(downcase.to_s.gsub(/\b('?[\S])/u) { Unicode.apply_mapping $1, :uppercase_mapping })
367
+ chars(downcase.to_s.gsub(/\b('?\S)/u) { Unicode.apply_mapping $1, :uppercase_mapping })
368
368
  end
369
369
  alias_method :titlecase, :titleize
370
370
 
@@ -412,7 +412,7 @@ module Mail #:nodoc:
412
412
  chars(Unicode.tidy_bytes(@wrapped_string, force))
413
413
  end
414
414
 
415
- %w(capitalize downcase lstrip reverse rstrip slice strip tidy_bytes upcase).each do |method|
415
+ %w(capitalize downcase lstrip reverse rstrip slice strip tidy_bytes upcase).each do |method|
416
416
  # Only define a corresponding bang method for methods defined in the proxy; On 1.9 the proxy will
417
417
  # exclude lstrip!, rstrip! and strip! because they are already work as expected on multibyte strings.
418
418
  if public_method_defined?(method)
@@ -391,8 +391,10 @@ module Mail
391
391
  end
392
392
  end
393
393
 
394
- module ActiveSupport
395
- unless const_defined?(:Multibyte)
396
- Multibyte = Mail::Multibyte
394
+ unless defined?(ActiveSupport)
395
+ module ActiveSupport
396
+ unless const_defined?(:Multibyte)
397
+ Multibyte = Mail::Multibyte
398
+ end
397
399
  end
398
400
  end
@@ -1,5 +1,3 @@
1
- require 'mail/check_delivery_params'
2
-
3
1
  module Mail
4
2
 
5
3
  # A delivery method implementation which sends via exim.
@@ -38,16 +36,13 @@ module Mail
38
36
  #
39
37
  # mail.deliver!
40
38
  class Exim < Sendmail
41
- include Mail::CheckDeliveryParams
42
-
43
39
  def initialize(values)
44
40
  self.settings = { :location => '/usr/sbin/exim',
45
41
  :arguments => '-i -t' }.merge(values)
46
42
  end
47
43
 
48
44
  def self.call(path, arguments, destinations, mail)
49
- check_params(mail)
50
- IO.popen("#{path} #{arguments}", "w+") do |io|
45
+ popen "#{path} #{arguments}" do |io|
51
46
  io.puts mail.encoded.to_lf
52
47
  io.flush
53
48
  end
@@ -28,7 +28,7 @@ module Mail
28
28
  attr_accessor :settings
29
29
 
30
30
  def deliver!(mail)
31
- check_params(mail)
31
+ check_delivery_params(mail)
32
32
 
33
33
  if ::File.respond_to?(:makedirs)
34
34
  ::File.makedirs settings[:location]
@@ -41,27 +41,49 @@ module Mail
41
41
 
42
42
  def initialize(values)
43
43
  self.settings = { :location => '/usr/sbin/sendmail',
44
- :arguments => '-i -t' }.merge(values)
44
+ :arguments => '-i' }.merge(values)
45
45
  end
46
46
 
47
47
  attr_accessor :settings
48
48
 
49
49
  def deliver!(mail)
50
- check_params(mail)
50
+ smtp_from, smtp_to, message = check_delivery_params(mail)
51
51
 
52
- envelope_from = mail.return_path || mail.sender || mail.from_addrs.first
53
- return_path = "-f " + '"' + envelope_from.escape_for_shell + '"' if envelope_from
52
+ from = "-f #{self.class.shellquote(smtp_from)}"
53
+ to = smtp_to.map { |to| self.class.shellquote(to) }.join(' ')
54
54
 
55
- arguments = [settings[:arguments], return_path].compact.join(" ")
56
-
57
- self.class.call(settings[:location], arguments, mail.destinations.collect(&:escape_for_shell).join(" "), mail)
55
+ arguments = "#{settings[:arguments]} #{from} --"
56
+ self.class.call(settings[:location], arguments, to, message)
58
57
  end
59
58
 
60
- def self.call(path, arguments, destinations, mail)
61
- IO.popen("#{path} #{arguments} #{destinations}", "w+") do |io|
62
- io.puts mail.encoded.to_lf
59
+ def self.call(path, arguments, destinations, encoded_message)
60
+ popen "#{path} #{arguments} #{destinations}" do |io|
61
+ io.puts encoded_message.to_lf
63
62
  io.flush
64
63
  end
65
64
  end
65
+
66
+ if RUBY_VERSION < '1.9.0'
67
+ def self.popen(command, &block)
68
+ IO.popen "#{command} 2>&1", 'w+', &block
69
+ end
70
+ else
71
+ def self.popen(command, &block)
72
+ IO.popen command, 'w+', :err => :out, &block
73
+ end
74
+ end
75
+
76
+ # The following is an adaptation of ruby 1.9.2's shellwords.rb file,
77
+ # it is modified to include '+' in the allowed list to allow for
78
+ # sendmail to accept email addresses as the sender with a + in them.
79
+ def self.shellquote(address)
80
+ # Process as a single byte sequence because not all shell
81
+ # implementations are multibyte aware.
82
+ #
83
+ # A LF cannot be escaped with a backslash because a backslash + LF
84
+ # combo is regarded as line continuation and simply ignored. Strip it.
85
+ escaped = address.gsub(/([^A-Za-z0-9_\s\+\-.,:\/@])/n, "\\\\\\1").gsub("\n", '')
86
+ %("#{escaped}")
87
+ end
66
88
  end
67
89
  end
@@ -89,57 +89,58 @@ module Mail
89
89
  :tls => nil
90
90
  }.merge!(values)
91
91
  end
92
-
92
+
93
93
  attr_accessor :settings
94
-
94
+
95
95
  # Send the message via SMTP.
96
96
  # The from and to attributes are optional. If not set, they are retrieve from the Message.
97
97
  def deliver!(mail)
98
- envelope_from, destinations, message = check_params(mail)
98
+ smtp_from, smtp_to, message = check_delivery_params(mail)
99
99
 
100
100
  smtp = Net::SMTP.new(settings[:address], settings[:port])
101
101
  if settings[:tls] || settings[:ssl]
102
102
  if smtp.respond_to?(:enable_tls)
103
- unless settings[:openssl_verify_mode]
104
- smtp.enable_tls
105
- else
106
- openssl_verify_mode = settings[:openssl_verify_mode]
107
- if openssl_verify_mode.kind_of?(String)
108
- openssl_verify_mode = "OpenSSL::SSL::VERIFY_#{openssl_verify_mode.upcase}".constantize
109
- end
110
- context = Net::SMTP.default_ssl_context
111
- context.verify_mode = openssl_verify_mode
112
- smtp.enable_tls(context)
113
- end
103
+ smtp.enable_tls(ssl_context)
114
104
  end
115
105
  elsif settings[:enable_starttls_auto]
116
- if smtp.respond_to?(:enable_starttls_auto)
117
- unless settings[:openssl_verify_mode]
118
- smtp.enable_starttls_auto
119
- else
120
- openssl_verify_mode = settings[:openssl_verify_mode]
121
- if openssl_verify_mode.kind_of?(String)
122
- openssl_verify_mode = "OpenSSL::SSL::VERIFY_#{openssl_verify_mode.upcase}".constantize
123
- end
124
- if RUBY_VERSION >= '1.9.0'
125
- context = Net::SMTP.default_ssl_context
126
- context.verify_mode = openssl_verify_mode
127
- smtp.enable_tls(context)
128
- else
129
- smtp.enable_tls(openssl_verify_mode)
130
- end
131
- end
106
+ if smtp.respond_to?(:enable_starttls_auto)
107
+ smtp.enable_starttls_auto(ssl_context)
132
108
  end
133
109
  end
134
-
110
+
135
111
  response = nil
136
112
  smtp.start(settings[:domain], settings[:user_name], settings[:password], settings[:authentication]) do |smtp_obj|
137
- response = smtp_obj.sendmail(message, envelope_from, destinations)
113
+ response = smtp_obj.sendmail(message, smtp_from, smtp_to)
138
114
  end
139
115
 
140
- return settings[:return_response] ? response : self
116
+ if settings[:return_response]
117
+ response
118
+ else
119
+ self
120
+ end
141
121
  end
142
122
 
143
-
123
+
124
+ private
125
+
126
+ # Allow SSL context to be configured via settings, for Ruby >= 1.9
127
+ # Just returns openssl verify mode for Ruby 1.8.x
128
+ def ssl_context
129
+ openssl_verify_mode = settings[:openssl_verify_mode]
130
+
131
+ if openssl_verify_mode.kind_of?(String)
132
+ openssl_verify_mode = "OpenSSL::SSL::VERIFY_#{openssl_verify_mode.upcase}".constantize
133
+ end
134
+
135
+ if RUBY_VERSION < '1.9.0'
136
+ openssl_verify_mode
137
+ else
138
+ context = Net::SMTP.default_ssl_context
139
+ context.verify_mode = openssl_verify_mode
140
+ context.ca_path = settings[:ca_path] if settings[:ca_path]
141
+ context.ca_file = settings[:ca_file] if settings[:ca_file]
142
+ context
143
+ end
144
+ end
144
145
  end
145
146
  end
@@ -44,18 +44,18 @@ module Mail
44
44
  self.smtp = values[:connection]
45
45
  self.settings = values
46
46
  end
47
-
47
+
48
48
  attr_accessor :smtp
49
49
  attr_accessor :settings
50
-
50
+
51
51
  # Send the message via SMTP.
52
52
  # The from and to attributes are optional. If not set, they are retrieve from the Message.
53
53
  def deliver!(mail)
54
- envelope_from, destinations, message = check_params(mail)
55
- response = smtp.sendmail(message, envelope_from, destinations)
54
+ smtp_from, smtp_to, message = check_delivery_params(mail)
55
+ response = smtp.sendmail(message, smtp_from, smtp_to)
56
56
 
57
- settings[:return_response] ? response : self
57
+ settings[:return_response] ? response : self
58
58
  end
59
-
59
+
60
60
  end
61
61
  end
@@ -30,13 +30,13 @@ module Mail
30
30
  end
31
31
 
32
32
  def initialize(values)
33
- @settings = {}
33
+ @settings = values.dup
34
34
  end
35
35
 
36
36
  attr_accessor :settings
37
37
 
38
38
  def deliver!(mail)
39
- check_params(mail)
39
+ check_delivery_params(mail)
40
40
  Mail::TestMailer.deliveries << mail
41
41
  end
42
42
 
@@ -85,19 +85,6 @@ module Mail
85
85
  r0
86
86
  end
87
87
 
88
- module Encoding0
89
- def ietf_token
90
- elements[0]
91
- end
92
-
93
- end
94
-
95
- module Encoding1
96
- def text_value
97
- ietf_token.text_value
98
- end
99
- end
100
-
101
88
  def _nt_encoding
102
89
  start_index = index
103
90
  if node_cache[:encoding].has_key?(index)
@@ -110,41 +97,93 @@ module Mail
110
97
  end
111
98
 
112
99
  i0 = index
113
- i1, s1 = index, []
114
- r2 = _nt_ietf_token
115
- s1 << r2
116
- if r2
117
- if has_terminal?("s", false, index)
118
- r4 = instantiate_node(SyntaxNode,input, index...(index + 1))
119
- @index += 1
120
- else
121
- terminal_parse_failure("s")
122
- r4 = nil
123
- end
124
- if r4
125
- r3 = r4
126
- else
127
- r3 = instantiate_node(SyntaxNode,input, index...index)
128
- end
129
- s1 << r3
130
- end
131
- if s1.last
132
- r1 = instantiate_node(SyntaxNode,input, i1...index, s1)
133
- r1.extend(Encoding0)
134
- r1.extend(Encoding1)
100
+ if has_terminal?("7bits", false, index)
101
+ r1 = instantiate_node(SyntaxNode,input, index...(index + 5))
102
+ @index += 5
135
103
  else
136
- @index = i1
104
+ terminal_parse_failure("7bits")
137
105
  r1 = nil
138
106
  end
139
107
  if r1
140
108
  r0 = r1
141
109
  else
142
- r5 = _nt_custom_x_token
143
- if r5
144
- r0 = r5
110
+ if has_terminal?("8bits", false, index)
111
+ r2 = instantiate_node(SyntaxNode,input, index...(index + 5))
112
+ @index += 5
113
+ else
114
+ terminal_parse_failure("8bits")
115
+ r2 = nil
116
+ end
117
+ if r2
118
+ r0 = r2
145
119
  else
146
- @index = i0
147
- r0 = nil
120
+ if has_terminal?("7bit", false, index)
121
+ r3 = instantiate_node(SyntaxNode,input, index...(index + 4))
122
+ @index += 4
123
+ else
124
+ terminal_parse_failure("7bit")
125
+ r3 = nil
126
+ end
127
+ if r3
128
+ r0 = r3
129
+ else
130
+ if has_terminal?("8bit", false, index)
131
+ r4 = instantiate_node(SyntaxNode,input, index...(index + 4))
132
+ @index += 4
133
+ else
134
+ terminal_parse_failure("8bit")
135
+ r4 = nil
136
+ end
137
+ if r4
138
+ r0 = r4
139
+ else
140
+ if has_terminal?("binary", false, index)
141
+ r5 = instantiate_node(SyntaxNode,input, index...(index + 6))
142
+ @index += 6
143
+ else
144
+ terminal_parse_failure("binary")
145
+ r5 = nil
146
+ end
147
+ if r5
148
+ r0 = r5
149
+ else
150
+ if has_terminal?("quoted-printable", false, index)
151
+ r6 = instantiate_node(SyntaxNode,input, index...(index + 16))
152
+ @index += 16
153
+ else
154
+ terminal_parse_failure("quoted-printable")
155
+ r6 = nil
156
+ end
157
+ if r6
158
+ r0 = r6
159
+ else
160
+ if has_terminal?("base64", false, index)
161
+ r7 = instantiate_node(SyntaxNode,input, index...(index + 6))
162
+ @index += 6
163
+ else
164
+ terminal_parse_failure("base64")
165
+ r7 = nil
166
+ end
167
+ if r7
168
+ r0 = r7
169
+ else
170
+ r8 = _nt_ietf_token
171
+ if r8
172
+ r0 = r8
173
+ else
174
+ r9 = _nt_custom_x_token
175
+ if r9
176
+ r0 = r9
177
+ else
178
+ @index = i0
179
+ r0 = nil
180
+ end
181
+ end
182
+ end
183
+ end
184
+ end
185
+ end
186
+ end
148
187
  end
149
188
  end
150
189
 
@@ -159,4 +198,4 @@ module Mail
159
198
  include ContentTransferEncoding
160
199
  end
161
200
 
162
- end
201
+ end
@@ -9,12 +9,10 @@ module Mail
9
9
  end
10
10
 
11
11
  rule encoding
12
- ietf_token "s"? {
13
- def text_value
14
- ietf_token.text_value
15
- end
16
- } / custom_x_token
12
+ "7bits" / "8bits" /
13
+ "7bit" / "8bit" / "binary" / "quoted-printable" / "base64" /
14
+ ietf_token / custom_x_token
17
15
  end
18
16
 
19
17
  end
20
- end
18
+ end
@@ -82,18 +82,22 @@ module Mail
82
82
  r6 = _nt_CFWS
83
83
  s5 << r6
84
84
  if r6
85
- if has_terminal?(";", false, index)
86
- r8 = instantiate_node(SyntaxNode,input, index...(index + 1))
87
- @index += 1
88
- else
89
- terminal_parse_failure(";")
90
- r8 = nil
91
- end
92
- if r8
93
- r7 = r8
94
- else
95
- r7 = instantiate_node(SyntaxNode,input, index...index)
85
+ s7, i7 = [], index
86
+ loop do
87
+ if has_terminal?(";", false, index)
88
+ r8 = instantiate_node(SyntaxNode,input, index...(index + 1))
89
+ @index += 1
90
+ else
91
+ terminal_parse_failure(";")
92
+ r8 = nil
93
+ end
94
+ if r8
95
+ s7 << r8
96
+ else
97
+ break
98
+ end
96
99
  end
100
+ r7 = instantiate_node(SyntaxNode,input, i7...index, s7)
97
101
  s5 << r7
98
102
  if r7
99
103
  r9 = _nt_parameter
@@ -964,4 +968,4 @@ module Mail
964
968
  include ContentType
965
969
  end
966
970
 
967
- end
971
+ end