mail 2.6.4 → 2.6.6

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f91f133d2e44832ecef1cb4bfe9cc57391aedf84
4
- data.tar.gz: 23d0cdbc09cdbaafee76b01d7c3820a6c0dfb6d1
3
+ metadata.gz: fffa789ce57e01eb58d470854eef55242eae6f9c
4
+ data.tar.gz: fa95a3e43e7c7b80972dd81989688ed00ef5e22c
5
5
  SHA512:
6
- metadata.gz: c788407da309561bee6a59ec746efeea7c0cc8633206eb2085f08ad6b161df92475109a988de748e554248d2ca47e6cd31c3fd0394d0eddac5950e7bb28783a8
7
- data.tar.gz: 55b70f9d539420d254373c7abfccf6bc85228f34c38696086be363a36fb4f966415238aaa8e9ec9e6eed02207af2a3940b9f85c5f3076e735cd19e095764abc2
6
+ metadata.gz: '06621968e5681c087041b046f1f52cb7316116bedf04e38ab4255118249142488f768fba638c6fc2b99eb69d15a6d84823383f073f33bc8b05a6b3be635417d7'
7
+ data.tar.gz: f890a870876c79ca6014c8cccc84af35834cfc79576a2032aeef5a6f34ff183661e5fd73796b4693de53c1a288059e7733e359e7f0252548fe8c49e657f5bc7f
data/CHANGELOG.rdoc CHANGED
@@ -1,4 +1,20 @@
1
- == HEAD
1
+ == Version 2.6.6 - 2017-06-09 Jeremy Daer <jeremydaer@gmail.com>
2
+
3
+ Security:
4
+ * #1097 – SMTP security: prevent command injection via To/From addresses. (jeremy)
5
+
6
+ Bugs:
7
+ * #689 - Fix Exim delivery method broken by #477 in 2.5.4. (jethrogb)
8
+
9
+ == Version 2.6.5 - 2017-04-26 Jeremy Daer <jeremydaer@gmail.com>
10
+
11
+ Features:
12
+ * #1053 - Ruby 2.4.0 compatibility. Fixnum+Bignum unified as Integer. (peterkovacs)
13
+
14
+ Bugs:
15
+ * #605 - Fix Mail::Address#name for nil addresses (peterkovacs)
16
+ * #1003 - Fix decoding some b encoded headers on specific rubies that don't account for lack of base64 padding (kjg)
17
+ * #1023 - Fix double-quoting in display names. (garethrees)
2
18
 
3
19
  == Version 2.6.4 - Wed Mar 23 08:16 -0700 2016 Jeremy Daer <jeremydaer@gmail.com>
4
20
 
data/Gemfile CHANGED
@@ -1,11 +1,14 @@
1
- source "https://rubygems.org"
1
+ source 'https://rubygems.org'
2
2
 
3
3
  gemspec
4
4
 
5
- gem "tlsmail", "~> 0.0.1" if RUBY_VERSION <= "1.8.6"
6
- gem "jruby-openssl", :platforms => :jruby
5
+ gem 'tlsmail', '~> 0.0.1' if RUBY_VERSION <= '1.8.6'
6
+ gem 'jruby-openssl', :platforms => :jruby
7
+ gem 'rake', '< 11.0', :platforms => :ruby_18
8
+ gem 'rdoc', '< 4.3', :platforms => [ :ruby_18, :ruby_19 ]
9
+ gem 'mime-types', '< 2.0', :platforms => [ :ruby_18, :ruby_19 ]
7
10
 
8
11
  # For gems not required to run tests
9
12
  group :local_development, :test do
10
- gem "appraisal", "~> 1.0" unless RUBY_VERSION <= "1.8.7"
13
+ gem 'appraisal', '~> 1.0' unless RUBY_VERSION < '1.9'
11
14
  end
data/MIT-LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2009-2016 Mikel Lindsaar
1
+ Copyright (c) 2009-2017 Mikel Lindsaar
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
data/README.md CHANGED
@@ -42,22 +42,14 @@ me a nice email :)
42
42
  Compatibility
43
43
  -------------
44
44
 
45
- Every Mail commit is tested by Travis on the [following platforms](https://github.com/mikel/mail/blob/master/.travis.yml)
45
+ Mail supports Ruby 1.8.7+, including JRuby and Rubinius.
46
46
 
47
- * ruby-1.8.7 [ i686 ]
48
- * ruby-1.9.2 [ x86_64 ]
49
- * ruby-1.9.3 [ x86_64 ]
50
- * ruby-2.0.0 [ x86_64 ]
51
- * ruby-2.1.2 [ x86_64 ]
52
- * ruby-head [ x86_64 ]
53
- * jruby [ x86_64 ]
54
- * jruby-head [ x86_64 ]
55
- * rbx-2 [ x86_64 ]
47
+ Every Mail commit is tested by Travis on [all supported Ruby versions](https://github.com/mikel/mail/blob/master/.travis.yml).
56
48
 
57
- Testing a specific mime type (needed for 1.8.7 for example) can be done manually with:
49
+ Testing a specific version of mime-types (needed for Ruby 1.8.7, for example) can be done manually with:
58
50
 
59
51
  ```sh
60
- BUNDLE_GEMFILE=gemfiles/mime_types_1.16.gemfile (bundle check || bundle) && rake
52
+ BUNDLE_GEMFILE=gemfiles/mime_types_1.16.gemfile bundle && rake
61
53
  ```
62
54
 
63
55
  Discussion
@@ -697,7 +689,7 @@ License
697
689
 
698
690
  (The MIT License)
699
691
 
700
- Copyright (c) 2009-2016 Mikel Lindsaar
692
+ Copyright (c) 2009-2017 Mikel Lindsaar
701
693
 
702
694
  Permission is hereby granted, free of charge, to any person obtaining
703
695
  a copy of this software and associated documentation files (the
@@ -30,7 +30,7 @@ module Mail
30
30
  # mail.attachments['test.png'].filename #=> 'test.png'
31
31
  # mail.attachments[1].filename #=> 'test.jpg'
32
32
  def [](index_value)
33
- if index_value.is_a?(Fixnum)
33
+ if index_value.is_a?(Integer)
34
34
  self.fetch(index_value)
35
35
  else
36
36
  self.select { |a| a.filename == index_value }.first
@@ -1,21 +1,58 @@
1
1
  # frozen_string_literal: true
2
2
  module Mail
3
- module CheckDeliveryParams
4
- def check_delivery_params(mail)
5
- if Utilities.blank?(mail.smtp_envelope_from)
6
- raise ArgumentError.new('An SMTP From address is required to send a message. Set the message smtp_envelope_from, return_path, sender, or from address.')
3
+ module CheckDeliveryParams #:nodoc:
4
+ class << self
5
+ def check(mail)
6
+ [ check_from(mail.smtp_envelope_from),
7
+ check_to(mail.smtp_envelope_to),
8
+ check_message(mail) ]
7
9
  end
8
10
 
9
- if Utilities.blank?(mail.smtp_envelope_to)
10
- raise ArgumentError.new('An SMTP To address is required to send a message. Set the message smtp_envelope_to, to, cc, or bcc address.')
11
+ def check_from(addr)
12
+ if Utilities.blank?(addr)
13
+ raise ArgumentError, "SMTP From address may not be blank: #{addr.inspect}"
14
+ end
15
+
16
+ check_addr 'From', addr
17
+ end
18
+
19
+ def check_to(addrs)
20
+ if Utilities.blank?(addrs)
21
+ raise ArgumentError, "SMTP To address may not be blank: #{addrs.inspect}"
22
+ end
23
+
24
+ Array(addrs).map do |addr|
25
+ check_addr 'To', addr
26
+ end
11
27
  end
12
28
 
13
- message = mail.encoded if mail.respond_to?(:encoded)
14
- if Utilities.blank?(message)
15
- raise ArgumentError.new('An encoded message is required to send an email')
29
+ def check_addr(addr_name, addr)
30
+ validate_smtp_addr addr do |error_message|
31
+ raise ArgumentError, "SMTP #{addr_name} address #{error_message}: #{addr.inspect}"
32
+ end
16
33
  end
17
34
 
18
- [mail.smtp_envelope_from, mail.smtp_envelope_to, message]
35
+ def validate_smtp_addr(addr)
36
+ if addr.bytesize > 2048
37
+ yield 'may not exceed 2kB'
38
+ end
39
+
40
+ if /[\r\n]/ =~ addr
41
+ yield 'may not contain CR or LF line breaks'
42
+ end
43
+
44
+ addr
45
+ end
46
+
47
+ def check_message(message)
48
+ message = message.encoded if message.respond_to?(:encoded)
49
+
50
+ if Utilities.blank?(message)
51
+ raise ArgumentError, 'An encoded message is required to send an email'
52
+ end
53
+
54
+ message
55
+ end
19
56
  end
20
57
  end
21
58
  end
@@ -93,7 +93,7 @@ module Mail
93
93
  # a.display_name = 'Mikel Lindsaar'
94
94
  # a.format #=> 'Mikel Lindsaar <mikel@test.lindsaar.net>'
95
95
  def display_name=( str )
96
- @display_name = str.dup # in case frozen
96
+ @display_name = str.nil? ? nil : str.dup # in case frozen
97
97
  end
98
98
 
99
99
  # Returns the local part (the left hand side of the @ sign in the email address) of
@@ -123,7 +123,12 @@ module Mail
123
123
  # a.comments #=> ['My email address']
124
124
  def comments
125
125
  parse unless @parsed
126
- get_comments.map { |c| c.squeeze(SPACE) } unless get_comments.empty?
126
+ comments = get_comments
127
+ if comments.nil? || comments.none?
128
+ nil
129
+ else
130
+ comments.map { |c| c.squeeze(SPACE) }
131
+ end
127
132
  end
128
133
 
129
134
  # Sometimes an address will not have a display name, but might have the name
@@ -205,9 +210,9 @@ module Mail
205
210
  end
206
211
 
207
212
  def get_display_name
208
- if @data.display_name
213
+ if @data && @data.display_name
209
214
  str = strip_all_comments(@data.display_name.to_s)
210
- elsif @data.comments && @data.domain
215
+ elsif @data && @data.comments && @data.domain
211
216
  str = strip_domain_comments(format_comments)
212
217
  end
213
218
  str unless Utilities.blank?(str)
@@ -20,7 +20,7 @@ module Mail
20
20
  # a.group_names #=> ["My Group"]
21
21
  def initialize(string)
22
22
  @addresses_grouped_by_group = nil
23
- @address_list = Parsers::AddressListsParser.new.parse(string)
23
+ @address_list = Mail::Parsers::AddressListsParser.new.parse(string)
24
24
  end
25
25
 
26
26
  # Returns a list of address objects from the parsed line
@@ -8,10 +8,10 @@ module Mail
8
8
  super(list)
9
9
  end
10
10
 
11
- def << (address)
11
+ def <<(address)
12
12
  @field << address
13
13
  end
14
14
 
15
15
  end
16
16
 
17
- end
17
+ end
@@ -269,12 +269,12 @@ module Mail #:nodoc:
269
269
  @wrapped_string[*args] = replace_by
270
270
  else
271
271
  result = Unicode.u_unpack(@wrapped_string)
272
- if args[0].is_a?(Fixnum)
272
+ if args[0].is_a?(Integer)
273
273
  raise IndexError, "index #{args[0]} out of string" if args[0] >= result.length
274
274
  min = args[0]
275
275
  max = args[1].nil? ? min : (min + args[1] - 1)
276
276
  range = Range.new(min, max)
277
- replace_by = [replace_by].pack('U') if replace_by.is_a?(Fixnum)
277
+ replace_by = [replace_by].pack('U') if replace_by.is_a?(Integer)
278
278
  elsif args.first.is_a?(Range)
279
279
  raise RangeError, "#{args[0]} out of range" if args[0].min >= result.length
280
280
  range = args[0]
@@ -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
@@ -38,17 +38,19 @@ 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
55
  from = "-f #{self.class.shellquote(smtp_from)}"
54
56
  to = smtp_to.map { |_to| self.class.shellquote(_to) }.join(' ')
@@ -75,7 +75,7 @@ module Mail
75
75
  #
76
76
  # mail.deliver!
77
77
  class SMTP
78
- include Mail::CheckDeliveryParams
78
+ attr_accessor :settings
79
79
 
80
80
  def initialize(values)
81
81
  self.settings = { :address => "localhost",
@@ -91,12 +91,10 @@ module Mail
91
91
  }.merge!(values)
92
92
  end
93
93
 
94
- attr_accessor :settings
95
-
96
94
  # Send the message via SMTP.
97
95
  # The from and to attributes are optional. If not set, they are retrieve from the Message.
98
96
  def deliver!(mail)
99
- smtp_from, smtp_to, message = check_delivery_params(mail)
97
+ smtp_from, smtp_to, message = Mail::CheckDeliveryParams.check(mail)
100
98
 
101
99
  smtp = Net::SMTP.new(settings[:address], settings[:port])
102
100
  if settings[:tls] || settings[:ssl]
@@ -120,7 +118,6 @@ module Mail
120
118
  self
121
119
  end
122
120
  end
123
-
124
121
 
125
122
  private
126
123
 
@@ -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,13 @@ 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)
52
+ smtp_from, smtp_to, message = Mail::CheckDeliveryParams.check(mail)
56
53
  response = smtp.sendmail(message, smtp_from, smtp_to)
57
54
 
58
55
  settings[:return_response] ? response : self
59
56
  end
60
-
61
57
  end
62
58
  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
@@ -25,7 +25,7 @@ module Mail
25
25
  emails_index.reverse! if options[:what] == :last
26
26
  emails_index = case count = options[:count]
27
27
  when :all then emails_index
28
- when Fixnum then emails_index[0, count]
28
+ when Integer then emails_index[0, count]
29
29
  else
30
30
  raise 'Invalid count option value: ' + count.inspect
31
31
  end
@@ -92,7 +92,7 @@ module Mail::Parsers
92
92
  # version.
93
93
  when :angle_addr_s
94
94
  if qstr
95
- address.display_name = qstr
95
+ address.display_name = Mail::Utilities.unescape(qstr)
96
96
  qstr = nil
97
97
  elsif phrase_e
98
98
  address.display_name = s[phrase_s..phrase_e].strip
@@ -72,12 +72,26 @@ module Mail
72
72
  # unqoute(string) #=> 'This is "a string"'
73
73
  def unquote( str )
74
74
  if str =~ /^"(.*?)"$/
75
- $1.gsub(/\\(.)/, '\1')
75
+ unescape($1)
76
76
  else
77
77
  str
78
78
  end
79
79
  end
80
80
 
81
+ # Removes any \-escaping.
82
+ #
83
+ # Example:
84
+ #
85
+ # string = 'This is \"a string\"'
86
+ # unescape(string) #=> 'This is "a string"'
87
+ #
88
+ # string = '"This is \"a string\""'
89
+ # unescape(string) #=> '"This is "a string""'
90
+ def unescape( str )
91
+ str.gsub(/\\(.)/, '\1')
92
+ end
93
+ module_function :unescape
94
+
81
95
  # Wraps a string in parenthesis and escapes any that are in the string itself.
82
96
  #
83
97
  # Example:
data/lib/mail/version.rb CHANGED
@@ -4,7 +4,7 @@ module Mail
4
4
 
5
5
  MAJOR = 2
6
6
  MINOR = 6
7
- PATCH = 4
7
+ PATCH = 6
8
8
  BUILD = nil
9
9
 
10
10
  STRING = [MAJOR, MINOR, PATCH, BUILD].compact.join('.')
@@ -59,6 +59,9 @@ module Mail
59
59
  end
60
60
 
61
61
  def Ruby19.decode_base64(str)
62
+ if !str.end_with?("=") && str.length % 4 != 0
63
+ str = str.ljust((str.length + 3) & ~3, "=")
64
+ end
62
65
  str.unpack( 'm' ).first
63
66
  end
64
67
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mail
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.6.4
4
+ version: 2.6.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mikel Lindsaar
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-03-23 00:00:00.000000000 Z
11
+ date: 2017-06-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: mime-types
@@ -269,7 +269,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
269
269
  version: '0'
270
270
  requirements: []
271
271
  rubyforge_project:
272
- rubygems_version: 2.5.1
272
+ rubygems_version: 2.6.11
273
273
  signing_key:
274
274
  specification_version: 4
275
275
  summary: Mail provides a nice Ruby DSL for making, sending and reading emails.