mail 2.6.1 → 2.8.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.
- checksums.yaml +5 -5
- data/MIT-LICENSE +1 -1
- data/README.md +150 -107
- data/lib/mail/attachments_list.rb +13 -10
- data/lib/mail/body.rb +104 -90
- data/lib/mail/check_delivery_params.rb +55 -10
- data/lib/mail/configuration.rb +3 -0
- data/lib/mail/constants.rb +79 -0
- data/lib/mail/elements/address.rb +96 -108
- data/lib/mail/elements/address_list.rb +13 -30
- data/lib/mail/elements/content_disposition_element.rb +10 -16
- data/lib/mail/elements/content_location_element.rb +9 -13
- data/lib/mail/elements/content_transfer_encoding_element.rb +7 -11
- data/lib/mail/elements/content_type_element.rb +17 -23
- data/lib/mail/elements/date_time_element.rb +8 -15
- data/lib/mail/elements/envelope_from_element.rb +23 -23
- data/lib/mail/elements/message_ids_element.rb +22 -15
- data/lib/mail/elements/mime_version_element.rb +8 -15
- data/lib/mail/elements/phrase_list.rb +13 -10
- data/lib/mail/elements/received_element.rb +28 -19
- data/lib/mail/elements.rb +1 -0
- data/lib/mail/encodings/7bit.rb +10 -14
- data/lib/mail/encodings/8bit.rb +5 -18
- data/lib/mail/encodings/base64.rb +15 -10
- data/lib/mail/encodings/binary.rb +4 -22
- data/lib/mail/encodings/identity.rb +24 -0
- data/lib/mail/encodings/quoted_printable.rb +13 -7
- data/lib/mail/encodings/transfer_encoding.rb +47 -28
- data/lib/mail/encodings/unix_to_unix.rb +20 -0
- data/lib/mail/encodings.rb +102 -92
- data/lib/mail/envelope.rb +12 -14
- data/lib/mail/field.rb +121 -85
- data/lib/mail/field_list.rb +62 -8
- data/lib/mail/fields/bcc_field.rb +42 -48
- data/lib/mail/fields/cc_field.rb +29 -50
- data/lib/mail/fields/comments_field.rb +28 -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 +8 -14
- data/lib/mail/fields/content_disposition_field.rb +20 -44
- data/lib/mail/fields/content_id_field.rb +25 -51
- data/lib/mail/fields/content_location_field.rb +12 -25
- data/lib/mail/fields/content_transfer_encoding_field.rb +32 -31
- data/lib/mail/fields/content_type_field.rb +51 -80
- data/lib/mail/fields/date_field.rb +24 -52
- data/lib/mail/fields/from_field.rb +29 -50
- data/lib/mail/fields/in_reply_to_field.rb +39 -49
- data/lib/mail/fields/keywords_field.rb +19 -32
- data/lib/mail/fields/message_id_field.rb +26 -71
- data/lib/mail/fields/mime_version_field.rb +20 -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 +10 -7
- data/lib/mail/fields/{common/parameter_hash.rb → parameter_hash.rb} +16 -13
- data/lib/mail/fields/received_field.rb +44 -57
- data/lib/mail/fields/references_field.rb +36 -49
- data/lib/mail/fields/reply_to_field.rb +29 -50
- data/lib/mail/fields/resent_bcc_field.rb +29 -50
- data/lib/mail/fields/resent_cc_field.rb +29 -50
- data/lib/mail/fields/resent_date_field.rb +6 -30
- data/lib/mail/fields/resent_from_field.rb +29 -50
- data/lib/mail/fields/resent_message_id_field.rb +6 -29
- data/lib/mail/fields/resent_sender_field.rb +28 -57
- data/lib/mail/fields/resent_to_field.rb +29 -50
- data/lib/mail/fields/return_path_field.rb +51 -55
- data/lib/mail/fields/sender_field.rb +35 -56
- data/lib/mail/fields/structured_field.rb +4 -30
- data/lib/mail/fields/subject_field.rb +10 -11
- data/lib/mail/fields/to_field.rb +29 -50
- data/lib/mail/fields/unstructured_field.rb +36 -50
- data/lib/mail/fields.rb +1 -0
- data/lib/mail/header.rb +73 -110
- data/lib/mail/indifferent_hash.rb +1 -0
- data/lib/mail/mail.rb +6 -11
- data/lib/mail/matchers/attachment_matchers.rb +44 -0
- data/lib/mail/matchers/has_sent_mail.rb +53 -9
- data/lib/mail/message.rb +132 -136
- data/lib/mail/multibyte/chars.rb +24 -180
- data/lib/mail/multibyte/unicode.rb +31 -26
- data/lib/mail/multibyte/utils.rb +27 -43
- data/lib/mail/multibyte.rb +56 -16
- data/lib/mail/network/delivery_methods/exim.rb +9 -11
- data/lib/mail/network/delivery_methods/file_delivery.rb +14 -16
- data/lib/mail/network/delivery_methods/logger_delivery.rb +34 -0
- data/lib/mail/network/delivery_methods/sendmail.rb +68 -24
- data/lib/mail/network/delivery_methods/smtp.rb +77 -54
- data/lib/mail/network/delivery_methods/smtp_connection.rb +5 -9
- data/lib/mail/network/delivery_methods/test_mailer.rb +9 -9
- data/lib/mail/network/retriever_methods/base.rb +9 -8
- data/lib/mail/network/retriever_methods/imap.rb +21 -7
- data/lib/mail/network/retriever_methods/pop3.rb +6 -3
- data/lib/mail/network/retriever_methods/test_retriever.rb +4 -2
- data/lib/mail/network.rb +2 -0
- data/lib/mail/parser_tools.rb +15 -0
- data/lib/mail/parsers/address_lists_parser.rb +33226 -116
- data/lib/mail/parsers/address_lists_parser.rl +179 -0
- data/lib/mail/parsers/content_disposition_parser.rb +883 -49
- data/lib/mail/parsers/content_disposition_parser.rl +89 -0
- data/lib/mail/parsers/content_location_parser.rb +810 -23
- data/lib/mail/parsers/content_location_parser.rl +78 -0
- data/lib/mail/parsers/content_transfer_encoding_parser.rb +510 -21
- data/lib/mail/parsers/content_transfer_encoding_parser.rl +71 -0
- data/lib/mail/parsers/content_type_parser.rb +1031 -47
- data/lib/mail/parsers/content_type_parser.rl +90 -0
- data/lib/mail/parsers/date_time_parser.rb +879 -24
- data/lib/mail/parsers/date_time_parser.rl +69 -0
- data/lib/mail/parsers/envelope_from_parser.rb +3670 -40
- data/lib/mail/parsers/envelope_from_parser.rl +89 -0
- data/lib/mail/parsers/message_ids_parser.rb +5147 -25
- data/lib/mail/parsers/message_ids_parser.rl +93 -0
- data/lib/mail/parsers/mime_version_parser.rb +498 -26
- data/lib/mail/parsers/mime_version_parser.rl +68 -0
- data/lib/mail/parsers/phrase_lists_parser.rb +872 -21
- data/lib/mail/parsers/phrase_lists_parser.rl +90 -0
- data/lib/mail/parsers/received_parser.rb +8777 -42
- data/lib/mail/parsers/received_parser.rl +91 -0
- data/lib/mail/parsers/rfc2045_content_transfer_encoding.rl +13 -0
- data/lib/mail/parsers/rfc2045_content_type.rl +25 -0
- data/lib/mail/parsers/rfc2045_mime.rl +16 -0
- data/lib/mail/parsers/rfc2183_content_disposition.rl +15 -0
- data/lib/mail/parsers/rfc3629_utf8.rl +19 -0
- data/lib/mail/parsers/rfc5234_abnf_core_rules.rl +22 -0
- data/lib/mail/parsers/rfc5322.rl +74 -0
- data/lib/mail/parsers/rfc5322_address.rl +72 -0
- data/lib/mail/parsers/{ragel/date_time.rl → rfc5322_date_time.rl} +8 -1
- data/lib/mail/parsers/rfc5322_lexical_tokens.rl +60 -0
- data/lib/mail/parsers.rb +12 -25
- data/lib/mail/part.rb +11 -12
- data/lib/mail/parts_list.rb +88 -14
- data/lib/mail/smtp_envelope.rb +57 -0
- data/lib/mail/utilities.rb +377 -40
- data/lib/mail/values/unicode_tables.dat +0 -0
- data/lib/mail/version.rb +8 -15
- data/lib/mail/yaml.rb +30 -0
- data/lib/mail.rb +9 -32
- metadata +138 -94
- data/CHANGELOG.rdoc +0 -752
- data/CONTRIBUTING.md +0 -60
- data/Dependencies.txt +0 -2
- data/Gemfile +0 -15
- data/Rakefile +0 -29
- data/TODO.rdoc +0 -9
- data/VERSION +0 -4
- data/lib/mail/core_extensions/nil.rb +0 -19
- data/lib/mail/core_extensions/object.rb +0 -13
- data/lib/mail/core_extensions/smtp.rb +0 -24
- data/lib/mail/core_extensions/string/access.rb +0 -145
- data/lib/mail/core_extensions/string/multibyte.rb +0 -78
- data/lib/mail/core_extensions/string.rb +0 -43
- data/lib/mail/fields/common/address_container.rb +0 -16
- data/lib/mail/fields/common/common_address.rb +0 -135
- data/lib/mail/fields/common/common_date.rb +0 -35
- data/lib/mail/fields/common/common_field.rb +0 -57
- data/lib/mail/fields/common/common_message_id.rb +0 -48
- data/lib/mail/multibyte/exceptions.rb +0 -8
- data/lib/mail/parsers/ragel/common.rl +0 -184
- data/lib/mail/parsers/ragel/parser_info.rb +0 -61
- data/lib/mail/parsers/ragel/ruby/machines/address_lists_machine.rb +0 -14864
- data/lib/mail/parsers/ragel/ruby/machines/address_lists_machine.rb.rl +0 -37
- data/lib/mail/parsers/ragel/ruby/machines/content_disposition_machine.rb +0 -751
- data/lib/mail/parsers/ragel/ruby/machines/content_disposition_machine.rb.rl +0 -37
- data/lib/mail/parsers/ragel/ruby/machines/content_location_machine.rb +0 -614
- data/lib/mail/parsers/ragel/ruby/machines/content_location_machine.rb.rl +0 -37
- data/lib/mail/parsers/ragel/ruby/machines/content_transfer_encoding_machine.rb +0 -447
- data/lib/mail/parsers/ragel/ruby/machines/content_transfer_encoding_machine.rb.rl +0 -37
- data/lib/mail/parsers/ragel/ruby/machines/content_type_machine.rb +0 -825
- data/lib/mail/parsers/ragel/ruby/machines/content_type_machine.rb.rl +0 -37
- data/lib/mail/parsers/ragel/ruby/machines/date_time_machine.rb +0 -817
- data/lib/mail/parsers/ragel/ruby/machines/date_time_machine.rb.rl +0 -37
- data/lib/mail/parsers/ragel/ruby/machines/envelope_from_machine.rb +0 -2129
- data/lib/mail/parsers/ragel/ruby/machines/envelope_from_machine.rb.rl +0 -37
- data/lib/mail/parsers/ragel/ruby/machines/message_ids_machine.rb +0 -1570
- data/lib/mail/parsers/ragel/ruby/machines/message_ids_machine.rb.rl +0 -37
- data/lib/mail/parsers/ragel/ruby/machines/mime_version_machine.rb +0 -440
- data/lib/mail/parsers/ragel/ruby/machines/mime_version_machine.rb.rl +0 -37
- data/lib/mail/parsers/ragel/ruby/machines/phrase_lists_machine.rb +0 -564
- data/lib/mail/parsers/ragel/ruby/machines/phrase_lists_machine.rb.rl +0 -37
- data/lib/mail/parsers/ragel/ruby/machines/rb_actions.rl +0 -51
- data/lib/mail/parsers/ragel/ruby/machines/received_machine.rb +0 -5144
- data/lib/mail/parsers/ragel/ruby/machines/received_machine.rb.rl +0 -37
- data/lib/mail/parsers/ragel/ruby/parser.rb.rl.erb +0 -37
- data/lib/mail/parsers/ragel/ruby.rb +0 -39
- data/lib/mail/parsers/ragel.rb +0 -17
- data/lib/mail/patterns.rb +0 -37
- data/lib/mail/version_specific/ruby_1_8.rb +0 -119
- data/lib/mail/version_specific/ruby_1_9.rb +0 -159
@@ -1,5 +1,7 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
-
|
2
|
+
# frozen_string_literal: true
|
3
|
+
require 'mail/fields/common_field'
|
4
|
+
require 'mail/utilities'
|
3
5
|
|
4
6
|
module Mail
|
5
7
|
# Provides access to an unstructured header field
|
@@ -14,63 +16,43 @@ module Mail
|
|
14
16
|
# field bodies are simply to be treated as a single line of characters
|
15
17
|
# with no further processing (except for header "folding" and
|
16
18
|
# "unfolding" as described in section 2.2.3).
|
17
|
-
class UnstructuredField
|
18
|
-
|
19
|
-
include Mail::CommonField
|
20
|
-
include Mail::Utilities
|
21
|
-
|
22
|
-
attr_accessor :charset
|
23
|
-
attr_reader :errors
|
24
|
-
|
19
|
+
class UnstructuredField < CommonField #:nodoc:
|
25
20
|
def initialize(name, value, charset = nil)
|
26
|
-
@errors = []
|
27
|
-
|
28
21
|
if value.is_a?(Array)
|
29
22
|
# Probably has arrived here from a failed parse of an AddressList Field
|
30
23
|
value = value.join(', ')
|
31
|
-
|
32
|
-
|
33
|
-
|
24
|
+
|
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?
|
34
29
|
end
|
35
30
|
|
36
|
-
|
37
|
-
self.charset = charset
|
38
|
-
else
|
31
|
+
charset ||=
|
39
32
|
if value.respond_to?(:encoding)
|
40
|
-
|
41
|
-
else
|
42
|
-
self.charset = $KCODE
|
33
|
+
value.encoding
|
43
34
|
end
|
44
|
-
end
|
45
|
-
self.name = name
|
46
|
-
self.value = value
|
47
|
-
self
|
48
|
-
end
|
49
35
|
|
50
|
-
|
51
|
-
do_encode
|
36
|
+
super name, value.to_s, charset
|
52
37
|
end
|
53
38
|
|
54
|
-
|
55
|
-
|
56
|
-
end
|
57
|
-
|
58
|
-
def default
|
59
|
-
decoded
|
60
|
-
end
|
61
|
-
|
62
|
-
def parse # An unstructured field does not parse
|
39
|
+
# An unstructured field does not parse
|
40
|
+
def parse
|
63
41
|
self
|
64
42
|
end
|
65
43
|
|
66
44
|
private
|
67
45
|
|
68
46
|
def do_encode
|
69
|
-
value.
|
47
|
+
if value && !value.empty?
|
48
|
+
"#{wrapped_value}\r\n"
|
49
|
+
else
|
50
|
+
''
|
51
|
+
end
|
70
52
|
end
|
71
53
|
|
72
54
|
def do_decode
|
73
|
-
|
55
|
+
Utilities.blank?(value) ? nil : Encodings.decode_encode(value, :decode)
|
74
56
|
end
|
75
57
|
|
76
58
|
# 2.2.3. Long Header Fields
|
@@ -120,16 +102,16 @@ module Mail
|
|
120
102
|
def fold(prepend = 0) # :nodoc:
|
121
103
|
encoding = normalized_encoding
|
122
104
|
decoded_string = decoded.to_s
|
123
|
-
should_encode = decoded_string.
|
105
|
+
should_encode = !decoded_string.ascii_only?
|
124
106
|
if should_encode
|
125
107
|
first = true
|
126
108
|
words = decoded_string.split(/[ \t]/).map do |word|
|
127
109
|
if first
|
128
110
|
first = !first
|
129
111
|
else
|
130
|
-
word = " "
|
112
|
+
word = " #{word}"
|
131
113
|
end
|
132
|
-
if word.
|
114
|
+
if !word.ascii_only?
|
133
115
|
word
|
134
116
|
else
|
135
117
|
word.scan(/.{7}|.+$/)
|
@@ -143,11 +125,18 @@ module Mail
|
|
143
125
|
while !words.empty?
|
144
126
|
limit = 78 - prepend
|
145
127
|
limit = limit - 7 - encoding.length if should_encode
|
146
|
-
line =
|
128
|
+
line = String.new
|
147
129
|
first_word = true
|
148
130
|
while !words.empty?
|
149
131
|
break unless word = words.first.dup
|
150
|
-
|
132
|
+
|
133
|
+
# Convert on 1.9+ only since we aren't sure of the current
|
134
|
+
# charset encoding on 1.8. We'd need to track internal/external
|
135
|
+
# charset on each field.
|
136
|
+
if charset && word.respond_to?(:encoding)
|
137
|
+
word = Encodings.transcode_charset(word, word.encoding, charset)
|
138
|
+
end
|
139
|
+
|
151
140
|
word = encode(word) if should_encode
|
152
141
|
word = encode_crlf(word)
|
153
142
|
# Skip to next line if we're going to go past the limit
|
@@ -178,7 +167,7 @@ module Mail
|
|
178
167
|
end
|
179
168
|
|
180
169
|
def encode(value)
|
181
|
-
value = [value].pack(
|
170
|
+
value = [value].pack(Constants::CAPITAL_M).gsub(Constants::EQUAL_LF, Constants::EMPTY)
|
182
171
|
value.gsub!(/"/, '=22')
|
183
172
|
value.gsub!(/\(/, '=28')
|
184
173
|
value.gsub!(/\)/, '=29')
|
@@ -189,16 +178,13 @@ module Mail
|
|
189
178
|
end
|
190
179
|
|
191
180
|
def encode_crlf(value)
|
192
|
-
value.gsub!(
|
193
|
-
value.gsub!(
|
181
|
+
value.gsub!(Constants::CR, Constants::CR_ENCODED)
|
182
|
+
value.gsub!(Constants::LF, Constants::LF_ENCODED)
|
194
183
|
value
|
195
184
|
end
|
196
185
|
|
197
186
|
def normalized_encoding
|
198
|
-
|
199
|
-
encoding = 'UTF-8' if encoding == 'UTF8' # Ruby 1.8.x and $KCODE == 'u'
|
200
|
-
encoding
|
187
|
+
charset.to_s.upcase.gsub('_', '-')
|
201
188
|
end
|
202
|
-
|
203
189
|
end
|
204
190
|
end
|
data/lib/mail/fields.rb
CHANGED
data/lib/mail/header.rb
CHANGED
@@ -1,12 +1,15 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
require 'mail/constants'
|
4
|
+
require 'mail/utilities'
|
5
|
+
|
2
6
|
module Mail
|
3
|
-
|
4
7
|
# Provides access to a header object.
|
5
|
-
#
|
8
|
+
#
|
6
9
|
# ===Per RFC2822
|
7
|
-
#
|
10
|
+
#
|
8
11
|
# 2.2. Header Fields
|
9
|
-
#
|
12
|
+
#
|
10
13
|
# Header fields are lines composed of a field name, followed by a colon
|
11
14
|
# (":"), followed by a field body, and terminated by CRLF. A field
|
12
15
|
# name MUST be composed of printable US-ASCII characters (i.e.,
|
@@ -17,14 +20,12 @@ module Mail
|
|
17
20
|
# 2.2.3. All field bodies MUST conform to the syntax described in
|
18
21
|
# sections 3 and 4 of this standard.
|
19
22
|
class Header
|
20
|
-
include Patterns
|
21
|
-
include Utilities
|
22
23
|
include Enumerable
|
23
|
-
|
24
|
+
|
24
25
|
@@maximum_amount = 1000
|
25
26
|
|
26
27
|
# Large amount of headers in Email might create extra high CPU load
|
27
|
-
# 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
|
28
29
|
# mail library.
|
29
30
|
# Default: 1000
|
30
31
|
def self.maximum_amount
|
@@ -35,12 +36,14 @@ module Mail
|
|
35
36
|
@@maximum_amount = value
|
36
37
|
end
|
37
38
|
|
39
|
+
attr_reader :raw_source, :charset
|
40
|
+
|
38
41
|
# Creates a new header object.
|
39
|
-
#
|
42
|
+
#
|
40
43
|
# Accepts raw text or nothing. If given raw text will attempt to parse
|
41
44
|
# it and split it into the various fields, instantiating each field as
|
42
45
|
# it goes.
|
43
|
-
#
|
46
|
+
#
|
44
47
|
# If it finds a field that should be a structured field (such as content
|
45
48
|
# type), but it fails to parse it, it will simply make it an unstructured
|
46
49
|
# field and leave it alone. This will mean that the data is preserved but
|
@@ -49,29 +52,24 @@ module Mail
|
|
49
52
|
# me the example so we can fix it.
|
50
53
|
def initialize(header_text = nil, charset = nil)
|
51
54
|
@charset = charset
|
52
|
-
|
55
|
+
@raw_source = ::Mail::Utilities.to_crlf(header_text).lstrip
|
53
56
|
split_header if header_text
|
54
57
|
end
|
55
58
|
|
56
59
|
def initialize_copy(original)
|
57
60
|
super
|
58
61
|
@fields = @fields.dup
|
62
|
+
@fields.map!(&:dup)
|
59
63
|
end
|
60
|
-
|
61
|
-
# The preserved raw source of the header as you passed it in, untouched
|
62
|
-
# for your Regexing glory.
|
63
|
-
def raw_source
|
64
|
-
@raw_source
|
65
|
-
end
|
66
|
-
|
64
|
+
|
67
65
|
# Returns an array of all the fields in the header in order that they
|
68
66
|
# were read in.
|
69
67
|
def fields
|
70
68
|
@fields ||= FieldList.new
|
71
69
|
end
|
72
|
-
|
70
|
+
|
73
71
|
# 3.6. Field definitions
|
74
|
-
#
|
72
|
+
#
|
75
73
|
# It is important to note that the header fields are not guaranteed to
|
76
74
|
# be in a particular order. They may appear in any order, and they
|
77
75
|
# have been known to be reordered occasionally when transported over
|
@@ -81,35 +79,35 @@ module Mail
|
|
81
79
|
# header fields MUST NOT be reordered, and SHOULD be kept in blocks
|
82
80
|
# prepended to the message. See sections 3.6.6 and 3.6.7 for more
|
83
81
|
# information.
|
84
|
-
#
|
82
|
+
#
|
85
83
|
# Populates the fields container with Field objects in the order it
|
86
84
|
# receives them in.
|
87
85
|
#
|
88
86
|
# Acceps an array of field string values, for example:
|
89
|
-
#
|
87
|
+
#
|
90
88
|
# h = Header.new
|
91
89
|
# h.fields = ['From: mikel@me.com', 'To: bob@you.com']
|
92
90
|
def fields=(unfolded_fields)
|
93
91
|
@fields = Mail::FieldList.new
|
94
|
-
warn "Warning: more than #{self.class.maximum_amount} header fields only using the first #{self.class.maximum_amount}" if unfolded_fields.length > self.class.maximum_amount
|
95
|
-
unfolded_fields[0..(self.class.maximum_amount-1)].each do |field|
|
96
92
|
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
else
|
101
|
-
@fields << field
|
102
|
-
end
|
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)
|
103
96
|
end
|
104
97
|
|
98
|
+
unfolded_fields.each do |field|
|
99
|
+
if field = Field.parse(field, charset)
|
100
|
+
@fields.add_field field
|
101
|
+
end
|
102
|
+
end
|
105
103
|
end
|
106
|
-
|
104
|
+
|
107
105
|
def errors
|
108
106
|
@fields.map(&:errors).flatten(1)
|
109
107
|
end
|
110
|
-
|
108
|
+
|
111
109
|
# 3.6. Field definitions
|
112
|
-
#
|
110
|
+
#
|
113
111
|
# The following table indicates limits on the number of times each
|
114
112
|
# field may occur in a message header as well as any special
|
115
113
|
# limitations on the use of those fields. An asterisk next to a value
|
@@ -119,34 +117,25 @@ module Mail
|
|
119
117
|
# <snip table from 3.6>
|
120
118
|
#
|
121
119
|
# As per RFC, many fields can appear more than once, we will return a string
|
122
|
-
# 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
|
123
121
|
# matching header, will return an array of values in order that they appear
|
124
122
|
# in the header ordered from top to bottom.
|
125
|
-
#
|
123
|
+
#
|
126
124
|
# Example:
|
127
|
-
#
|
125
|
+
#
|
128
126
|
# h = Header.new
|
129
127
|
# h.fields = ['To: mikel@me.com', 'X-Mail-SPAM: 15', 'X-Mail-SPAM: 20']
|
130
128
|
# h['To'] #=> 'mikel@me.com'
|
131
129
|
# h['X-Mail-SPAM'] #=> ['15', '20']
|
132
130
|
def [](name)
|
133
|
-
|
134
|
-
selected = select_field_for(name)
|
135
|
-
case
|
136
|
-
when selected.length > 1
|
137
|
-
selected.map { |f| f }
|
138
|
-
when !selected.blank?
|
139
|
-
selected.first
|
140
|
-
else
|
141
|
-
nil
|
142
|
-
end
|
131
|
+
fields.get_field(Utilities.dasherize(name))
|
143
132
|
end
|
144
|
-
|
133
|
+
|
145
134
|
# Sets the FIRST matching field in the header to passed value, or deletes
|
146
135
|
# the FIRST field matched from the header if passed nil
|
147
|
-
#
|
136
|
+
#
|
148
137
|
# Example:
|
149
|
-
#
|
138
|
+
#
|
150
139
|
# h = Header.new
|
151
140
|
# h.fields = ['To: mikel@me.com', 'X-Mail-SPAM: 15', 'X-Mail-SPAM: 20']
|
152
141
|
# h['To'] = 'bob@you.com'
|
@@ -156,54 +145,42 @@ module Mail
|
|
156
145
|
# h['X-Mail-SPAM'] = nil
|
157
146
|
# h['X-Mail-SPAM'] # => nil
|
158
147
|
def []=(name, value)
|
159
|
-
name =
|
160
|
-
if name.include?(
|
148
|
+
name = name.to_s
|
149
|
+
if name.include?(Constants::COLON)
|
161
150
|
raise ArgumentError, "Header names may not contain a colon: #{name.inspect}"
|
162
151
|
end
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
fields.delete_if { |f| selected.include?(f) }
|
170
|
-
|
171
|
-
# User wants to change the field
|
172
|
-
when !selected.blank? && limited_field?(fn)
|
173
|
-
selected.first.update(fn, value)
|
174
|
-
|
175
|
-
# 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
|
176
158
|
else
|
177
|
-
|
178
|
-
|
179
|
-
end
|
180
|
-
if dasherize(fn) == "content-type"
|
159
|
+
fields.add_field Field.new(name.to_s, value, charset)
|
160
|
+
|
181
161
|
# Update charset if specified in Content-Type
|
182
|
-
|
183
|
-
|
162
|
+
if name == 'content-type'
|
163
|
+
params = self[:content_type].parameters rescue nil
|
164
|
+
@charset = params[:charset] if params && params[:charset]
|
165
|
+
end
|
184
166
|
end
|
185
167
|
end
|
186
|
-
|
187
|
-
def charset
|
188
|
-
@charset
|
189
|
-
end
|
190
|
-
|
168
|
+
|
191
169
|
def charset=(val)
|
192
170
|
params = self[:content_type].parameters rescue nil
|
193
171
|
if params
|
194
|
-
|
172
|
+
if val
|
173
|
+
params[:charset] = val
|
174
|
+
else
|
175
|
+
params.delete(:charset)
|
176
|
+
end
|
195
177
|
end
|
196
178
|
@charset = val
|
197
179
|
end
|
198
|
-
|
199
|
-
LIMITED_FIELDS = %w[ date from sender reply-to to cc bcc
|
200
|
-
message-id in-reply-to references subject
|
201
|
-
return-path content-type mime-version
|
202
|
-
content-transfer-encoding content-description
|
203
|
-
content-id content-disposition content-location]
|
180
|
+
|
204
181
|
|
205
182
|
def encoded
|
206
|
-
buffer =
|
183
|
+
buffer = String.new
|
207
184
|
buffer.force_encoding('us-ascii') if buffer.respond_to?(:force_encoding)
|
208
185
|
fields.each do |field|
|
209
186
|
buffer << field.encoded
|
@@ -214,61 +191,47 @@ module Mail
|
|
214
191
|
def to_s
|
215
192
|
encoded
|
216
193
|
end
|
217
|
-
|
194
|
+
|
218
195
|
def decoded
|
219
|
-
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.'
|
220
197
|
end
|
221
198
|
|
222
199
|
def field_summary
|
223
|
-
fields.
|
200
|
+
fields.summary
|
224
201
|
end
|
225
202
|
|
226
203
|
# Returns true if the header has a Message-ID defined (empty or not)
|
227
204
|
def has_message_id?
|
228
|
-
|
205
|
+
fields.has_field? 'Message-ID'
|
229
206
|
end
|
230
207
|
|
231
208
|
# Returns true if the header has a Content-ID defined (empty or not)
|
232
209
|
def has_content_id?
|
233
|
-
|
210
|
+
fields.has_field? 'Content-ID'
|
234
211
|
end
|
235
212
|
|
236
213
|
# Returns true if the header has a Date defined (empty or not)
|
237
214
|
def has_date?
|
238
|
-
|
215
|
+
fields.has_field? 'Date'
|
239
216
|
end
|
240
217
|
|
241
218
|
# Returns true if the header has a MIME version defined (empty or not)
|
242
219
|
def has_mime_version?
|
243
|
-
|
220
|
+
fields.has_field? 'Mime-Version'
|
244
221
|
end
|
245
222
|
|
246
223
|
private
|
247
|
-
|
248
|
-
def raw_source=(val)
|
249
|
-
@raw_source = val
|
250
|
-
end
|
251
|
-
|
224
|
+
|
252
225
|
# Splits an unfolded and line break cleaned header into individual field
|
253
226
|
# strings.
|
254
227
|
def split_header
|
255
|
-
self.fields = raw_source.split(HEADER_SPLIT)
|
256
|
-
end
|
257
|
-
|
258
|
-
def select_field_for(name)
|
259
|
-
fields.select { |f| f.responsible_for?(name) }
|
260
|
-
end
|
261
|
-
|
262
|
-
def limited_field?(name)
|
263
|
-
LIMITED_FIELDS.include?(name.to_s.downcase)
|
228
|
+
self.fields = @raw_source.split(Constants::HEADER_SPLIT)
|
264
229
|
end
|
265
230
|
|
266
|
-
# Enumerable support; yield each field in order to the block if there is one,
|
267
|
-
# or return an Enumerator for them if there isn't.
|
268
|
-
def each( &block )
|
269
|
-
return self.fields.each( &block ) if block
|
270
|
-
self.fields.each
|
271
|
-
end
|
272
231
|
|
232
|
+
# Enumerable support. Yield each field in order.
|
233
|
+
def each(&block)
|
234
|
+
fields.each(&block)
|
235
|
+
end
|
273
236
|
end
|
274
237
|
end
|
data/lib/mail/mail.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
+
# frozen_string_literal: true
|
2
3
|
module Mail
|
3
4
|
|
4
5
|
# Allows you to create a new Mail::Message object.
|
@@ -89,19 +90,11 @@ module Mail
|
|
89
90
|
# Each mail object inherits the default set in Mail.delivery_method, however, on
|
90
91
|
# a per email basis, you can override the method:
|
91
92
|
#
|
92
|
-
# mail.delivery_method :
|
93
|
+
# mail.delivery_method :smtp
|
93
94
|
#
|
94
95
|
# Or you can override the method and pass in settings:
|
95
96
|
#
|
96
|
-
# mail.delivery_method :
|
97
|
-
#
|
98
|
-
# You can also just modify the settings:
|
99
|
-
#
|
100
|
-
# mail.delivery_settings = { :address => 'some.host' }
|
101
|
-
#
|
102
|
-
# The passed in hash is just merged against the defaults with +merge!+ and the result
|
103
|
-
# assigned the mail object. So the above example will change only the :address value
|
104
|
-
# of the global smtp_settings to be 'some.host', keeping all other values
|
97
|
+
# mail.delivery_method :smtp, :address => 'some.host'
|
105
98
|
def self.defaults(&block)
|
106
99
|
Configuration.instance.instance_eval(&block)
|
107
100
|
end
|
@@ -245,9 +238,11 @@ module Mail
|
|
245
238
|
|
246
239
|
protected
|
247
240
|
|
241
|
+
RANDOM_TAG='%x%x_%x%x%d%x'
|
242
|
+
|
248
243
|
def self.random_tag
|
249
244
|
t = Time.now
|
250
|
-
sprintf(
|
245
|
+
sprintf(RANDOM_TAG,
|
251
246
|
t.to_i, t.tv_usec,
|
252
247
|
$$, Thread.current.object_id.abs, self.uniq, rand(255))
|
253
248
|
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Mail
|
3
|
+
module Matchers
|
4
|
+
def any_attachment
|
5
|
+
AnyAttachmentMatcher.new
|
6
|
+
end
|
7
|
+
|
8
|
+
def an_attachment_with_filename(filename)
|
9
|
+
AttachmentFilenameMatcher.new(filename)
|
10
|
+
end
|
11
|
+
|
12
|
+
def an_attachment_with_mime_type(filename)
|
13
|
+
AttachmentMimeTypeMatcher.new(filename)
|
14
|
+
end
|
15
|
+
|
16
|
+
class AnyAttachmentMatcher
|
17
|
+
def ===(other)
|
18
|
+
other.attachment?
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
class AttachmentFilenameMatcher
|
23
|
+
attr_reader :filename
|
24
|
+
def initialize(filename)
|
25
|
+
@filename = filename
|
26
|
+
end
|
27
|
+
|
28
|
+
def ===(other)
|
29
|
+
other.attachment? && other.filename == filename
|
30
|
+
end
|
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
|
43
|
+
end
|
44
|
+
end
|