mail 2.7.1 → 2.9.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 (126) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +135 -59
  3. data/lib/mail/attachments_list.rb +5 -6
  4. data/lib/mail/body.rb +51 -74
  5. data/lib/mail/constants.rb +27 -5
  6. data/lib/mail/elements/address.rb +27 -27
  7. data/lib/mail/elements/address_list.rb +1 -1
  8. data/lib/mail/elements/content_disposition_element.rb +1 -1
  9. data/lib/mail/elements/content_location_element.rb +1 -1
  10. data/lib/mail/elements/content_transfer_encoding_element.rb +1 -1
  11. data/lib/mail/elements/content_type_element.rb +8 -4
  12. data/lib/mail/elements/date_time_element.rb +1 -1
  13. data/lib/mail/elements/envelope_from_element.rb +13 -7
  14. data/lib/mail/elements/message_ids_element.rb +14 -5
  15. data/lib/mail/elements/mime_version_element.rb +1 -1
  16. data/lib/mail/elements/phrase_list.rb +7 -2
  17. data/lib/mail/elements/received_element.rb +20 -6
  18. data/lib/mail/encodings/7bit.rb +5 -0
  19. data/lib/mail/encodings/base64.rb +2 -2
  20. data/lib/mail/encodings/quoted_printable.rb +2 -2
  21. data/lib/mail/encodings/unix_to_unix.rb +1 -1
  22. data/lib/mail/encodings.rb +32 -61
  23. data/lib/mail/envelope.rb +11 -14
  24. data/lib/mail/field.rb +100 -86
  25. data/lib/mail/field_list.rb +61 -8
  26. data/lib/mail/fields/bcc_field.rb +33 -52
  27. data/lib/mail/fields/cc_field.rb +27 -49
  28. data/lib/mail/fields/comments_field.rb +26 -37
  29. data/lib/mail/fields/common_address_field.rb +162 -0
  30. data/lib/mail/fields/common_date_field.rb +56 -0
  31. data/lib/mail/fields/common_field.rb +77 -0
  32. data/lib/mail/fields/common_message_id_field.rb +41 -0
  33. data/lib/mail/fields/content_description_field.rb +6 -14
  34. data/lib/mail/fields/content_disposition_field.rb +11 -38
  35. data/lib/mail/fields/content_id_field.rb +23 -51
  36. data/lib/mail/fields/content_location_field.rb +10 -25
  37. data/lib/mail/fields/content_transfer_encoding_field.rb +30 -31
  38. data/lib/mail/fields/content_type_field.rb +49 -75
  39. data/lib/mail/fields/date_field.rb +22 -51
  40. data/lib/mail/fields/from_field.rb +27 -49
  41. data/lib/mail/fields/in_reply_to_field.rb +37 -49
  42. data/lib/mail/fields/keywords_field.rb +17 -31
  43. data/lib/mail/fields/message_id_field.rb +24 -71
  44. data/lib/mail/fields/mime_version_field.rb +18 -30
  45. data/lib/mail/fields/named_structured_field.rb +10 -0
  46. data/lib/mail/fields/named_unstructured_field.rb +10 -0
  47. data/lib/mail/fields/optional_field.rb +5 -7
  48. data/lib/mail/fields/{common/parameter_hash.rb → parameter_hash.rb} +12 -10
  49. data/lib/mail/fields/received_field.rb +42 -57
  50. data/lib/mail/fields/references_field.rb +34 -49
  51. data/lib/mail/fields/reply_to_field.rb +27 -49
  52. data/lib/mail/fields/resent_bcc_field.rb +27 -49
  53. data/lib/mail/fields/resent_cc_field.rb +27 -49
  54. data/lib/mail/fields/resent_date_field.rb +4 -29
  55. data/lib/mail/fields/resent_from_field.rb +27 -49
  56. data/lib/mail/fields/resent_message_id_field.rb +4 -29
  57. data/lib/mail/fields/resent_sender_field.rb +26 -56
  58. data/lib/mail/fields/resent_to_field.rb +27 -49
  59. data/lib/mail/fields/return_path_field.rb +49 -54
  60. data/lib/mail/fields/sender_field.rb +33 -55
  61. data/lib/mail/fields/structured_field.rb +2 -30
  62. data/lib/mail/fields/subject_field.rb +8 -11
  63. data/lib/mail/fields/to_field.rb +27 -49
  64. data/lib/mail/fields/unstructured_field.rb +15 -48
  65. data/lib/mail/fields.rb +9 -0
  66. data/lib/mail/header.rb +69 -110
  67. data/lib/mail/mail.rb +32 -27
  68. data/lib/mail/matchers/attachment_matchers.rb +15 -0
  69. data/lib/mail/message.rb +67 -78
  70. data/lib/mail/multibyte/chars.rb +9 -167
  71. data/lib/mail/multibyte/unicode.rb +1 -1
  72. data/lib/mail/multibyte/utils.rb +26 -43
  73. data/lib/mail/multibyte.rb +1 -11
  74. data/lib/mail/network/delivery_methods/exim.rb +5 -4
  75. data/lib/mail/network/delivery_methods/file_delivery.rb +13 -12
  76. data/lib/mail/network/delivery_methods/logger_delivery.rb +2 -5
  77. data/lib/mail/network/delivery_methods/sendmail.rb +27 -35
  78. data/lib/mail/network/delivery_methods/smtp.rb +81 -30
  79. data/lib/mail/network/delivery_methods/smtp_connection.rb +10 -19
  80. data/lib/mail/network/delivery_methods/test_mailer.rb +8 -6
  81. data/lib/mail/network/retriever_methods/base.rb +13 -13
  82. data/lib/mail/network/retriever_methods/imap.rb +8 -5
  83. data/lib/mail/network/retriever_methods/pop3.rb +22 -22
  84. data/lib/mail/network/retriever_methods/test_retriever.rb +2 -1
  85. data/lib/mail/parsers/address_lists_parser.rb +33073 -33064
  86. data/lib/mail/parsers/address_lists_parser.rl +11 -0
  87. data/lib/mail/parsers/content_disposition_parser.rb +837 -828
  88. data/lib/mail/parsers/content_disposition_parser.rl +11 -0
  89. data/lib/mail/parsers/content_location_parser.rb +773 -764
  90. data/lib/mail/parsers/content_location_parser.rl +12 -1
  91. data/lib/mail/parsers/content_transfer_encoding_parser.rb +477 -468
  92. data/lib/mail/parsers/content_transfer_encoding_parser.rl +11 -0
  93. data/lib/mail/parsers/content_type_parser.rb +974 -965
  94. data/lib/mail/parsers/content_type_parser.rl +11 -0
  95. data/lib/mail/parsers/date_time_parser.rb +841 -832
  96. data/lib/mail/parsers/date_time_parser.rl +11 -0
  97. data/lib/mail/parsers/envelope_from_parser.rb +3627 -3530
  98. data/lib/mail/parsers/envelope_from_parser.rl +11 -0
  99. data/lib/mail/parsers/message_ids_parser.rb +5110 -2800
  100. data/lib/mail/parsers/message_ids_parser.rl +16 -1
  101. data/lib/mail/parsers/mime_version_parser.rb +466 -457
  102. data/lib/mail/parsers/mime_version_parser.rl +11 -0
  103. data/lib/mail/parsers/phrase_lists_parser.rb +839 -830
  104. data/lib/mail/parsers/phrase_lists_parser.rl +12 -1
  105. data/lib/mail/parsers/received_parser.rb +8692 -8683
  106. data/lib/mail/parsers/received_parser.rl +11 -0
  107. data/lib/mail/parsers/rfc5322.rl +28 -13
  108. data/lib/mail/parsers.rb +11 -17
  109. data/lib/mail/part.rb +24 -28
  110. data/lib/mail/parts_list.rb +57 -0
  111. data/lib/mail/smtp_envelope.rb +57 -0
  112. data/lib/mail/utilities.rb +321 -69
  113. data/lib/mail/version.rb +1 -1
  114. data/lib/mail/yaml.rb +30 -0
  115. data/lib/mail.rb +2 -22
  116. metadata +83 -19
  117. data/lib/mail/check_delivery_params.rb +0 -60
  118. data/lib/mail/core_extensions/smtp.rb +0 -28
  119. data/lib/mail/core_extensions/string.rb +0 -17
  120. data/lib/mail/fields/common/address_container.rb +0 -17
  121. data/lib/mail/fields/common/common_address.rb +0 -161
  122. data/lib/mail/fields/common/common_date.rb +0 -36
  123. data/lib/mail/fields/common/common_field.rb +0 -52
  124. data/lib/mail/fields/common/common_message_id.rb +0 -49
  125. data/lib/mail/version_specific/ruby_1_8.rb +0 -163
  126. data/lib/mail/version_specific/ruby_1_9.rb +0 -278
@@ -1,6 +1,6 @@
1
1
  # encoding: utf-8
2
2
  # frozen_string_literal: true
3
- require 'mail/fields/common/common_field'
3
+ require 'mail/utilities'
4
4
 
5
5
  module Mail
6
6
  # Provides access to an unstructured header field
@@ -15,58 +15,28 @@ module Mail
15
15
  # field bodies are simply to be treated as a single line of characters
16
16
  # with no further processing (except for header "folding" and
17
17
  # "unfolding" as described in section 2.2.3).
18
- class UnstructuredField
19
-
20
- include Mail::CommonField
21
- include Mail::Utilities
22
-
23
- attr_accessor :charset
24
- attr_reader :errors
25
-
18
+ class UnstructuredField < CommonField #:nodoc:
26
19
  def initialize(name, value, charset = nil)
27
- @errors = []
28
-
29
20
  if value.is_a?(Array)
30
21
  # Probably has arrived here from a failed parse of an AddressList Field
31
22
  value = value.join(', ')
32
- else
33
- # Ensure we are dealing with a string
34
- value = value.to_s
35
23
 
36
- # Mark UTF-8 strings parsed from ASCII-8BIT
37
- if value.respond_to?(:force_encoding) && value.encoding == Encoding::ASCII_8BIT
38
- utf8 = value.dup.force_encoding(Encoding::UTF_8)
39
- value = utf8 if utf8.valid_encoding?
40
- end
24
+ # Mark UTF-8 strings parsed from ASCII-8BIT
25
+ elsif value.respond_to?(:force_encoding) && value.encoding == Encoding::ASCII_8BIT
26
+ utf8 = value.dup.force_encoding(Encoding::UTF_8)
27
+ value = utf8 if utf8.valid_encoding?
41
28
  end
42
29
 
43
- if charset
44
- self.charset = charset
45
- else
30
+ charset ||=
46
31
  if value.respond_to?(:encoding)
47
- self.charset = value.encoding
48
- else
49
- self.charset = $KCODE
32
+ value.encoding
50
33
  end
51
- end
52
- self.name = name
53
- self.value = value
54
- self
55
- end
56
-
57
- def encoded
58
- do_encode
59
- end
60
34
 
61
- def decoded
62
- do_decode
35
+ super name, value.to_s, charset
63
36
  end
64
37
 
65
- def default
66
- decoded
67
- end
68
-
69
- def parse # An unstructured field does not parse
38
+ # An unstructured field does not parse
39
+ def parse
70
40
  self
71
41
  end
72
42
 
@@ -196,7 +166,7 @@ module Mail
196
166
  end
197
167
 
198
168
  def encode(value)
199
- value = [value].pack(CAPITAL_M).gsub(EQUAL_LF, EMPTY)
169
+ value = [value].pack(Constants::CAPITAL_M).gsub(Constants::EQUAL_LF, Constants::EMPTY)
200
170
  value.gsub!(/"/, '=22')
201
171
  value.gsub!(/\(/, '=28')
202
172
  value.gsub!(/\)/, '=29')
@@ -207,16 +177,13 @@ module Mail
207
177
  end
208
178
 
209
179
  def encode_crlf(value)
210
- value.gsub!(CR, CR_ENCODED)
211
- value.gsub!(LF, LF_ENCODED)
180
+ value.gsub!(Constants::CR, Constants::CR_ENCODED)
181
+ value.gsub!(Constants::LF, Constants::LF_ENCODED)
212
182
  value
213
183
  end
214
184
 
215
185
  def normalized_encoding
216
- encoding = charset.to_s.upcase.gsub('_', '-')
217
- encoding = 'UTF-8' if encoding == 'UTF8' # Ruby 1.8.x and $KCODE == 'u'
218
- encoding
186
+ charset.to_s.upcase.gsub('_', '-')
219
187
  end
220
-
221
188
  end
222
189
  end
data/lib/mail/fields.rb CHANGED
@@ -1,6 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
  module Mail
3
+ register_autoload :CommonField, 'mail/fields/common_field'
4
+ register_autoload :CommonAddressField, 'mail/fields/common_address_field'
5
+ register_autoload :CommonMessageIdField, 'mail/fields/common_message_id_field'
6
+ register_autoload :CommonDateField, 'mail/fields/common_date_field'
7
+
3
8
  register_autoload :UnstructuredField, 'mail/fields/unstructured_field'
9
+ register_autoload :NamedUnstructuredField, 'mail/fields/named_unstructured_field'
4
10
  register_autoload :StructuredField, 'mail/fields/structured_field'
5
11
  register_autoload :OptionalField, 'mail/fields/optional_field'
6
12
 
@@ -19,6 +25,7 @@ module Mail
19
25
  register_autoload :KeywordsField, 'mail/fields/keywords_field'
20
26
  register_autoload :MessageIdField, 'mail/fields/message_id_field'
21
27
  register_autoload :MimeVersionField, 'mail/fields/mime_version_field'
28
+ register_autoload :NamedStructuredField, 'mail/fields/named_structured_field'
22
29
  register_autoload :ReceivedField, 'mail/fields/received_field'
23
30
  register_autoload :ReferencesField, 'mail/fields/references_field'
24
31
  register_autoload :ReplyToField, 'mail/fields/reply_to_field'
@@ -33,4 +40,6 @@ module Mail
33
40
  register_autoload :SenderField, 'mail/fields/sender_field'
34
41
  register_autoload :SubjectField, 'mail/fields/subject_field'
35
42
  register_autoload :ToField, 'mail/fields/to_field'
43
+
44
+ register_autoload :ParameterHash, 'mail/fields/parameter_hash'
36
45
  end
data/lib/mail/header.rb CHANGED
@@ -1,13 +1,15 @@
1
1
  # encoding: utf-8
2
2
  # frozen_string_literal: true
3
+ require 'mail/constants'
4
+ require 'mail/utilities'
5
+
3
6
  module Mail
4
-
5
7
  # Provides access to a header object.
6
- #
8
+ #
7
9
  # ===Per RFC2822
8
- #
10
+ #
9
11
  # 2.2. Header Fields
10
- #
12
+ #
11
13
  # Header fields are lines composed of a field name, followed by a colon
12
14
  # (":"), followed by a field body, and terminated by CRLF. A field
13
15
  # name MUST be composed of printable US-ASCII characters (i.e.,
@@ -18,14 +20,12 @@ module Mail
18
20
  # 2.2.3. All field bodies MUST conform to the syntax described in
19
21
  # sections 3 and 4 of this standard.
20
22
  class Header
21
- include Constants
22
- include Utilities
23
23
  include Enumerable
24
-
24
+
25
25
  @@maximum_amount = 1000
26
26
 
27
27
  # Large amount of headers in Email might create extra high CPU load
28
- # Use this parameter to limit number of headers that will be parsed by
28
+ # Use this parameter to limit number of headers that will be parsed by
29
29
  # mail library.
30
30
  # Default: 1000
31
31
  def self.maximum_amount
@@ -36,12 +36,14 @@ module Mail
36
36
  @@maximum_amount = value
37
37
  end
38
38
 
39
+ attr_reader :raw_source, :charset
40
+
39
41
  # Creates a new header object.
40
- #
42
+ #
41
43
  # Accepts raw text or nothing. If given raw text will attempt to parse
42
44
  # it and split it into the various fields, instantiating each field as
43
45
  # it goes.
44
- #
46
+ #
45
47
  # If it finds a field that should be a structured field (such as content
46
48
  # type), but it fails to parse it, it will simply make it an unstructured
47
49
  # field and leave it alone. This will mean that the data is preserved but
@@ -50,7 +52,7 @@ module Mail
50
52
  # me the example so we can fix it.
51
53
  def initialize(header_text = nil, charset = nil)
52
54
  @charset = charset
53
- self.raw_source = header_text
55
+ @raw_source = ::Mail::Utilities.to_crlf(header_text).lstrip
54
56
  split_header if header_text
55
57
  end
56
58
 
@@ -59,21 +61,15 @@ module Mail
59
61
  @fields = @fields.dup
60
62
  @fields.map!(&:dup)
61
63
  end
62
-
63
- # The preserved raw source of the header as you passed it in, untouched
64
- # for your Regexing glory.
65
- def raw_source
66
- @raw_source
67
- end
68
-
64
+
69
65
  # Returns an array of all the fields in the header in order that they
70
66
  # were read in.
71
67
  def fields
72
68
  @fields ||= FieldList.new
73
69
  end
74
-
70
+
75
71
  # 3.6. Field definitions
76
- #
72
+ #
77
73
  # It is important to note that the header fields are not guaranteed to
78
74
  # be in a particular order. They may appear in any order, and they
79
75
  # have been known to be reordered occasionally when transported over
@@ -83,36 +79,35 @@ module Mail
83
79
  # header fields MUST NOT be reordered, and SHOULD be kept in blocks
84
80
  # prepended to the message. See sections 3.6.6 and 3.6.7 for more
85
81
  # information.
86
- #
82
+ #
87
83
  # Populates the fields container with Field objects in the order it
88
84
  # receives them in.
89
85
  #
90
86
  # Acceps an array of field string values, for example:
91
- #
87
+ #
92
88
  # h = Header.new
93
89
  # h.fields = ['From: mikel@me.com', 'To: bob@you.com']
94
90
  def fields=(unfolded_fields)
95
91
  @fields = Mail::FieldList.new
96
- Kernel.warn "WARNING: More than #{self.class.maximum_amount} header fields; only using the first #{self.class.maximum_amount} and ignoring the rest" if unfolded_fields.length > self.class.maximum_amount
97
- unfolded_fields[0..(self.class.maximum_amount-1)].each do |field|
98
92
 
93
+ if unfolded_fields.size > self.class.maximum_amount
94
+ Kernel.warn "WARNING: More than #{self.class.maximum_amount} header fields; only using the first #{self.class.maximum_amount} and ignoring the rest"
95
+ unfolded_fields = unfolded_fields.slice(0...self.class.maximum_amount)
96
+ end
97
+
98
+ unfolded_fields.each do |field|
99
99
  if field = Field.parse(field, charset)
100
- if limited_field?(field.name) && (selected = select_field_for(field.name)) && selected.any?
101
- selected.first.update(field.name, field.value)
102
- else
103
- @fields << field
104
- end
100
+ @fields.add_field field
105
101
  end
106
102
  end
107
-
108
103
  end
109
-
104
+
110
105
  def errors
111
106
  @fields.map(&:errors).flatten(1)
112
107
  end
113
-
108
+
114
109
  # 3.6. Field definitions
115
- #
110
+ #
116
111
  # The following table indicates limits on the number of times each
117
112
  # field may occur in a message header as well as any special
118
113
  # limitations on the use of those fields. An asterisk next to a value
@@ -122,35 +117,25 @@ module Mail
122
117
  # <snip table from 3.6>
123
118
  #
124
119
  # As per RFC, many fields can appear more than once, we will return a string
125
- # of the value if there is only one header, or if there is more than one
120
+ # of the value if there is only one header, or if there is more than one
126
121
  # matching header, will return an array of values in order that they appear
127
122
  # in the header ordered from top to bottom.
128
- #
123
+ #
129
124
  # Example:
130
- #
125
+ #
131
126
  # h = Header.new
132
127
  # h.fields = ['To: mikel@me.com', 'X-Mail-SPAM: 15', 'X-Mail-SPAM: 20']
133
128
  # h['To'] #=> 'mikel@me.com'
134
129
  # h['X-Mail-SPAM'] #=> ['15', '20']
135
130
  def [](name)
136
- name = dasherize(name)
137
- name.downcase!
138
- selected = select_field_for(name)
139
- case
140
- when selected.length > 1
141
- selected.map { |f| f }
142
- when !Utilities.blank?(selected)
143
- selected.first
144
- else
145
- nil
146
- end
131
+ fields.get_field(Utilities.dasherize(name))
147
132
  end
148
-
133
+
149
134
  # Sets the FIRST matching field in the header to passed value, or deletes
150
135
  # the FIRST field matched from the header if passed nil
151
- #
136
+ #
152
137
  # Example:
153
- #
138
+ #
154
139
  # h = Header.new
155
140
  # h.fields = ['To: mikel@me.com', 'X-Mail-SPAM: 15', 'X-Mail-SPAM: 20']
156
141
  # h['To'] = 'bob@you.com'
@@ -160,51 +145,39 @@ module Mail
160
145
  # h['X-Mail-SPAM'] = nil
161
146
  # h['X-Mail-SPAM'] # => nil
162
147
  def []=(name, value)
163
- name = dasherize(name)
164
- if name.include?(':')
148
+ name = name.to_s
149
+ if name.include?(Constants::COLON)
165
150
  raise ArgumentError, "Header names may not contain a colon: #{name.inspect}"
166
151
  end
167
- fn = name.downcase
168
- selected = select_field_for(fn)
169
-
170
- case
171
- # User wants to delete the field
172
- when !Utilities.blank?(selected) && value == nil
173
- fields.delete_if { |f| selected.include?(f) }
174
-
175
- # User wants to change the field
176
- when !Utilities.blank?(selected) && limited_field?(fn)
177
- selected.first.update(fn, value)
178
-
179
- # User wants to create the field
152
+
153
+ name = Utilities.dasherize(name)
154
+
155
+ # Assign nil to delete the field
156
+ if value.nil?
157
+ fields.delete_field name
180
158
  else
181
- # Need to insert in correct order for trace fields
182
- self.fields << Field.new(name.to_s, value, charset)
183
- end
184
- if dasherize(fn) == "content-type"
159
+ fields.add_field Field.new(name.to_s, value, charset)
160
+
185
161
  # Update charset if specified in Content-Type
186
- params = self[:content_type].parameters rescue nil
187
- @charset = params[:charset] if params && params[:charset]
162
+ if name == 'content-type'
163
+ params = self[:content_type].parameters rescue nil
164
+ @charset = params[:charset] if params && params[:charset]
165
+ end
188
166
  end
189
167
  end
190
-
191
- def charset
192
- @charset
193
- end
194
-
168
+
195
169
  def charset=(val)
196
170
  params = self[:content_type].parameters rescue nil
197
171
  if params
198
- params[:charset] = val
172
+ if val
173
+ params[:charset] = val
174
+ else
175
+ params.delete(:charset)
176
+ end
199
177
  end
200
178
  @charset = val
201
179
  end
202
-
203
- LIMITED_FIELDS = %w[ date from sender reply-to to cc bcc
204
- message-id in-reply-to references subject
205
- return-path content-type mime-version
206
- content-transfer-encoding content-description
207
- content-id content-disposition content-location]
180
+
208
181
 
209
182
  def encoded
210
183
  buffer = String.new
@@ -218,61 +191,47 @@ module Mail
218
191
  def to_s
219
192
  encoded
220
193
  end
221
-
194
+
222
195
  def decoded
223
- raise NoMethodError, 'Can not decode an entire header as there could be character set conflicts, try calling #decoded on the various fields.'
196
+ raise NoMethodError, 'Can not decode an entire header as there could be character set conflicts. Try calling #decoded on the various fields.'
224
197
  end
225
198
 
226
199
  def field_summary
227
- fields.map { |f| "<#{f.name}: #{f.value}>" }.join(", ")
200
+ fields.summary
228
201
  end
229
202
 
230
203
  # Returns true if the header has a Message-ID defined (empty or not)
231
204
  def has_message_id?
232
- !fields.select { |f| f.responsible_for?('Message-ID') }.empty?
205
+ fields.has_field? 'Message-ID'
233
206
  end
234
207
 
235
208
  # Returns true if the header has a Content-ID defined (empty or not)
236
209
  def has_content_id?
237
- !fields.select { |f| f.responsible_for?('Content-ID') }.empty?
210
+ fields.has_field? 'Content-ID'
238
211
  end
239
212
 
240
213
  # Returns true if the header has a Date defined (empty or not)
241
214
  def has_date?
242
- !fields.select { |f| f.responsible_for?('Date') }.empty?
215
+ fields.has_field? 'Date'
243
216
  end
244
217
 
245
218
  # Returns true if the header has a MIME version defined (empty or not)
246
219
  def has_mime_version?
247
- !fields.select { |f| f.responsible_for?('Mime-Version') }.empty?
220
+ fields.has_field? 'MIME-Version'
248
221
  end
249
222
 
250
223
  private
251
-
252
- def raw_source=(val)
253
- @raw_source = ::Mail::Utilities.to_crlf(val).lstrip
254
- end
255
-
224
+
256
225
  # Splits an unfolded and line break cleaned header into individual field
257
226
  # strings.
258
227
  def split_header
259
- self.fields = raw_source.split(HEADER_SPLIT)
260
- end
261
-
262
- def select_field_for(name)
263
- fields.select { |f| f.responsible_for?(name) }
264
- end
265
-
266
- def limited_field?(name)
267
- LIMITED_FIELDS.include?(name.to_s.downcase)
228
+ self.fields = @raw_source.split(Constants::HEADER_SPLIT)
268
229
  end
269
230
 
270
- # Enumerable support; yield each field in order to the block if there is one,
271
- # or return an Enumerator for them if there isn't.
272
- def each( &block )
273
- return self.fields.each( &block ) if block
274
- self.fields.each
275
- end
276
231
 
232
+ # Enumerable support. Yield each field in order.
233
+ def each(&block)
234
+ fields.each(&block)
235
+ end
277
236
  end
278
237
  end
data/lib/mail/mail.rb CHANGED
@@ -3,45 +3,45 @@
3
3
  module Mail
4
4
 
5
5
  # Allows you to create a new Mail::Message object.
6
- #
6
+ #
7
7
  # You can make an email via passing a string or passing a block.
8
- #
8
+ #
9
9
  # For example, the following two examples will create the same email
10
10
  # message:
11
- #
11
+ #
12
12
  # Creating via a string:
13
- #
13
+ #
14
14
  # string = "To: mikel@test.lindsaar.net\r\n"
15
15
  # string << "From: bob@test.lindsaar.net\r\n"
16
16
  # string << "Subject: This is an email\r\n"
17
17
  # string << "\r\n"
18
18
  # string << "This is the body"
19
19
  # Mail.new(string)
20
- #
20
+ #
21
21
  # Or creating via a block:
22
- #
22
+ #
23
23
  # message = Mail.new do
24
24
  # to 'mikel@test.lindsaar.net'
25
25
  # from 'bob@test.lindsaar.net'
26
26
  # subject 'This is an email'
27
27
  # body 'This is the body'
28
28
  # end
29
- #
29
+ #
30
30
  # Or creating via a hash (or hash like object):
31
- #
31
+ #
32
32
  # message = Mail.new({:to => 'mikel@test.lindsaar.net',
33
33
  # 'from' => 'bob@test.lindsaar.net',
34
34
  # :subject => 'This is an email',
35
35
  # :body => 'This is the body' })
36
- #
36
+ #
37
37
  # Note, the hash keys can be strings or symbols, the passed in object
38
38
  # does not need to be a hash, it just needs to respond to :each_pair
39
39
  # and yield each key value pair.
40
- #
40
+ #
41
41
  # As a side note, you can also create a new email through creating
42
42
  # a Mail::Message object directly and then passing in values via string,
43
43
  # symbol or direct method calls. See Mail::Message for more information.
44
- #
44
+ #
45
45
  # mail = Mail.new
46
46
  # mail.to = 'mikel@test.lindsaar.net'
47
47
  # mail[:from] = 'bob@test.lindsaar.net'
@@ -54,20 +54,20 @@ module Mail
54
54
  # Sets the default delivery method and retriever method for all new Mail objects.
55
55
  # The delivery_method and retriever_method default to :smtp and :pop3, with defaults
56
56
  # set.
57
- #
57
+ #
58
58
  # So sending a new email, if you have an SMTP server running on localhost is
59
59
  # as easy as:
60
- #
60
+ #
61
61
  # Mail.deliver do
62
62
  # to 'mikel@test.lindsaar.net'
63
63
  # from 'bob@test.lindsaar.net'
64
64
  # subject 'hi there!'
65
65
  # body 'this is a body'
66
66
  # end
67
- #
67
+ #
68
68
  # If you do not specify anything, you will get the following equivalent code set in
69
69
  # every new mail object:
70
- #
70
+ #
71
71
  # Mail.defaults do
72
72
  # delivery_method :smtp, { :address => "localhost",
73
73
  # :port => 25,
@@ -76,14 +76,14 @@ module Mail
76
76
  # :password => nil,
77
77
  # :authentication => nil,
78
78
  # :enable_starttls_auto => true }
79
- #
79
+ #
80
80
  # retriever_method :pop3, { :address => "localhost",
81
81
  # :port => 995,
82
82
  # :user_name => nil,
83
83
  # :password => nil,
84
84
  # :enable_ssl => true }
85
85
  # end
86
- #
86
+ #
87
87
  # Mail.delivery_method.new #=> Mail::SMTP instance
88
88
  # Mail.retriever_method.new #=> Mail::POP3 instance
89
89
  #
@@ -91,9 +91,9 @@ module Mail
91
91
  # a per email basis, you can override the method:
92
92
  #
93
93
  # mail.delivery_method :smtp
94
- #
94
+ #
95
95
  # Or you can override the method and pass in settings:
96
- #
96
+ #
97
97
  # mail.delivery_method :smtp, :address => 'some.host'
98
98
  def self.defaults(&block)
99
99
  Configuration.instance.instance_eval(&block)
@@ -112,21 +112,21 @@ module Mail
112
112
  # Send an email using the default configuration. You do need to set a default
113
113
  # configuration first before you use self.deliver, if you don't, an appropriate
114
114
  # error will be raised telling you to.
115
- #
115
+ #
116
116
  # If you do not specify a delivery type, SMTP will be used.
117
- #
117
+ #
118
118
  # Mail.deliver do
119
119
  # to 'mikel@test.lindsaar.net'
120
120
  # from 'ada@test.lindsaar.net'
121
121
  # subject 'This is a test email'
122
122
  # body 'Not much to say here'
123
123
  # end
124
- #
124
+ #
125
125
  # You can also do:
126
- #
126
+ #
127
127
  # mail = Mail.read('email.eml')
128
128
  # mail.deliver!
129
- #
129
+ #
130
130
  # And your email object will be created and sent.
131
131
  def self.deliver(*args, &block)
132
132
  mail = self.new(args, &block)
@@ -152,7 +152,7 @@ module Mail
152
152
  retriever_method.first(*args, &block)
153
153
  end
154
154
 
155
- # Receive the first email(s) from the default retriever
155
+ # Receive the last email(s) from the default retriever
156
156
  # See Mail::Retriever for a complete documentation.
157
157
  def self.last(*args, &block)
158
158
  retriever_method.last(*args, &block)
@@ -190,7 +190,7 @@ module Mail
190
190
 
191
191
  # You can register an object to be informed of every email that is sent through
192
192
  # this method.
193
- #
193
+ #
194
194
  # Your object needs to respond to a single method #delivered_email(mail)
195
195
  # which receives the email that is sent.
196
196
  def self.register_observer(observer)
@@ -208,7 +208,7 @@ module Mail
208
208
  # You can register an object to be given every mail object that will be sent,
209
209
  # before it is sent. So if you want to add special headers or modify any
210
210
  # email that gets sent through the Mail library, you can do so.
211
- #
211
+ #
212
212
  # Your object needs to respond to a single method #delivering_email(mail)
213
213
  # which receives the email that is about to be sent. Make your modifications
214
214
  # directly to this object.
@@ -236,6 +236,11 @@ module Mail
236
236
  end
237
237
  end
238
238
 
239
+ # Returns a list of registered delivery interceptors.
240
+ def self.delivery_interceptors
241
+ @@delivery_interceptors
242
+ end
243
+
239
244
  protected
240
245
 
241
246
  RANDOM_TAG='%x%x_%x%x%d%x'
@@ -9,6 +9,10 @@ module Mail
9
9
  AttachmentFilenameMatcher.new(filename)
10
10
  end
11
11
 
12
+ def an_attachment_with_mime_type(filename)
13
+ AttachmentMimeTypeMatcher.new(filename)
14
+ end
15
+
12
16
  class AnyAttachmentMatcher
13
17
  def ===(other)
14
18
  other.attachment?
@@ -25,5 +29,16 @@ module Mail
25
29
  other.attachment? && other.filename == filename
26
30
  end
27
31
  end
32
+
33
+ class AttachmentMimeTypeMatcher
34
+ attr_reader :mime_type
35
+ def initialize(mime_type)
36
+ @mime_type = mime_type
37
+ end
38
+
39
+ def ===(other)
40
+ other.attachment? && other.mime_type == mime_type
41
+ end
42
+ end
28
43
  end
29
44
  end