mail 2.5.2 → 2.6.4
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 +7 -0
- data/CHANGELOG.rdoc +124 -0
- data/CONTRIBUTING.md +21 -6
- data/Dependencies.txt +0 -1
- data/Gemfile +7 -22
- data/MIT-LICENSE +20 -0
- data/README.md +86 -31
- data/Rakefile +11 -22
- data/lib/mail/attachments_list.rb +4 -2
- data/lib/mail/body.rb +36 -11
- data/lib/mail/check_delivery_params.rb +13 -22
- data/lib/mail/configuration.rb +1 -0
- data/lib/mail/{patterns.rb → constants.rb} +29 -6
- data/lib/mail/core_extensions/smtp.rb +13 -13
- data/lib/mail/core_extensions/string/access.rb +1 -0
- data/lib/mail/core_extensions/string/multibyte.rb +1 -0
- data/lib/mail/core_extensions/string.rb +5 -17
- data/lib/mail/elements/address.rb +86 -145
- data/lib/mail/elements/address_list.rb +10 -42
- data/lib/mail/elements/content_disposition_element.rb +4 -7
- data/lib/mail/elements/content_location_element.rb +8 -11
- data/lib/mail/elements/content_transfer_encoding_element.rb +4 -10
- data/lib/mail/elements/content_type_element.rb +5 -8
- data/lib/mail/elements/date_time_element.rb +4 -7
- data/lib/mail/elements/envelope_from_element.rb +19 -13
- data/lib/mail/elements/message_ids_element.rb +8 -11
- data/lib/mail/elements/mime_version_element.rb +4 -7
- data/lib/mail/elements/phrase_list.rb +3 -7
- data/lib/mail/elements/received_element.rb +4 -7
- data/lib/mail/elements.rb +1 -0
- data/lib/mail/encodings/7bit.rb +1 -0
- data/lib/mail/encodings/8bit.rb +8 -2
- data/lib/mail/encodings/base64.rb +7 -1
- data/lib/mail/encodings/binary.rb +1 -0
- data/lib/mail/encodings/quoted_printable.rb +11 -4
- data/lib/mail/encodings/transfer_encoding.rb +27 -17
- data/lib/mail/encodings/unix_to_unix.rb +18 -0
- data/lib/mail/encodings.rb +54 -39
- data/lib/mail/envelope.rb +1 -5
- data/lib/mail/field.rb +81 -31
- data/lib/mail/field_list.rb +19 -18
- data/lib/mail/fields/bcc_field.rb +17 -5
- data/lib/mail/fields/cc_field.rb +3 -3
- data/lib/mail/fields/comments_field.rb +2 -1
- data/lib/mail/fields/common/address_container.rb +1 -0
- data/lib/mail/fields/common/common_address.rb +34 -28
- data/lib/mail/fields/common/common_date.rb +2 -8
- data/lib/mail/fields/common/common_field.rb +9 -5
- data/lib/mail/fields/common/common_message_id.rb +3 -2
- data/lib/mail/fields/common/parameter_hash.rb +4 -3
- data/lib/mail/fields/content_description_field.rb +1 -0
- data/lib/mail/fields/content_disposition_field.rb +13 -12
- data/lib/mail/fields/content_id_field.rb +4 -4
- data/lib/mail/fields/content_location_field.rb +2 -1
- data/lib/mail/fields/content_transfer_encoding_field.rb +4 -9
- data/lib/mail/fields/content_type_field.rb +4 -3
- data/lib/mail/fields/date_field.rb +16 -15
- data/lib/mail/fields/from_field.rb +3 -3
- data/lib/mail/fields/in_reply_to_field.rb +3 -1
- data/lib/mail/fields/keywords_field.rb +2 -2
- data/lib/mail/fields/message_id_field.rb +4 -4
- data/lib/mail/fields/mime_version_field.rb +3 -2
- data/lib/mail/fields/optional_field.rb +1 -0
- data/lib/mail/fields/received_field.rb +4 -3
- data/lib/mail/fields/references_field.rb +3 -1
- data/lib/mail/fields/reply_to_field.rb +3 -3
- data/lib/mail/fields/resent_bcc_field.rb +3 -3
- data/lib/mail/fields/resent_cc_field.rb +3 -3
- data/lib/mail/fields/resent_date_field.rb +2 -1
- data/lib/mail/fields/resent_from_field.rb +3 -3
- data/lib/mail/fields/resent_message_id_field.rb +1 -0
- data/lib/mail/fields/resent_sender_field.rb +4 -4
- data/lib/mail/fields/resent_to_field.rb +3 -3
- data/lib/mail/fields/return_path_field.rb +1 -1
- data/lib/mail/fields/sender_field.rb +9 -9
- data/lib/mail/fields/structured_field.rb +1 -0
- data/lib/mail/fields/subject_field.rb +1 -0
- data/lib/mail/fields/to_field.rb +3 -3
- data/lib/mail/fields/unstructured_field.rb +15 -8
- data/lib/mail/fields.rb +1 -0
- data/lib/mail/header.rb +21 -29
- data/lib/mail/indifferent_hash.rb +1 -0
- data/lib/mail/mail.rb +16 -1
- data/lib/mail/matchers/attachment_matchers.rb +29 -0
- data/lib/mail/matchers/has_sent_mail.rb +61 -4
- data/lib/mail/message.rb +175 -72
- data/lib/mail/multibyte/chars.rb +3 -2
- data/lib/mail/multibyte/exceptions.rb +1 -0
- data/lib/mail/multibyte/unicode.rb +22 -15
- data/lib/mail/multibyte/utils.rb +1 -0
- data/lib/mail/multibyte.rb +1 -0
- data/lib/mail/network/delivery_methods/exim.rb +3 -7
- data/lib/mail/network/delivery_methods/file_delivery.rb +2 -1
- data/lib/mail/network/delivery_methods/sendmail.rb +33 -10
- data/lib/mail/network/delivery_methods/smtp.rb +32 -34
- data/lib/mail/network/delivery_methods/smtp_connection.rb +7 -6
- data/lib/mail/network/delivery_methods/test_mailer.rb +3 -2
- data/lib/mail/network/retriever_methods/base.rb +1 -0
- data/lib/mail/network/retriever_methods/imap.rb +19 -13
- data/lib/mail/network/retriever_methods/pop3.rb +1 -0
- data/lib/mail/network/retriever_methods/test_retriever.rb +1 -0
- data/lib/mail/network.rb +1 -0
- data/lib/mail/parsers/address_lists_parser.rb +133 -0
- data/lib/mail/parsers/content_disposition_parser.rb +68 -0
- data/lib/mail/parsers/content_location_parser.rb +36 -0
- data/lib/mail/parsers/content_transfer_encoding_parser.rb +34 -0
- data/lib/mail/parsers/content_type_parser.rb +67 -0
- data/lib/mail/parsers/date_time_parser.rb +39 -0
- data/lib/mail/parsers/envelope_from_parser.rb +46 -0
- data/lib/mail/parsers/message_ids_parser.rb +40 -0
- data/lib/mail/parsers/mime_version_parser.rb +42 -0
- data/lib/mail/parsers/phrase_lists_parser.rb +36 -0
- data/lib/mail/parsers/ragel/common.rl +185 -0
- data/lib/mail/parsers/ragel/date_time.rl +30 -0
- data/lib/mail/parsers/ragel/parser_info.rb +61 -0
- data/lib/mail/parsers/ragel/ruby/machines/address_lists_machine.rb +14864 -0
- data/lib/mail/parsers/ragel/ruby/machines/address_lists_machine.rb.rl +37 -0
- data/lib/mail/parsers/ragel/ruby/machines/content_disposition_machine.rb +751 -0
- data/lib/mail/parsers/ragel/ruby/machines/content_disposition_machine.rb.rl +37 -0
- data/lib/mail/parsers/ragel/ruby/machines/content_location_machine.rb +614 -0
- data/lib/mail/parsers/ragel/ruby/machines/content_location_machine.rb.rl +37 -0
- data/lib/mail/parsers/ragel/ruby/machines/content_transfer_encoding_machine.rb +447 -0
- data/lib/mail/parsers/ragel/ruby/machines/content_transfer_encoding_machine.rb.rl +37 -0
- data/lib/mail/parsers/ragel/ruby/machines/content_type_machine.rb +825 -0
- data/lib/mail/parsers/ragel/ruby/machines/content_type_machine.rb.rl +37 -0
- data/lib/mail/parsers/ragel/ruby/machines/date_time_machine.rb +817 -0
- data/lib/mail/parsers/ragel/ruby/machines/date_time_machine.rb.rl +37 -0
- data/lib/mail/parsers/ragel/ruby/machines/envelope_from_machine.rb +2149 -0
- data/lib/mail/parsers/ragel/ruby/machines/envelope_from_machine.rb.rl +37 -0
- data/lib/mail/parsers/ragel/ruby/machines/message_ids_machine.rb +1570 -0
- data/lib/mail/parsers/ragel/ruby/machines/message_ids_machine.rb.rl +37 -0
- data/lib/mail/parsers/ragel/ruby/machines/mime_version_machine.rb +440 -0
- data/lib/mail/parsers/ragel/ruby/machines/mime_version_machine.rb.rl +37 -0
- data/lib/mail/parsers/ragel/ruby/machines/phrase_lists_machine.rb +564 -0
- data/lib/mail/parsers/ragel/ruby/machines/phrase_lists_machine.rb.rl +37 -0
- data/lib/mail/parsers/ragel/ruby/machines/rb_actions.rl +51 -0
- data/lib/mail/parsers/ragel/ruby/machines/received_machine.rb +5144 -0
- data/lib/mail/parsers/ragel/ruby/machines/received_machine.rb.rl +37 -0
- data/lib/mail/parsers/ragel/ruby/parser.rb.rl.erb +37 -0
- data/lib/mail/parsers/ragel/ruby.rb +40 -0
- data/lib/mail/parsers/ragel.rb +18 -0
- data/lib/mail/parsers/received_parser.rb +49 -0
- data/lib/mail/parsers.rb +27 -0
- data/lib/mail/part.rb +11 -4
- data/lib/mail/parts_list.rb +30 -10
- data/lib/mail/utilities.rb +127 -63
- data/lib/mail/values/unicode_tables.dat +0 -0
- data/lib/mail/version.rb +8 -15
- data/lib/mail/version_specific/ruby_1_8.rb +18 -7
- data/lib/mail/version_specific/ruby_1_9.rb +136 -32
- data/lib/mail.rb +12 -6
- metadata +115 -77
- data/lib/VERSION +0 -4
- data/lib/load_parsers.rb +0 -41
- data/lib/mail/core_extensions/nil.rb +0 -19
- data/lib/mail/core_extensions/object.rb +0 -13
- data/lib/mail/core_extensions/shell_escape.rb +0 -56
- data/lib/mail/parsers/address_lists.rb +0 -64
- data/lib/mail/parsers/address_lists.treetop +0 -19
- data/lib/mail/parsers/content_disposition.rb +0 -535
- data/lib/mail/parsers/content_disposition.treetop +0 -46
- data/lib/mail/parsers/content_location.rb +0 -139
- data/lib/mail/parsers/content_location.treetop +0 -20
- data/lib/mail/parsers/content_transfer_encoding.rb +0 -162
- data/lib/mail/parsers/content_transfer_encoding.treetop +0 -20
- data/lib/mail/parsers/content_type.rb +0 -967
- data/lib/mail/parsers/content_type.treetop +0 -68
- data/lib/mail/parsers/date_time.rb +0 -114
- data/lib/mail/parsers/date_time.treetop +0 -11
- data/lib/mail/parsers/envelope_from.rb +0 -194
- data/lib/mail/parsers/envelope_from.treetop +0 -32
- data/lib/mail/parsers/message_ids.rb +0 -45
- data/lib/mail/parsers/message_ids.treetop +0 -15
- data/lib/mail/parsers/mime_version.rb +0 -144
- data/lib/mail/parsers/mime_version.treetop +0 -19
- data/lib/mail/parsers/phrase_lists.rb +0 -45
- data/lib/mail/parsers/phrase_lists.treetop +0 -15
- data/lib/mail/parsers/received.rb +0 -71
- data/lib/mail/parsers/received.treetop +0 -11
- data/lib/mail/parsers/rfc2045.rb +0 -464
- data/lib/mail/parsers/rfc2045.treetop +0 -36
- data/lib/mail/parsers/rfc2822.rb +0 -5397
- data/lib/mail/parsers/rfc2822.treetop +0 -410
- data/lib/mail/parsers/rfc2822_obsolete.rb +0 -3768
- data/lib/mail/parsers/rfc2822_obsolete.treetop +0 -241
- data/lib/tasks/corpus.rake +0 -125
- data/lib/tasks/treetop.rake +0 -10
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
# encoding: utf-8
|
|
2
|
+
# frozen_string_literal: true
|
|
2
3
|
#
|
|
3
4
|
# 4.4.3. REPLY-TO / RESENT-REPLY-TO
|
|
4
5
|
#
|
|
@@ -41,7 +42,6 @@ module Mail
|
|
|
41
42
|
value = nil if value == '<>'
|
|
42
43
|
self.charset = charset
|
|
43
44
|
super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value), charset)
|
|
44
|
-
self.parse
|
|
45
45
|
self
|
|
46
46
|
end
|
|
47
47
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
# encoding: utf-8
|
|
2
|
+
# frozen_string_literal: true
|
|
2
3
|
#
|
|
3
4
|
# = Sender Field
|
|
4
5
|
#
|
|
@@ -6,7 +7,7 @@
|
|
|
6
7
|
# field in the email.
|
|
7
8
|
#
|
|
8
9
|
# Sending sender to a mail message will instantiate a Mail::Field object that
|
|
9
|
-
# has a SenderField as
|
|
10
|
+
# has a SenderField as its field type. This includes all Mail::CommonAddress
|
|
10
11
|
# module instance metods.
|
|
11
12
|
#
|
|
12
13
|
# Only one Sender field can appear in a header, though it can have multiple
|
|
@@ -15,16 +16,16 @@
|
|
|
15
16
|
# == Examples:
|
|
16
17
|
#
|
|
17
18
|
# mail = Mail.new
|
|
18
|
-
# mail.sender = 'Mikel Lindsaar <mikel@test.lindsaar.net
|
|
19
|
-
# mail.sender #=>
|
|
19
|
+
# mail.sender = 'Mikel Lindsaar <mikel@test.lindsaar.net>'
|
|
20
|
+
# mail.sender #=> 'mikel@test.lindsaar.net'
|
|
20
21
|
# mail[:sender] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::SenderField:0x180e1c4
|
|
21
22
|
# mail['sender'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::SenderField:0x180e1c4
|
|
22
23
|
# mail['Sender'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::SenderField:0x180e1c4
|
|
23
24
|
#
|
|
24
|
-
# mail[:sender].encoded #=>
|
|
25
|
-
# mail[:sender].decoded #=> 'Mikel Lindsaar <mikel@test.lindsaar.net
|
|
26
|
-
# mail[:sender].addresses #=> ['mikel@test.lindsaar.net'
|
|
27
|
-
# mail[:sender].formatted #=> ['Mikel Lindsaar <mikel@test.lindsaar.net>'
|
|
25
|
+
# mail[:sender].encoded #=> "Sender: Mikel Lindsaar <mikel@test.lindsaar.net>\r\n"
|
|
26
|
+
# mail[:sender].decoded #=> 'Mikel Lindsaar <mikel@test.lindsaar.net>'
|
|
27
|
+
# mail[:sender].addresses #=> ['mikel@test.lindsaar.net']
|
|
28
|
+
# mail[:sender].formatted #=> ['Mikel Lindsaar <mikel@test.lindsaar.net>']
|
|
28
29
|
#
|
|
29
30
|
require 'mail/fields/common/common_address'
|
|
30
31
|
|
|
@@ -39,7 +40,6 @@ module Mail
|
|
|
39
40
|
def initialize(value = nil, charset = 'utf-8')
|
|
40
41
|
self.charset = charset
|
|
41
42
|
super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value), charset)
|
|
42
|
-
self.parse
|
|
43
43
|
self
|
|
44
44
|
end
|
|
45
45
|
|
|
@@ -48,7 +48,7 @@ module Mail
|
|
|
48
48
|
end
|
|
49
49
|
|
|
50
50
|
def address
|
|
51
|
-
|
|
51
|
+
address_list.addresses.first
|
|
52
52
|
end
|
|
53
53
|
|
|
54
54
|
def encoded
|
data/lib/mail/fields/to_field.rb
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
# encoding: utf-8
|
|
2
|
+
# frozen_string_literal: true
|
|
2
3
|
#
|
|
3
4
|
# = To Field
|
|
4
5
|
#
|
|
@@ -6,7 +7,7 @@
|
|
|
6
7
|
# field in the email.
|
|
7
8
|
#
|
|
8
9
|
# Sending to to a mail message will instantiate a Mail::Field object that
|
|
9
|
-
# has a ToField as
|
|
10
|
+
# has a ToField as its field type. This includes all Mail::CommonAddress
|
|
10
11
|
# module instance metods.
|
|
11
12
|
#
|
|
12
13
|
# Only one To field can appear in a header, though it can have multiple
|
|
@@ -16,7 +17,7 @@
|
|
|
16
17
|
#
|
|
17
18
|
# mail = Mail.new
|
|
18
19
|
# mail.to = 'Mikel Lindsaar <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
|
|
19
|
-
# mail.to #=> ['
|
|
20
|
+
# mail.to #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
|
|
20
21
|
# mail[:to] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::ToField:0x180e1c4
|
|
21
22
|
# mail['to'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::ToField:0x180e1c4
|
|
22
23
|
# mail['To'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::ToField:0x180e1c4
|
|
@@ -39,7 +40,6 @@ module Mail
|
|
|
39
40
|
def initialize(value = nil, charset = 'utf-8')
|
|
40
41
|
self.charset = charset
|
|
41
42
|
super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value), charset)
|
|
42
|
-
self.parse
|
|
43
43
|
self
|
|
44
44
|
end
|
|
45
45
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
# encoding: utf-8
|
|
2
|
+
# frozen_string_literal: true
|
|
2
3
|
require 'mail/fields/common/common_field'
|
|
3
4
|
|
|
4
5
|
module Mail
|
|
@@ -70,7 +71,7 @@ module Mail
|
|
|
70
71
|
end
|
|
71
72
|
|
|
72
73
|
def do_decode
|
|
73
|
-
|
|
74
|
+
Utilities.blank?(value) ? nil : Encodings.decode_encode(value, :decode)
|
|
74
75
|
end
|
|
75
76
|
|
|
76
77
|
# 2.2.3. Long Header Fields
|
|
@@ -127,7 +128,7 @@ module Mail
|
|
|
127
128
|
if first
|
|
128
129
|
first = !first
|
|
129
130
|
else
|
|
130
|
-
word = " "
|
|
131
|
+
word = " #{word}"
|
|
131
132
|
end
|
|
132
133
|
if word.not_ascii_only?
|
|
133
134
|
word
|
|
@@ -143,10 +144,11 @@ module Mail
|
|
|
143
144
|
while !words.empty?
|
|
144
145
|
limit = 78 - prepend
|
|
145
146
|
limit = limit - 7 - encoding.length if should_encode
|
|
146
|
-
line =
|
|
147
|
+
line = String.new
|
|
148
|
+
first_word = true
|
|
147
149
|
while !words.empty?
|
|
148
150
|
break unless word = words.first.dup
|
|
149
|
-
word.encode!(charset) if
|
|
151
|
+
word.encode!(charset) if charset && word.respond_to?(:encode!)
|
|
150
152
|
word = encode(word) if should_encode
|
|
151
153
|
word = encode_crlf(word)
|
|
152
154
|
# Skip to next line if we're going to go past the limit
|
|
@@ -158,7 +160,12 @@ module Mail
|
|
|
158
160
|
# Remove the word from the queue ...
|
|
159
161
|
words.shift
|
|
160
162
|
# Add word separator
|
|
161
|
-
|
|
163
|
+
if first_word
|
|
164
|
+
first_word = false
|
|
165
|
+
else
|
|
166
|
+
line << " " if !should_encode
|
|
167
|
+
end
|
|
168
|
+
|
|
162
169
|
# ... add it in encoded form to the current line
|
|
163
170
|
line << word
|
|
164
171
|
end
|
|
@@ -172,7 +179,7 @@ module Mail
|
|
|
172
179
|
end
|
|
173
180
|
|
|
174
181
|
def encode(value)
|
|
175
|
-
value = [value].pack(
|
|
182
|
+
value = [value].pack(CAPITAL_M).gsub(EQUAL_LF, EMPTY)
|
|
176
183
|
value.gsub!(/"/, '=22')
|
|
177
184
|
value.gsub!(/\(/, '=28')
|
|
178
185
|
value.gsub!(/\)/, '=29')
|
|
@@ -183,8 +190,8 @@ module Mail
|
|
|
183
190
|
end
|
|
184
191
|
|
|
185
192
|
def encode_crlf(value)
|
|
186
|
-
value.gsub!(
|
|
187
|
-
value.gsub!(
|
|
193
|
+
value.gsub!(CR, CR_ENCODED)
|
|
194
|
+
value.gsub!(LF, LF_ENCODED)
|
|
188
195
|
value
|
|
189
196
|
end
|
|
190
197
|
|
data/lib/mail/fields.rb
CHANGED
data/lib/mail/header.rb
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
# encoding: utf-8
|
|
2
|
+
# frozen_string_literal: true
|
|
2
3
|
module Mail
|
|
3
4
|
|
|
4
5
|
# Provides access to a header object.
|
|
@@ -17,7 +18,7 @@ module Mail
|
|
|
17
18
|
# 2.2.3. All field bodies MUST conform to the syntax described in
|
|
18
19
|
# sections 3 and 4 of this standard.
|
|
19
20
|
class Header
|
|
20
|
-
include
|
|
21
|
+
include Constants
|
|
21
22
|
include Utilities
|
|
22
23
|
include Enumerable
|
|
23
24
|
|
|
@@ -48,11 +49,15 @@ module Mail
|
|
|
48
49
|
# these cases, please make a patch and send it in, or at the least, send
|
|
49
50
|
# me the example so we can fix it.
|
|
50
51
|
def initialize(header_text = nil, charset = nil)
|
|
51
|
-
@errors = []
|
|
52
52
|
@charset = charset
|
|
53
|
-
self.raw_source = header_text.
|
|
53
|
+
self.raw_source = ::Mail::Utilities.to_crlf(header_text).lstrip
|
|
54
54
|
split_header if header_text
|
|
55
55
|
end
|
|
56
|
+
|
|
57
|
+
def initialize_copy(original)
|
|
58
|
+
super
|
|
59
|
+
@fields = @fields.dup
|
|
60
|
+
end
|
|
56
61
|
|
|
57
62
|
# The preserved raw source of the header as you passed it in, untouched
|
|
58
63
|
# for your Regexing glory.
|
|
@@ -91,7 +96,6 @@ module Mail
|
|
|
91
96
|
unfolded_fields[0..(self.class.maximum_amount-1)].each do |field|
|
|
92
97
|
|
|
93
98
|
field = Field.new(field, nil, charset)
|
|
94
|
-
field.errors.each { |error| self.errors << error }
|
|
95
99
|
if limited_field?(field.name) && (selected = select_field_for(field.name)) && selected.any?
|
|
96
100
|
selected.first.update(field.name, field.value)
|
|
97
101
|
else
|
|
@@ -102,7 +106,7 @@ module Mail
|
|
|
102
106
|
end
|
|
103
107
|
|
|
104
108
|
def errors
|
|
105
|
-
@errors
|
|
109
|
+
@fields.map(&:errors).flatten(1)
|
|
106
110
|
end
|
|
107
111
|
|
|
108
112
|
# 3.6. Field definitions
|
|
@@ -127,12 +131,13 @@ module Mail
|
|
|
127
131
|
# h['To'] #=> 'mikel@me.com'
|
|
128
132
|
# h['X-Mail-SPAM'] #=> ['15', '20']
|
|
129
133
|
def [](name)
|
|
130
|
-
name = dasherize(name)
|
|
134
|
+
name = dasherize(name)
|
|
135
|
+
name.downcase!
|
|
131
136
|
selected = select_field_for(name)
|
|
132
137
|
case
|
|
133
138
|
when selected.length > 1
|
|
134
139
|
selected.map { |f| f }
|
|
135
|
-
when !
|
|
140
|
+
when !Utilities.blank?(selected)
|
|
136
141
|
selected.first
|
|
137
142
|
else
|
|
138
143
|
nil
|
|
@@ -154,16 +159,19 @@ module Mail
|
|
|
154
159
|
# h['X-Mail-SPAM'] # => nil
|
|
155
160
|
def []=(name, value)
|
|
156
161
|
name = dasherize(name)
|
|
162
|
+
if name.include?(':')
|
|
163
|
+
raise ArgumentError, "Header names may not contain a colon: #{name.inspect}"
|
|
164
|
+
end
|
|
157
165
|
fn = name.downcase
|
|
158
166
|
selected = select_field_for(fn)
|
|
159
167
|
|
|
160
168
|
case
|
|
161
169
|
# User wants to delete the field
|
|
162
|
-
when !
|
|
170
|
+
when !Utilities.blank?(selected) && value == nil
|
|
163
171
|
fields.delete_if { |f| selected.include?(f) }
|
|
164
172
|
|
|
165
173
|
# User wants to change the field
|
|
166
|
-
when !
|
|
174
|
+
when !Utilities.blank?(selected) && limited_field?(fn)
|
|
167
175
|
selected.first.update(fn, value)
|
|
168
176
|
|
|
169
177
|
# User wants to create the field
|
|
@@ -174,7 +182,7 @@ module Mail
|
|
|
174
182
|
if dasherize(fn) == "content-type"
|
|
175
183
|
# Update charset if specified in Content-Type
|
|
176
184
|
params = self[:content_type].parameters rescue nil
|
|
177
|
-
@charset = params && params[:charset]
|
|
185
|
+
@charset = params[:charset] if params && params[:charset]
|
|
178
186
|
end
|
|
179
187
|
end
|
|
180
188
|
|
|
@@ -197,7 +205,8 @@ module Mail
|
|
|
197
205
|
content-id content-disposition content-location]
|
|
198
206
|
|
|
199
207
|
def encoded
|
|
200
|
-
buffer =
|
|
208
|
+
buffer = String.new
|
|
209
|
+
buffer.force_encoding('us-ascii') if buffer.respond_to?(:force_encoding)
|
|
201
210
|
fields.each do |field|
|
|
202
211
|
buffer << field.encoded
|
|
203
212
|
end
|
|
@@ -242,27 +251,10 @@ module Mail
|
|
|
242
251
|
@raw_source = val
|
|
243
252
|
end
|
|
244
253
|
|
|
245
|
-
# 2.2.3. Long Header Fields
|
|
246
|
-
#
|
|
247
|
-
# The process of moving from this folded multiple-line representation
|
|
248
|
-
# of a header field to its single line representation is called
|
|
249
|
-
# "unfolding". Unfolding is accomplished by simply removing any CRLF
|
|
250
|
-
# that is immediately followed by WSP. Each header field should be
|
|
251
|
-
# treated in its unfolded form for further syntactic and semantic
|
|
252
|
-
# evaluation.
|
|
253
|
-
def unfold(string)
|
|
254
|
-
string.gsub(/#{CRLF}#{WSP}+/, ' ').gsub(/#{WSP}+/, ' ')
|
|
255
|
-
end
|
|
256
|
-
|
|
257
|
-
# Returns the header with all the folds removed
|
|
258
|
-
def unfolded_header
|
|
259
|
-
@unfolded_header ||= unfold(raw_source)
|
|
260
|
-
end
|
|
261
|
-
|
|
262
254
|
# Splits an unfolded and line break cleaned header into individual field
|
|
263
255
|
# strings.
|
|
264
256
|
def split_header
|
|
265
|
-
self.fields =
|
|
257
|
+
self.fields = raw_source.split(HEADER_SPLIT)
|
|
266
258
|
end
|
|
267
259
|
|
|
268
260
|
def select_field_for(name)
|
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.
|
|
@@ -206,6 +207,12 @@ module Mail
|
|
|
206
207
|
end
|
|
207
208
|
end
|
|
208
209
|
|
|
210
|
+
# Unregister the given observer, allowing mail to resume operations
|
|
211
|
+
# without it.
|
|
212
|
+
def self.unregister_observer(observer)
|
|
213
|
+
@@delivery_notification_observers.delete(observer)
|
|
214
|
+
end
|
|
215
|
+
|
|
209
216
|
# You can register an object to be given every mail object that will be sent,
|
|
210
217
|
# before it is sent. So if you want to add special headers or modify any
|
|
211
218
|
# email that gets sent through the Mail library, you can do so.
|
|
@@ -219,6 +226,12 @@ module Mail
|
|
|
219
226
|
end
|
|
220
227
|
end
|
|
221
228
|
|
|
229
|
+
# Unregister the given interceptor, allowing mail to resume operations
|
|
230
|
+
# without it.
|
|
231
|
+
def self.unregister_interceptor(interceptor)
|
|
232
|
+
@@delivery_interceptors.delete(interceptor)
|
|
233
|
+
end
|
|
234
|
+
|
|
222
235
|
def self.inform_observers(mail)
|
|
223
236
|
@@delivery_notification_observers.each do |observer|
|
|
224
237
|
observer.delivered_email(mail)
|
|
@@ -233,9 +246,11 @@ module Mail
|
|
|
233
246
|
|
|
234
247
|
protected
|
|
235
248
|
|
|
249
|
+
RANDOM_TAG='%x%x_%x%x%d%x'
|
|
250
|
+
|
|
236
251
|
def self.random_tag
|
|
237
252
|
t = Time.now
|
|
238
|
-
sprintf(
|
|
253
|
+
sprintf(RANDOM_TAG,
|
|
239
254
|
t.to_i, t.tv_usec,
|
|
240
255
|
$$, Thread.current.object_id.abs, self.uniq, rand(255))
|
|
241
256
|
end
|
|
@@ -0,0 +1,29 @@
|
|
|
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
|
+
class AnyAttachmentMatcher
|
|
13
|
+
def ===(other)
|
|
14
|
+
other.attachment?
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
class AttachmentFilenameMatcher
|
|
19
|
+
attr_reader :filename
|
|
20
|
+
def initialize(filename)
|
|
21
|
+
@filename = filename
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def ===(other)
|
|
25
|
+
other.attachment? && other.filename == filename
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
1
2
|
module Mail
|
|
2
3
|
module Matchers
|
|
3
4
|
def have_sent_email
|
|
@@ -29,6 +30,39 @@ module Mail
|
|
|
29
30
|
self
|
|
30
31
|
end
|
|
31
32
|
|
|
33
|
+
def cc(recipient_or_list)
|
|
34
|
+
@copy_recipients ||= []
|
|
35
|
+
|
|
36
|
+
if recipient_or_list.kind_of?(Array)
|
|
37
|
+
@copy_recipients += recipient_or_list
|
|
38
|
+
else
|
|
39
|
+
@copy_recipients << recipient_or_list
|
|
40
|
+
end
|
|
41
|
+
self
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def bcc(recipient_or_list)
|
|
45
|
+
@blind_copy_recipients ||= []
|
|
46
|
+
@blind_copy_recipients.concat(Array(recipient_or_list))
|
|
47
|
+
self
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def with_attachments(attachments)
|
|
51
|
+
@attachments ||= []
|
|
52
|
+
@attachments.concat(Array(attachments))
|
|
53
|
+
self
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def with_no_attachments
|
|
57
|
+
@having_attachments = false
|
|
58
|
+
self
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def with_any_attachments
|
|
62
|
+
@having_attachments = true
|
|
63
|
+
self
|
|
64
|
+
end
|
|
65
|
+
|
|
32
66
|
def with_subject(subject)
|
|
33
67
|
@subject = subject
|
|
34
68
|
self
|
|
@@ -61,7 +95,7 @@ module Mail
|
|
|
61
95
|
result
|
|
62
96
|
end
|
|
63
97
|
|
|
64
|
-
def
|
|
98
|
+
def failure_message_when_negated
|
|
65
99
|
result = "Expected no email to be sent "
|
|
66
100
|
result += explain_expectations
|
|
67
101
|
result += dump_deliveries
|
|
@@ -69,11 +103,13 @@ module Mail
|
|
|
69
103
|
end
|
|
70
104
|
|
|
71
105
|
protected
|
|
72
|
-
|
|
106
|
+
|
|
73
107
|
def filter_matched_deliveries(deliveries)
|
|
74
108
|
candidate_deliveries = deliveries
|
|
75
|
-
|
|
76
|
-
|
|
109
|
+
modifiers =
|
|
110
|
+
%w(sender recipients copy_recipients blind_copy_recipients subject
|
|
111
|
+
subject_matcher body body_matcher having_attachments attachments)
|
|
112
|
+
modifiers.each do |modifier_name|
|
|
77
113
|
next unless instance_variable_defined?("@#{modifier_name}")
|
|
78
114
|
candidate_deliveries = candidate_deliveries.select{|matching_delivery| self.send("matches_on_#{modifier_name}?", matching_delivery)}
|
|
79
115
|
end
|
|
@@ -89,6 +125,14 @@ module Mail
|
|
|
89
125
|
@recipients.all? {|recipient| delivery.to.include?(recipient) }
|
|
90
126
|
end
|
|
91
127
|
|
|
128
|
+
def matches_on_copy_recipients?(delivery)
|
|
129
|
+
@copy_recipients.all? {|recipient| delivery.cc.include?(recipient) }
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def matches_on_blind_copy_recipients?(delivery)
|
|
133
|
+
@blind_copy_recipients.all? {|recipient| delivery.bcc.include?(recipient) }
|
|
134
|
+
end
|
|
135
|
+
|
|
92
136
|
def matches_on_subject?(delivery)
|
|
93
137
|
delivery.subject == @subject
|
|
94
138
|
end
|
|
@@ -97,6 +141,17 @@ module Mail
|
|
|
97
141
|
@subject_matcher.match delivery.subject
|
|
98
142
|
end
|
|
99
143
|
|
|
144
|
+
def matches_on_having_attachments?(delivery)
|
|
145
|
+
@having_attachments && delivery.attachments.any? ||
|
|
146
|
+
(!@having_attachments && delivery.attachments.none?)
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def matches_on_attachments?(delivery)
|
|
150
|
+
@attachments.each_with_index.inject( true ) do |sent_attachments, (attachment, index)|
|
|
151
|
+
sent_attachments &&= (attachment === delivery.attachments[index])
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
|
|
100
155
|
def matches_on_body?(delivery)
|
|
101
156
|
delivery.body == @body
|
|
102
157
|
end
|
|
@@ -109,6 +164,8 @@ module Mail
|
|
|
109
164
|
result = ''
|
|
110
165
|
result += "from #{@sender} " if instance_variable_defined?('@sender')
|
|
111
166
|
result += "to #{@recipients.inspect} " if instance_variable_defined?('@recipients')
|
|
167
|
+
result += "cc #{@copy_recipients.inspect} " if instance_variable_defined?('@copy_recipients')
|
|
168
|
+
result += "bcc #{@blind_copy_recipients.inspect} " if instance_variable_defined?('@blind_copy_recipients')
|
|
112
169
|
result += "with subject \"#{@subject}\" " if instance_variable_defined?('@subject')
|
|
113
170
|
result += "with subject matching \"#{@subject_matcher}\" " if instance_variable_defined?('@subject_matcher')
|
|
114
171
|
result += "with body \"#{@body}\" " if instance_variable_defined?('@body')
|