mail 2.7.1 → 2.8.0.rc1
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 +4 -4
- data/README.md +45 -28
- data/lib/mail/attachments_list.rb +2 -5
- data/lib/mail/body.rb +24 -47
- data/lib/mail/constants.rb +27 -5
- data/lib/mail/elements/address.rb +27 -27
- data/lib/mail/elements/address_list.rb +1 -1
- data/lib/mail/elements/content_disposition_element.rb +1 -1
- data/lib/mail/elements/content_location_element.rb +1 -1
- data/lib/mail/elements/content_transfer_encoding_element.rb +1 -1
- data/lib/mail/elements/content_type_element.rb +8 -4
- data/lib/mail/elements/date_time_element.rb +1 -1
- data/lib/mail/elements/envelope_from_element.rb +13 -7
- data/lib/mail/elements/message_ids_element.rb +14 -5
- data/lib/mail/elements/mime_version_element.rb +1 -1
- data/lib/mail/elements/phrase_list.rb +7 -2
- data/lib/mail/elements/received_element.rb +20 -6
- data/lib/mail/encodings/7bit.rb +5 -0
- data/lib/mail/encodings/base64.rb +2 -2
- data/lib/mail/encodings/quoted_printable.rb +2 -2
- data/lib/mail/encodings.rb +30 -59
- data/lib/mail/envelope.rb +11 -14
- data/lib/mail/field.rb +37 -53
- data/lib/mail/field_list.rb +60 -7
- data/lib/mail/fields/bcc_field.rb +34 -52
- data/lib/mail/fields/cc_field.rb +28 -49
- data/lib/mail/fields/comments_field.rb +27 -37
- data/lib/mail/fields/common_address_field.rb +170 -0
- data/lib/mail/fields/common_date_field.rb +58 -0
- data/lib/mail/fields/common_field.rb +77 -0
- data/lib/mail/fields/common_message_id_field.rb +42 -0
- data/lib/mail/fields/content_description_field.rb +7 -14
- data/lib/mail/fields/content_disposition_field.rb +13 -38
- data/lib/mail/fields/content_id_field.rb +24 -51
- data/lib/mail/fields/content_location_field.rb +11 -25
- data/lib/mail/fields/content_transfer_encoding_field.rb +31 -31
- data/lib/mail/fields/content_type_field.rb +46 -71
- data/lib/mail/fields/date_field.rb +23 -51
- data/lib/mail/fields/from_field.rb +28 -49
- data/lib/mail/fields/in_reply_to_field.rb +38 -49
- data/lib/mail/fields/keywords_field.rb +18 -31
- data/lib/mail/fields/message_id_field.rb +25 -71
- data/lib/mail/fields/mime_version_field.rb +19 -30
- data/lib/mail/fields/named_structured_field.rb +11 -0
- data/lib/mail/fields/named_unstructured_field.rb +11 -0
- data/lib/mail/fields/optional_field.rb +5 -6
- data/lib/mail/fields/{common/parameter_hash.rb → parameter_hash.rb} +12 -10
- data/lib/mail/fields/received_field.rb +43 -57
- data/lib/mail/fields/references_field.rb +35 -49
- data/lib/mail/fields/reply_to_field.rb +28 -49
- data/lib/mail/fields/resent_bcc_field.rb +28 -49
- data/lib/mail/fields/resent_cc_field.rb +28 -49
- data/lib/mail/fields/resent_date_field.rb +5 -29
- data/lib/mail/fields/resent_from_field.rb +28 -49
- data/lib/mail/fields/resent_message_id_field.rb +5 -29
- data/lib/mail/fields/resent_sender_field.rb +27 -56
- data/lib/mail/fields/resent_to_field.rb +28 -49
- data/lib/mail/fields/return_path_field.rb +50 -54
- data/lib/mail/fields/sender_field.rb +34 -55
- data/lib/mail/fields/structured_field.rb +3 -30
- data/lib/mail/fields/subject_field.rb +9 -11
- data/lib/mail/fields/to_field.rb +28 -49
- data/lib/mail/fields/unstructured_field.rb +16 -48
- data/lib/mail/header.rb +69 -110
- data/lib/mail/matchers/attachment_matchers.rb +15 -0
- data/lib/mail/message.rb +46 -64
- data/lib/mail/multibyte/chars.rb +8 -166
- data/lib/mail/multibyte/utils.rb +26 -43
- data/lib/mail/multibyte.rb +1 -11
- data/lib/mail/network/delivery_methods/exim.rb +5 -4
- data/lib/mail/network/delivery_methods/file_delivery.rb +11 -10
- data/lib/mail/network/delivery_methods/logger_delivery.rb +2 -5
- data/lib/mail/network/delivery_methods/sendmail.rb +27 -35
- data/lib/mail/network/delivery_methods/smtp.rb +3 -3
- data/lib/mail/network/delivery_methods/smtp_connection.rb +3 -12
- data/lib/mail/network/delivery_methods/test_mailer.rb +4 -2
- data/lib/mail/network/retriever_methods/base.rb +8 -8
- data/lib/mail/network/retriever_methods/imap.rb +2 -2
- data/lib/mail/network/retriever_methods/pop3.rb +2 -2
- data/lib/mail/network/retriever_methods/test_retriever.rb +2 -1
- data/lib/mail/parsers/address_lists_parser.rb +33070 -33064
- data/lib/mail/parsers/address_lists_parser.rl +7 -0
- data/lib/mail/parsers/content_disposition_parser.rb +833 -827
- data/lib/mail/parsers/content_disposition_parser.rl +7 -0
- data/lib/mail/parsers/content_location_parser.rb +770 -764
- data/lib/mail/parsers/content_location_parser.rl +7 -0
- data/lib/mail/parsers/content_transfer_encoding_parser.rb +474 -468
- data/lib/mail/parsers/content_transfer_encoding_parser.rl +7 -0
- data/lib/mail/parsers/content_type_parser.rb +971 -965
- data/lib/mail/parsers/content_type_parser.rl +7 -0
- data/lib/mail/parsers/date_time_parser.rb +838 -832
- data/lib/mail/parsers/date_time_parser.rl +7 -0
- data/lib/mail/parsers/envelope_from_parser.rb +3623 -3529
- data/lib/mail/parsers/envelope_from_parser.rl +7 -0
- data/lib/mail/parsers/message_ids_parser.rb +5107 -2800
- data/lib/mail/parsers/message_ids_parser.rl +12 -1
- data/lib/mail/parsers/mime_version_parser.rb +463 -457
- data/lib/mail/parsers/mime_version_parser.rl +7 -0
- data/lib/mail/parsers/phrase_lists_parser.rb +836 -830
- data/lib/mail/parsers/phrase_lists_parser.rl +8 -1
- data/lib/mail/parsers/received_parser.rb +8688 -8682
- data/lib/mail/parsers/received_parser.rl +7 -0
- data/lib/mail/parsers/rfc5322.rl +28 -13
- data/lib/mail/parsers.rb +11 -17
- data/lib/mail/part.rb +5 -9
- data/lib/mail/parts_list.rb +57 -0
- data/lib/mail/smtp_envelope.rb +57 -0
- data/lib/mail/utilities.rb +307 -69
- data/lib/mail/version.rb +3 -3
- data/lib/mail/yaml.rb +30 -0
- data/lib/mail.rb +0 -20
- metadata +74 -21
- data/lib/mail/check_delivery_params.rb +0 -60
- data/lib/mail/core_extensions/smtp.rb +0 -28
- data/lib/mail/core_extensions/string.rb +0 -17
- data/lib/mail/fields/common/address_container.rb +0 -17
- data/lib/mail/fields/common/common_address.rb +0 -161
- data/lib/mail/fields/common/common_date.rb +0 -36
- data/lib/mail/fields/common/common_field.rb +0 -52
- data/lib/mail/fields/common/common_message_id.rb +0 -49
- data/lib/mail/version_specific/ruby_1_8.rb +0 -163
- data/lib/mail/version_specific/ruby_1_9.rb +0 -278
@@ -1,13 +1,13 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
# frozen_string_literal: true
|
3
|
-
require 'mail/fields/
|
3
|
+
require 'mail/fields/common_field'
|
4
4
|
|
5
5
|
module Mail
|
6
6
|
# Provides access to a structured header field
|
7
7
|
#
|
8
8
|
# ===Per RFC 2822:
|
9
9
|
# 2.2.2. Structured Header Field Bodies
|
10
|
-
#
|
10
|
+
#
|
11
11
|
# Some field bodies in this standard have specific syntactical
|
12
12
|
# structure more restrictive than the unstructured field bodies
|
13
13
|
# described above. These are referred to as "structured" field bodies.
|
@@ -20,33 +20,6 @@ module Mail
|
|
20
20
|
# characters are subject to header "folding" and "unfolding" as
|
21
21
|
# described in section 2.2.3. Semantic analysis of structured field
|
22
22
|
# bodies is given along with their syntax.
|
23
|
-
class StructuredField
|
24
|
-
|
25
|
-
include Mail::CommonField
|
26
|
-
include Mail::Utilities
|
27
|
-
|
28
|
-
def initialize(name = nil, value = nil, charset = nil)
|
29
|
-
self.name = name
|
30
|
-
self.value = value
|
31
|
-
self.charset = charset
|
32
|
-
self
|
33
|
-
end
|
34
|
-
|
35
|
-
def charset
|
36
|
-
@charset
|
37
|
-
end
|
38
|
-
|
39
|
-
def charset=(val)
|
40
|
-
@charset = val
|
41
|
-
end
|
42
|
-
|
43
|
-
def default
|
44
|
-
decoded
|
45
|
-
end
|
46
|
-
|
47
|
-
def errors
|
48
|
-
[]
|
49
|
-
end
|
50
|
-
|
23
|
+
class StructuredField < CommonField #:nodoc:
|
51
24
|
end
|
52
25
|
end
|
@@ -1,17 +1,15 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
# frozen_string_literal: true
|
3
|
-
|
4
|
-
|
3
|
+
require 'mail/fields/named_unstructured_field'
|
4
|
+
|
5
5
|
module Mail
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
def
|
12
|
-
|
13
|
-
super(CAPITALIZED_FIELD, value, charset)
|
6
|
+
#
|
7
|
+
# subject = "Subject:" unstructured CRLF
|
8
|
+
class SubjectField < NamedUnstructuredField #:nodoc:
|
9
|
+
NAME = 'Subject'
|
10
|
+
|
11
|
+
def self.singular?
|
12
|
+
true
|
14
13
|
end
|
15
|
-
|
16
14
|
end
|
17
15
|
end
|
data/lib/mail/fields/to_field.rb
CHANGED
@@ -1,55 +1,34 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
# frozen_string_literal: true
|
3
|
-
|
4
|
-
# = To Field
|
5
|
-
#
|
6
|
-
# The To field inherits to StructuredField and handles the To: header
|
7
|
-
# field in the email.
|
8
|
-
#
|
9
|
-
# Sending to to a mail message will instantiate a Mail::Field object that
|
10
|
-
# has a ToField as its field type. This includes all Mail::CommonAddress
|
11
|
-
# module instance metods.
|
12
|
-
#
|
13
|
-
# Only one To field can appear in a header, though it can have multiple
|
14
|
-
# addresses and groups of addresses.
|
15
|
-
#
|
16
|
-
# == Examples:
|
17
|
-
#
|
18
|
-
# mail = Mail.new
|
19
|
-
# mail.to = 'Mikel Lindsaar <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
|
20
|
-
# mail.to #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
|
21
|
-
# mail[:to] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::ToField:0x180e1c4
|
22
|
-
# mail['to'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::ToField:0x180e1c4
|
23
|
-
# mail['To'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::ToField:0x180e1c4
|
24
|
-
#
|
25
|
-
# mail[:to].encoded #=> 'To: Mikel Lindsaar <mikel@test.lindsaar.net>, ada@test.lindsaar.net\r\n'
|
26
|
-
# mail[:to].decoded #=> 'Mikel Lindsaar <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
|
27
|
-
# mail[:to].addresses #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
|
28
|
-
# mail[:to].formatted #=> ['Mikel Lindsaar <mikel@test.lindsaar.net>', 'ada@test.lindsaar.net']
|
29
|
-
#
|
30
|
-
require 'mail/fields/common/common_address'
|
3
|
+
require 'mail/fields/common_address_field'
|
31
4
|
|
32
5
|
module Mail
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
6
|
+
# = To Field
|
7
|
+
#
|
8
|
+
# The To field inherits to StructuredField and handles the To: header
|
9
|
+
# field in the email.
|
10
|
+
#
|
11
|
+
# Sending to to a mail message will instantiate a Mail::Field object that
|
12
|
+
# has a ToField as its field type. This includes all Mail::CommonAddress
|
13
|
+
# module instance metods.
|
14
|
+
#
|
15
|
+
# Only one To field can appear in a header, though it can have multiple
|
16
|
+
# addresses and groups of addresses.
|
17
|
+
#
|
18
|
+
# == Examples:
|
19
|
+
#
|
20
|
+
# mail = Mail.new
|
21
|
+
# mail.to = 'Mikel Lindsaar <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
|
22
|
+
# mail.to #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
|
23
|
+
# mail[:to] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::ToField:0x180e1c4
|
24
|
+
# mail['to'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::ToField:0x180e1c4
|
25
|
+
# mail['To'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::ToField:0x180e1c4
|
26
|
+
#
|
27
|
+
# mail[:to].encoded #=> 'To: Mikel Lindsaar <mikel@test.lindsaar.net>, ada@test.lindsaar.net\r\n'
|
28
|
+
# mail[:to].decoded #=> 'Mikel Lindsaar <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
|
29
|
+
# mail[:to].addresses #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
|
30
|
+
# mail[:to].formatted #=> ['Mikel Lindsaar <mikel@test.lindsaar.net>', 'ada@test.lindsaar.net']
|
31
|
+
class ToField < CommonAddressField #:nodoc:
|
32
|
+
NAME = 'To'
|
54
33
|
end
|
55
34
|
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
# frozen_string_literal: true
|
3
|
-
require 'mail/fields/
|
3
|
+
require 'mail/fields/common_field'
|
4
|
+
require 'mail/utilities'
|
4
5
|
|
5
6
|
module Mail
|
6
7
|
# Provides access to an unstructured header field
|
@@ -15,58 +16,28 @@ module Mail
|
|
15
16
|
# field bodies are simply to be treated as a single line of characters
|
16
17
|
# with no further processing (except for header "folding" and
|
17
18
|
# "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
|
-
|
19
|
+
class UnstructuredField < CommonField #:nodoc:
|
26
20
|
def initialize(name, value, charset = nil)
|
27
|
-
@errors = []
|
28
|
-
|
29
21
|
if value.is_a?(Array)
|
30
22
|
# Probably has arrived here from a failed parse of an AddressList Field
|
31
23
|
value = value.join(', ')
|
32
|
-
else
|
33
|
-
# Ensure we are dealing with a string
|
34
|
-
value = value.to_s
|
35
24
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
end
|
25
|
+
# Mark UTF-8 strings parsed from ASCII-8BIT
|
26
|
+
elsif value.respond_to?(:force_encoding) && value.encoding == Encoding::ASCII_8BIT
|
27
|
+
utf8 = value.dup.force_encoding(Encoding::UTF_8)
|
28
|
+
value = utf8 if utf8.valid_encoding?
|
41
29
|
end
|
42
30
|
|
43
|
-
|
44
|
-
self.charset = charset
|
45
|
-
else
|
31
|
+
charset ||=
|
46
32
|
if value.respond_to?(:encoding)
|
47
|
-
|
48
|
-
else
|
49
|
-
self.charset = $KCODE
|
33
|
+
value.encoding
|
50
34
|
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
35
|
|
61
|
-
|
62
|
-
do_decode
|
36
|
+
super name, value.to_s, charset
|
63
37
|
end
|
64
38
|
|
65
|
-
|
66
|
-
|
67
|
-
end
|
68
|
-
|
69
|
-
def parse # An unstructured field does not parse
|
39
|
+
# An unstructured field does not parse
|
40
|
+
def parse
|
70
41
|
self
|
71
42
|
end
|
72
43
|
|
@@ -196,7 +167,7 @@ module Mail
|
|
196
167
|
end
|
197
168
|
|
198
169
|
def encode(value)
|
199
|
-
value = [value].pack(CAPITAL_M).gsub(EQUAL_LF, EMPTY)
|
170
|
+
value = [value].pack(Constants::CAPITAL_M).gsub(Constants::EQUAL_LF, Constants::EMPTY)
|
200
171
|
value.gsub!(/"/, '=22')
|
201
172
|
value.gsub!(/\(/, '=28')
|
202
173
|
value.gsub!(/\)/, '=29')
|
@@ -207,16 +178,13 @@ module Mail
|
|
207
178
|
end
|
208
179
|
|
209
180
|
def encode_crlf(value)
|
210
|
-
value.gsub!(CR, CR_ENCODED)
|
211
|
-
value.gsub!(LF, LF_ENCODED)
|
181
|
+
value.gsub!(Constants::CR, Constants::CR_ENCODED)
|
182
|
+
value.gsub!(Constants::LF, Constants::LF_ENCODED)
|
212
183
|
value
|
213
184
|
end
|
214
185
|
|
215
186
|
def normalized_encoding
|
216
|
-
|
217
|
-
encoding = 'UTF-8' if encoding == 'UTF8' # Ruby 1.8.x and $KCODE == 'u'
|
218
|
-
encoding
|
187
|
+
charset.to_s.upcase.gsub('_', '-')
|
219
188
|
end
|
220
|
-
|
221
189
|
end
|
222
190
|
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
|
-
|
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
|
-
|
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
|
-
|
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 =
|
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
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
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
|
-
|
182
|
-
|
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
|
-
|
187
|
-
|
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
|
-
|
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
|
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.
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
@@ -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
|