mail 2.2.15 → 2.3.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 (39) hide show
  1. data/CHANGELOG.rdoc +38 -0
  2. data/Dependencies.txt +3 -0
  3. data/Gemfile +29 -0
  4. data/Rakefile +1 -1
  5. data/lib/VERSION +2 -2
  6. data/lib/mail/body.rb +10 -4
  7. data/lib/mail/configuration.rb +2 -0
  8. data/lib/mail/core_extensions/nil.rb +2 -0
  9. data/lib/mail/core_extensions/object.rb +13 -0
  10. data/lib/mail/core_extensions/shellwords.rb +2 -0
  11. data/lib/mail/core_extensions/smtp.rb +1 -0
  12. data/lib/mail/core_extensions/string/access.rb +104 -0
  13. data/lib/mail/core_extensions/string/multibyte.rb +78 -0
  14. data/lib/mail/core_extensions/string.rb +5 -1
  15. data/lib/mail/encodings.rb +43 -43
  16. data/lib/mail/field.rb +2 -1
  17. data/lib/mail/fields/common/common_message_id.rb +1 -1
  18. data/lib/mail/fields/common/parameter_hash.rb +5 -5
  19. data/lib/mail/fields/received_field.rb +11 -3
  20. data/lib/mail/fields/return_path_field.rb +1 -0
  21. data/lib/mail/fields/unstructured_field.rb +1 -0
  22. data/lib/mail/header.rb +2 -1
  23. data/lib/mail/indifferent_hash.rb +146 -0
  24. data/lib/mail/message.rb +26 -4
  25. data/lib/mail/multibyte/chars.rb +474 -0
  26. data/lib/mail/multibyte/exceptions.rb +8 -0
  27. data/lib/mail/multibyte/unicode.rb +392 -0
  28. data/lib/mail/multibyte/utils.rb +60 -0
  29. data/lib/mail/multibyte.rb +42 -0
  30. data/lib/mail/network/delivery_methods/smtp.rb +4 -3
  31. data/lib/mail/network/delivery_methods/smtp_connection.rb +74 -0
  32. data/lib/mail/network/retriever_methods/test_retriever.rb +8 -1
  33. data/lib/mail/network.rb +1 -0
  34. data/lib/mail/part.rb +1 -1
  35. data/lib/mail/parts_list.rb +17 -9
  36. data/lib/mail/version_specific/ruby_1_8.rb +14 -13
  37. data/lib/mail/version_specific/ruby_1_9.rb +19 -16
  38. data/lib/mail.rb +12 -7
  39. metadata +31 -28
@@ -52,15 +52,23 @@ module Mail
52
52
  end
53
53
 
54
54
  def formatted_date
55
- date_time.strftime("%a, %d %b %Y %H:%M:%S ") + date_time.zone.delete(':')
55
+ date_time.strftime("%a, %d %b %Y %H:%M:%S ") + date_time.zone.delete(':')
56
56
  end
57
57
 
58
58
  def encoded
59
- "#{CAPITALIZED_FIELD}: #{info}; #{formatted_date}\r\n"
59
+ if value.blank?
60
+ "#{CAPITALIZED_FIELD}: \r\n"
61
+ else
62
+ "#{CAPITALIZED_FIELD}: #{info}; #{formatted_date}\r\n"
63
+ end
60
64
  end
61
65
 
62
66
  def decoded
63
- "#{info}; #{formatted_date}"
67
+ if value.blank?
68
+ ""
69
+ else
70
+ "#{info}; #{formatted_date}"
71
+ end
64
72
  end
65
73
 
66
74
  end
@@ -38,6 +38,7 @@ module Mail
38
38
  CAPITALIZED_FIELD = 'Return-Path'
39
39
 
40
40
  def initialize(value = nil, charset = 'utf-8')
41
+ value = nil if value == '<>'
41
42
  self.charset = charset
42
43
  super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value), charset)
43
44
  self.parse
@@ -166,6 +166,7 @@ module Mail
166
166
  end
167
167
 
168
168
  def encode(value)
169
+ value.encode!(charset) if defined?(Encoding) && charset
169
170
  (value.not_ascii_only? ? [value].pack("M").gsub("=\n", '') : value).gsub("\r", "=0D").gsub("\n", "=0A")
170
171
  end
171
172
 
data/lib/mail/header.rb CHANGED
@@ -73,7 +73,8 @@ module Mail
73
73
  # h.fields = ['From: mikel@me.com', 'To: bob@you.com']
74
74
  def fields=(unfolded_fields)
75
75
  @fields = Mail::FieldList.new
76
- unfolded_fields.each do |field|
76
+ warn "Warning: more than 1000 header fields only using the first 1000" if unfolded_fields.length > 1000
77
+ unfolded_fields[0..1000].each do |field|
77
78
 
78
79
  field = Field.new(field, nil, charset)
79
80
  field.errors.each { |error| self.errors << error }
@@ -0,0 +1,146 @@
1
+ # encoding: utf-8
2
+
3
+ # This is an almost cut and paste from ActiveSupport v3.0.6, copied in here so that Mail
4
+ # itself does not depend on ActiveSupport to avoid versioning conflicts
5
+
6
+ module Mail
7
+ class IndifferentHash < Hash
8
+
9
+ def initialize(constructor = {})
10
+ if constructor.is_a?(Hash)
11
+ super()
12
+ update(constructor)
13
+ else
14
+ super(constructor)
15
+ end
16
+ end
17
+
18
+ def default(key = nil)
19
+ if key.is_a?(Symbol) && include?(key = key.to_s)
20
+ self[key]
21
+ else
22
+ super
23
+ end
24
+ end
25
+
26
+ def self.new_from_hash_copying_default(hash)
27
+ IndifferentHash.new(hash).tap do |new_hash|
28
+ new_hash.default = hash.default
29
+ end
30
+ end
31
+
32
+ alias_method :regular_writer, :[]= unless method_defined?(:regular_writer)
33
+ alias_method :regular_update, :update unless method_defined?(:regular_update)
34
+
35
+ # Assigns a new value to the hash:
36
+ #
37
+ # hash = HashWithIndifferentAccess.new
38
+ # hash[:key] = "value"
39
+ #
40
+ def []=(key, value)
41
+ regular_writer(convert_key(key), convert_value(value))
42
+ end
43
+
44
+ alias_method :store, :[]=
45
+
46
+ # Updates the instantized hash with values from the second:
47
+ #
48
+ # hash_1 = HashWithIndifferentAccess.new
49
+ # hash_1[:key] = "value"
50
+ #
51
+ # hash_2 = HashWithIndifferentAccess.new
52
+ # hash_2[:key] = "New Value!"
53
+ #
54
+ # hash_1.update(hash_2) # => {"key"=>"New Value!"}
55
+ #
56
+ def update(other_hash)
57
+ other_hash.each_pair { |key, value| regular_writer(convert_key(key), convert_value(value)) }
58
+ self
59
+ end
60
+
61
+ alias_method :merge!, :update
62
+
63
+ # Checks the hash for a key matching the argument passed in:
64
+ #
65
+ # hash = HashWithIndifferentAccess.new
66
+ # hash["key"] = "value"
67
+ # hash.key? :key # => true
68
+ # hash.key? "key" # => true
69
+ #
70
+ def key?(key)
71
+ super(convert_key(key))
72
+ end
73
+
74
+ alias_method :include?, :key?
75
+ alias_method :has_key?, :key?
76
+ alias_method :member?, :key?
77
+
78
+ # Fetches the value for the specified key, same as doing hash[key]
79
+ def fetch(key, *extras)
80
+ super(convert_key(key), *extras)
81
+ end
82
+
83
+ # Returns an array of the values at the specified indices:
84
+ #
85
+ # hash = HashWithIndifferentAccess.new
86
+ # hash[:a] = "x"
87
+ # hash[:b] = "y"
88
+ # hash.values_at("a", "b") # => ["x", "y"]
89
+ #
90
+ def values_at(*indices)
91
+ indices.collect {|key| self[convert_key(key)]}
92
+ end
93
+
94
+ # Returns an exact copy of the hash.
95
+ def dup
96
+ IndifferentHash.new(self)
97
+ end
98
+
99
+ # Merges the instantized and the specified hashes together, giving precedence to the values from the second hash
100
+ # Does not overwrite the existing hash.
101
+ def merge(hash)
102
+ self.dup.update(hash)
103
+ end
104
+
105
+ # Performs the opposite of merge, with the keys and values from the first hash taking precedence over the second.
106
+ # This overloaded definition prevents returning a regular hash, if reverse_merge is called on a HashWithDifferentAccess.
107
+ def reverse_merge(other_hash)
108
+ super self.class.new_from_hash_copying_default(other_hash)
109
+ end
110
+
111
+ def reverse_merge!(other_hash)
112
+ replace(reverse_merge( other_hash ))
113
+ end
114
+
115
+ # Removes a specified key from the hash.
116
+ def delete(key)
117
+ super(convert_key(key))
118
+ end
119
+
120
+ def stringify_keys!; self end
121
+ def stringify_keys; dup end
122
+ def symbolize_keys; to_hash.symbolize_keys end
123
+ def to_options!; self end
124
+
125
+ def to_hash
126
+ Hash.new(default).merge!(self)
127
+ end
128
+
129
+ protected
130
+
131
+ def convert_key(key)
132
+ key.kind_of?(Symbol) ? key.to_s : key
133
+ end
134
+
135
+ def convert_value(value)
136
+ if value.class == Hash
137
+ self.class.new_from_hash_copying_default(value)
138
+ elsif value.is_a?(Array)
139
+ value.dup.replace(value.map { |e| convert_value(e) })
140
+ else
141
+ value
142
+ end
143
+ end
144
+
145
+ end
146
+ end
data/lib/mail/message.rb CHANGED
@@ -1,4 +1,6 @@
1
1
  # encoding: utf-8
2
+ require "yaml"
3
+
2
4
  module Mail
3
5
  # The Message class provides a single point of access to all things to do with an
4
6
  # email message.
@@ -240,9 +242,9 @@ module Mail
240
242
  #
241
243
  # Returns self
242
244
  def deliver!
243
- delivery_method.deliver!(self)
245
+ response = delivery_method.deliver!(self)
244
246
  inform_observers
245
- self
247
+ delivery_method.settings[:return_response] ? response : self
246
248
  end
247
249
 
248
250
  def delivery_method(method = nil, settings = {})
@@ -268,7 +270,7 @@ module Mail
268
270
  reply.references ||= bracketed_message_id
269
271
  end
270
272
  if subject
271
- reply.subject = "RE: #{subject}"
273
+ reply.subject = subject =~ /^Re:/i ? subject : "RE: #{subject}"
272
274
  end
273
275
  if reply_to || from
274
276
  reply.to = self[reply_to ? :reply_to : :from].to_s
@@ -1677,6 +1679,7 @@ module Mail
1677
1679
  self.body = ''
1678
1680
  text_part = Mail::Part.new({:content_type => 'text/plain;',
1679
1681
  :body => text})
1682
+ text_part.charset = charset unless @defaulted_charset
1680
1683
  self.body << text_part
1681
1684
  end
1682
1685
 
@@ -1708,6 +1711,25 @@ module Mail
1708
1711
  buffer
1709
1712
  end
1710
1713
 
1714
+ def to_yaml
1715
+ ready_to_send!
1716
+ hash = {}
1717
+ header.fields.each do |field|
1718
+ hash[field.name] = field.value
1719
+ end
1720
+ hash['subject'] = subject
1721
+ hash['body'] = body.encoded(content_transfer_encoding)
1722
+ hash.to_yaml
1723
+ end
1724
+
1725
+ def self.from_yaml(str)
1726
+ from_hash(YAML::load(str))
1727
+ end
1728
+
1729
+ def self.from_hash(hash)
1730
+ Mail::Message.new(hash)
1731
+ end
1732
+
1711
1733
  def to_s
1712
1734
  encoded
1713
1735
  end
@@ -1906,7 +1928,7 @@ module Mail
1906
1928
  end
1907
1929
 
1908
1930
  def init_with_hash(hash)
1909
- passed_in_options = hash.with_indifferent_access
1931
+ passed_in_options = IndifferentHash.new(hash)
1910
1932
  self.raw_source = ''
1911
1933
 
1912
1934
  @header = Mail::Header.new