mail 2.5.3 → 2.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.rdoc +70 -0
- data/CONTRIBUTING.md +17 -4
- data/Dependencies.txt +0 -1
- data/Gemfile +10 -21
- data/MIT-LICENSE +20 -0
- data/README.md +50 -29
- data/Rakefile +11 -20
- data/VERSION +4 -0
- data/lib/mail/attachments_list.rb +2 -2
- data/lib/mail/body.rb +5 -5
- data/lib/mail/check_delivery_params.rb +12 -22
- data/lib/mail/core_extensions/object.rb +8 -8
- data/lib/mail/core_extensions/smtp.rb +12 -13
- data/lib/mail/core_extensions/string.rb +16 -6
- data/lib/mail/elements/address.rb +43 -79
- data/lib/mail/elements/address_list.rb +19 -42
- data/lib/mail/elements/content_disposition_element.rb +3 -7
- data/lib/mail/elements/content_location_element.rb +2 -6
- data/lib/mail/elements/content_transfer_encoding_element.rb +3 -10
- data/lib/mail/elements/content_type_element.rb +4 -8
- data/lib/mail/elements/date_time_element.rb +3 -7
- data/lib/mail/elements/envelope_from_element.rb +18 -13
- data/lib/mail/elements/message_ids_element.rb +1 -6
- data/lib/mail/elements/mime_version_element.rb +3 -7
- data/lib/mail/elements/phrase_list.rb +2 -7
- data/lib/mail/elements/received_element.rb +3 -7
- data/lib/mail/encodings/quoted_printable.rb +4 -3
- data/lib/mail/encodings.rb +60 -28
- data/lib/mail/envelope.rb +0 -5
- data/lib/mail/field.rb +63 -28
- data/lib/mail/field_list.rb +18 -18
- data/lib/mail/fields/bcc_field.rb +2 -2
- data/lib/mail/fields/cc_field.rb +2 -2
- data/lib/mail/fields/comments_field.rb +1 -1
- data/lib/mail/fields/common/common_address.rb +26 -21
- data/lib/mail/fields/common/common_date.rb +0 -7
- data/lib/mail/fields/common/common_field.rb +5 -5
- data/lib/mail/fields/content_id_field.rb +1 -2
- data/lib/mail/fields/content_transfer_encoding_field.rb +2 -8
- data/lib/mail/fields/content_type_field.rb +1 -1
- data/lib/mail/fields/date_field.rb +1 -1
- data/lib/mail/fields/from_field.rb +2 -2
- data/lib/mail/fields/in_reply_to_field.rb +2 -1
- data/lib/mail/fields/message_id_field.rb +2 -3
- data/lib/mail/fields/references_field.rb +2 -1
- data/lib/mail/fields/reply_to_field.rb +2 -2
- data/lib/mail/fields/resent_bcc_field.rb +2 -2
- data/lib/mail/fields/resent_cc_field.rb +2 -2
- data/lib/mail/fields/resent_from_field.rb +2 -2
- data/lib/mail/fields/resent_sender_field.rb +3 -3
- data/lib/mail/fields/resent_to_field.rb +2 -2
- data/lib/mail/fields/sender_field.rb +8 -8
- data/lib/mail/fields/to_field.rb +2 -2
- data/lib/mail/fields/unstructured_field.rb +8 -2
- data/lib/mail/header.rb +13 -23
- data/lib/mail/mail.rb +12 -0
- data/lib/mail/matchers/has_sent_mail.rb +34 -1
- data/lib/mail/message.rb +151 -48
- data/lib/mail/multibyte/chars.rb +2 -2
- data/lib/mail/multibyte/unicode.rb +6 -4
- data/lib/mail/network/delivery_methods/exim.rb +1 -6
- data/lib/mail/network/delivery_methods/file_delivery.rb +1 -1
- data/lib/mail/network/delivery_methods/sendmail.rb +32 -10
- data/lib/mail/network/delivery_methods/smtp.rb +31 -34
- data/lib/mail/network/delivery_methods/smtp_connection.rb +6 -6
- data/lib/mail/network/delivery_methods/test_mailer.rb +2 -2
- data/lib/mail/network/retriever_methods/imap.rb +18 -13
- data/lib/mail/parsers/address_lists_parser.rb +132 -0
- data/lib/mail/parsers/content_disposition_parser.rb +67 -0
- data/lib/mail/parsers/content_location_parser.rb +35 -0
- data/lib/mail/parsers/content_transfer_encoding_parser.rb +33 -0
- data/lib/mail/parsers/content_type_parser.rb +64 -0
- data/lib/mail/parsers/date_time_parser.rb +36 -0
- data/lib/mail/parsers/envelope_from_parser.rb +45 -0
- data/lib/mail/parsers/message_ids_parser.rb +39 -0
- data/lib/mail/parsers/mime_version_parser.rb +41 -0
- data/lib/mail/parsers/phrase_lists_parser.rb +33 -0
- data/lib/mail/parsers/ragel/common.rl +184 -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 +2129 -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 +29 -0
- data/lib/mail/parsers/ragel.rb +17 -0
- data/lib/mail/parsers/received_parser.rb +47 -0
- data/lib/mail/parsers.rb +26 -0
- data/lib/mail/part.rb +6 -2
- data/lib/mail/parts_list.rb +5 -3
- data/lib/mail/patterns.rb +4 -1
- data/lib/mail/utilities.rb +28 -18
- data/lib/mail/version.rb +1 -1
- data/lib/mail/version_specific/ruby_1_8.rb +6 -2
- data/lib/mail/version_specific/ruby_1_9.rb +61 -21
- data/lib/mail.rb +1 -2
- metadata +112 -73
- data/lib/VERSION +0 -4
- data/lib/load_parsers.rb +0 -35
- 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
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
# field in the email.
|
|
7
7
|
#
|
|
8
8
|
# Sending resent_to to a mail message will instantiate a Mail::Field object that
|
|
9
|
-
# has a ResentToField as
|
|
9
|
+
# has a ResentToField as its field type. This includes all Mail::CommonAddress
|
|
10
10
|
# module instance metods.
|
|
11
11
|
#
|
|
12
12
|
# Only one Resent-To field can appear in a header, though it can have multiple
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
#
|
|
17
17
|
# mail = Mail.new
|
|
18
18
|
# mail.resent_to = 'Mikel Lindsaar <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
|
|
19
|
-
# mail.resent_to #=> ['
|
|
19
|
+
# mail.resent_to #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
|
|
20
20
|
# mail[:resent_to] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::ResentToField:0x180e1c4
|
|
21
21
|
# mail['resent-to'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::ResentToField:0x180e1c4
|
|
22
22
|
# mail['Resent-To'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::ResentToField:0x180e1c4
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
# field in the email.
|
|
7
7
|
#
|
|
8
8
|
# Sending sender to a mail message will instantiate a Mail::Field object that
|
|
9
|
-
# has a SenderField as
|
|
9
|
+
# has a SenderField as its field type. This includes all Mail::CommonAddress
|
|
10
10
|
# module instance metods.
|
|
11
11
|
#
|
|
12
12
|
# Only one Sender field can appear in a header, though it can have multiple
|
|
@@ -15,16 +15,16 @@
|
|
|
15
15
|
# == Examples:
|
|
16
16
|
#
|
|
17
17
|
# mail = Mail.new
|
|
18
|
-
# mail.sender = 'Mikel Lindsaar <mikel@test.lindsaar.net
|
|
19
|
-
# mail.sender #=>
|
|
18
|
+
# mail.sender = 'Mikel Lindsaar <mikel@test.lindsaar.net>'
|
|
19
|
+
# mail.sender #=> 'mikel@test.lindsaar.net'
|
|
20
20
|
# mail[:sender] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::SenderField:0x180e1c4
|
|
21
21
|
# mail['sender'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::SenderField:0x180e1c4
|
|
22
22
|
# mail['Sender'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::SenderField:0x180e1c4
|
|
23
23
|
#
|
|
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>'
|
|
24
|
+
# mail[:sender].encoded #=> "Sender: Mikel Lindsaar <mikel@test.lindsaar.net>\r\n"
|
|
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>']
|
|
28
28
|
#
|
|
29
29
|
require 'mail/fields/common/common_address'
|
|
30
30
|
|
|
@@ -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
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
# field in the email.
|
|
7
7
|
#
|
|
8
8
|
# Sending to to a mail message will instantiate a Mail::Field object that
|
|
9
|
-
# has a ToField as
|
|
9
|
+
# has a ToField as its field type. This includes all Mail::CommonAddress
|
|
10
10
|
# module instance metods.
|
|
11
11
|
#
|
|
12
12
|
# Only one To field can appear in a header, though it can have multiple
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
#
|
|
17
17
|
# mail = Mail.new
|
|
18
18
|
# mail.to = 'Mikel Lindsaar <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
|
|
19
|
-
# mail.to #=> ['
|
|
19
|
+
# mail.to #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
|
|
20
20
|
# mail[:to] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::ToField:0x180e1c4
|
|
21
21
|
# mail['to'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::ToField:0x180e1c4
|
|
22
22
|
# mail['To'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::ToField:0x180e1c4
|
|
@@ -144,9 +144,10 @@ module Mail
|
|
|
144
144
|
limit = 78 - prepend
|
|
145
145
|
limit = limit - 7 - encoding.length if should_encode
|
|
146
146
|
line = ""
|
|
147
|
+
first_word = true
|
|
147
148
|
while !words.empty?
|
|
148
149
|
break unless word = words.first.dup
|
|
149
|
-
word.encode!(charset) if
|
|
150
|
+
word.encode!(charset) if charset && word.respond_to?(:encode!)
|
|
150
151
|
word = encode(word) if should_encode
|
|
151
152
|
word = encode_crlf(word)
|
|
152
153
|
# Skip to next line if we're going to go past the limit
|
|
@@ -158,7 +159,12 @@ module Mail
|
|
|
158
159
|
# Remove the word from the queue ...
|
|
159
160
|
words.shift
|
|
160
161
|
# Add word separator
|
|
161
|
-
|
|
162
|
+
if first_word
|
|
163
|
+
first_word = false
|
|
164
|
+
else
|
|
165
|
+
line << " " if !should_encode
|
|
166
|
+
end
|
|
167
|
+
|
|
162
168
|
# ... add it in encoded form to the current line
|
|
163
169
|
line << word
|
|
164
170
|
end
|
data/lib/mail/header.rb
CHANGED
|
@@ -48,11 +48,15 @@ module Mail
|
|
|
48
48
|
# these cases, please make a patch and send it in, or at the least, send
|
|
49
49
|
# me the example so we can fix it.
|
|
50
50
|
def initialize(header_text = nil, charset = nil)
|
|
51
|
-
@errors = []
|
|
52
51
|
@charset = charset
|
|
53
|
-
self.raw_source = header_text.to_crlf
|
|
52
|
+
self.raw_source = header_text.to_crlf.lstrip
|
|
54
53
|
split_header if header_text
|
|
55
54
|
end
|
|
55
|
+
|
|
56
|
+
def initialize_copy(original)
|
|
57
|
+
super
|
|
58
|
+
@fields = @fields.dup
|
|
59
|
+
end
|
|
56
60
|
|
|
57
61
|
# The preserved raw source of the header as you passed it in, untouched
|
|
58
62
|
# for your Regexing glory.
|
|
@@ -91,7 +95,6 @@ module Mail
|
|
|
91
95
|
unfolded_fields[0..(self.class.maximum_amount-1)].each do |field|
|
|
92
96
|
|
|
93
97
|
field = Field.new(field, nil, charset)
|
|
94
|
-
field.errors.each { |error| self.errors << error }
|
|
95
98
|
if limited_field?(field.name) && (selected = select_field_for(field.name)) && selected.any?
|
|
96
99
|
selected.first.update(field.name, field.value)
|
|
97
100
|
else
|
|
@@ -102,7 +105,7 @@ module Mail
|
|
|
102
105
|
end
|
|
103
106
|
|
|
104
107
|
def errors
|
|
105
|
-
@errors
|
|
108
|
+
@fields.map(&:errors).flatten(1)
|
|
106
109
|
end
|
|
107
110
|
|
|
108
111
|
# 3.6. Field definitions
|
|
@@ -154,6 +157,9 @@ module Mail
|
|
|
154
157
|
# h['X-Mail-SPAM'] # => nil
|
|
155
158
|
def []=(name, value)
|
|
156
159
|
name = dasherize(name)
|
|
160
|
+
if name.include?(':')
|
|
161
|
+
raise ArgumentError, "Header names may not contain a colon: #{name.inspect}"
|
|
162
|
+
end
|
|
157
163
|
fn = name.downcase
|
|
158
164
|
selected = select_field_for(fn)
|
|
159
165
|
|
|
@@ -174,7 +180,7 @@ module Mail
|
|
|
174
180
|
if dasherize(fn) == "content-type"
|
|
175
181
|
# Update charset if specified in Content-Type
|
|
176
182
|
params = self[:content_type].parameters rescue nil
|
|
177
|
-
@charset = params && params[:charset]
|
|
183
|
+
@charset = params[:charset] if params && params[:charset]
|
|
178
184
|
end
|
|
179
185
|
end
|
|
180
186
|
|
|
@@ -198,6 +204,7 @@ module Mail
|
|
|
198
204
|
|
|
199
205
|
def encoded
|
|
200
206
|
buffer = ''
|
|
207
|
+
buffer.force_encoding('us-ascii') if buffer.respond_to?(:force_encoding)
|
|
201
208
|
fields.each do |field|
|
|
202
209
|
buffer << field.encoded
|
|
203
210
|
end
|
|
@@ -242,27 +249,10 @@ module Mail
|
|
|
242
249
|
@raw_source = val
|
|
243
250
|
end
|
|
244
251
|
|
|
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
252
|
# Splits an unfolded and line break cleaned header into individual field
|
|
263
253
|
# strings.
|
|
264
254
|
def split_header
|
|
265
|
-
self.fields =
|
|
255
|
+
self.fields = raw_source.split(HEADER_SPLIT)
|
|
266
256
|
end
|
|
267
257
|
|
|
268
258
|
def select_field_for(name)
|
data/lib/mail/mail.rb
CHANGED
|
@@ -206,6 +206,12 @@ module Mail
|
|
|
206
206
|
end
|
|
207
207
|
end
|
|
208
208
|
|
|
209
|
+
# Unregister the given observer, allowing mail to resume operations
|
|
210
|
+
# without it.
|
|
211
|
+
def self.unregister_observer(observer)
|
|
212
|
+
@@delivery_notification_observers.delete(observer)
|
|
213
|
+
end
|
|
214
|
+
|
|
209
215
|
# You can register an object to be given every mail object that will be sent,
|
|
210
216
|
# before it is sent. So if you want to add special headers or modify any
|
|
211
217
|
# email that gets sent through the Mail library, you can do so.
|
|
@@ -219,6 +225,12 @@ module Mail
|
|
|
219
225
|
end
|
|
220
226
|
end
|
|
221
227
|
|
|
228
|
+
# Unregister the given interceptor, allowing mail to resume operations
|
|
229
|
+
# without it.
|
|
230
|
+
def self.unregister_interceptor(interceptor)
|
|
231
|
+
@@delivery_interceptors.delete(interceptor)
|
|
232
|
+
end
|
|
233
|
+
|
|
222
234
|
def self.inform_observers(mail)
|
|
223
235
|
@@delivery_notification_observers.each do |observer|
|
|
224
236
|
observer.delivered_email(mail)
|
|
@@ -29,6 +29,29 @@ module Mail
|
|
|
29
29
|
self
|
|
30
30
|
end
|
|
31
31
|
|
|
32
|
+
def cc(recipient_or_list)
|
|
33
|
+
@copy_recipients ||= []
|
|
34
|
+
|
|
35
|
+
if recipient_or_list.kind_of?(Array)
|
|
36
|
+
@copy_recipients += recipient_or_list
|
|
37
|
+
else
|
|
38
|
+
@copy_recipients << recipient_or_list
|
|
39
|
+
end
|
|
40
|
+
self
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def bcc(recipient_or_list)
|
|
44
|
+
@blind_copy_recipients ||= []
|
|
45
|
+
|
|
46
|
+
if recipient_or_list.kind_of?(Array)
|
|
47
|
+
@blind_copy_recipients += recipient_or_list
|
|
48
|
+
else
|
|
49
|
+
@blind_copy_recipients << recipient_or_list
|
|
50
|
+
end
|
|
51
|
+
self
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
|
|
32
55
|
def with_subject(subject)
|
|
33
56
|
@subject = subject
|
|
34
57
|
self
|
|
@@ -73,7 +96,7 @@ module Mail
|
|
|
73
96
|
def filter_matched_deliveries(deliveries)
|
|
74
97
|
candidate_deliveries = deliveries
|
|
75
98
|
|
|
76
|
-
%w(sender recipients subject subject_matcher body body_matcher).each do |modifier_name|
|
|
99
|
+
%w(sender recipients copy_recipients blind_copy_recipients subject subject_matcher body body_matcher).each do |modifier_name|
|
|
77
100
|
next unless instance_variable_defined?("@#{modifier_name}")
|
|
78
101
|
candidate_deliveries = candidate_deliveries.select{|matching_delivery| self.send("matches_on_#{modifier_name}?", matching_delivery)}
|
|
79
102
|
end
|
|
@@ -89,6 +112,14 @@ module Mail
|
|
|
89
112
|
@recipients.all? {|recipient| delivery.to.include?(recipient) }
|
|
90
113
|
end
|
|
91
114
|
|
|
115
|
+
def matches_on_copy_recipients?(delivery)
|
|
116
|
+
@copy_recipients.all? {|recipient| delivery.cc.include?(recipient) }
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def matches_on_blind_copy_recipients?(delivery)
|
|
120
|
+
@blind_copy_recipients.all? {|recipient| delivery.bcc.include?(recipient) }
|
|
121
|
+
end
|
|
122
|
+
|
|
92
123
|
def matches_on_subject?(delivery)
|
|
93
124
|
delivery.subject == @subject
|
|
94
125
|
end
|
|
@@ -109,6 +140,8 @@ module Mail
|
|
|
109
140
|
result = ''
|
|
110
141
|
result += "from #{@sender} " if instance_variable_defined?('@sender')
|
|
111
142
|
result += "to #{@recipients.inspect} " if instance_variable_defined?('@recipients')
|
|
143
|
+
result += "cc #{@copy_recipients.inspect} " if instance_variable_defined?('@copy_recipients')
|
|
144
|
+
result += "bcc #{@blind_copy_recipients.inspect} " if instance_variable_defined?('@blind_copy_recipients')
|
|
112
145
|
result += "with subject \"#{@subject}\" " if instance_variable_defined?('@subject')
|
|
113
146
|
result += "with subject matching \"#{@subject_matcher}\" " if instance_variable_defined?('@subject_matcher')
|
|
114
147
|
result += "with body \"#{@body}\" " if instance_variable_defined?('@body')
|
data/lib/mail/message.rb
CHANGED
|
@@ -108,6 +108,9 @@ module Mail
|
|
|
108
108
|
@charset = 'UTF-8'
|
|
109
109
|
@defaulted_charset = true
|
|
110
110
|
|
|
111
|
+
@smtp_envelope_from = nil
|
|
112
|
+
@smtp_envelope_to = nil
|
|
113
|
+
|
|
111
114
|
@perform_deliveries = true
|
|
112
115
|
@raise_delivery_errors = true
|
|
113
116
|
|
|
@@ -122,7 +125,7 @@ module Mail
|
|
|
122
125
|
if args.flatten.first.respond_to?(:each_pair)
|
|
123
126
|
init_with_hash(args.flatten.first)
|
|
124
127
|
else
|
|
125
|
-
init_with_string(args.flatten[0].to_s
|
|
128
|
+
init_with_string(args.flatten[0].to_s)
|
|
126
129
|
end
|
|
127
130
|
|
|
128
131
|
if block_given?
|
|
@@ -169,7 +172,7 @@ module Mail
|
|
|
169
172
|
# obj.mail.deliver
|
|
170
173
|
#
|
|
171
174
|
# Would cause Mail to call obj.deliver_mail passing itself as a parameter,
|
|
172
|
-
# which then can just yield and let Mail do
|
|
175
|
+
# which then can just yield and let Mail do its own private do_delivery
|
|
173
176
|
# method.
|
|
174
177
|
attr_accessor :delivery_handler
|
|
175
178
|
|
|
@@ -237,7 +240,7 @@ module Mail
|
|
|
237
240
|
# This method bypasses checking perform_deliveries and raise_delivery_errors,
|
|
238
241
|
# so use with caution.
|
|
239
242
|
#
|
|
240
|
-
# It still however fires off the
|
|
243
|
+
# It still however fires off the interceptors and calls the observers callbacks if they are defined.
|
|
241
244
|
#
|
|
242
245
|
# Returns self
|
|
243
246
|
def deliver!
|
|
@@ -350,17 +353,23 @@ module Mail
|
|
|
350
353
|
return false unless other.respond_to?(:encoded)
|
|
351
354
|
|
|
352
355
|
if self.message_id && other.message_id
|
|
353
|
-
|
|
356
|
+
self.encoded == other.encoded
|
|
354
357
|
else
|
|
355
358
|
self_message_id, other_message_id = self.message_id, other.message_id
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
359
|
+
begin
|
|
360
|
+
self.message_id, other.message_id = '<temp@test>', '<temp@test>'
|
|
361
|
+
self.encoded == other.encoded
|
|
362
|
+
ensure
|
|
363
|
+
self.message_id, other.message_id = self_message_id, other_message_id
|
|
364
|
+
end
|
|
361
365
|
end
|
|
362
366
|
end
|
|
363
367
|
|
|
368
|
+
def initialize_copy(original)
|
|
369
|
+
super
|
|
370
|
+
@header = @header.dup
|
|
371
|
+
end
|
|
372
|
+
|
|
364
373
|
# Provides access to the raw source of the message as it was when it
|
|
365
374
|
# was instantiated. This is set at initialization and so is untouched
|
|
366
375
|
# by the parsers or decoder / encoders
|
|
@@ -938,8 +947,8 @@ module Mail
|
|
|
938
947
|
#
|
|
939
948
|
# Example:
|
|
940
949
|
#
|
|
941
|
-
# mail.
|
|
942
|
-
# mail.
|
|
950
|
+
# mail.resent_sender = 'Mikel <mikel@test.lindsaar.net>'
|
|
951
|
+
# mail.resent_sender #=> 'mikel@test.lindsaar.net'
|
|
943
952
|
def resent_sender=( val )
|
|
944
953
|
header[:resent_sender] = val
|
|
945
954
|
end
|
|
@@ -1023,6 +1032,82 @@ module Mail
|
|
|
1023
1032
|
header[:sender] = val
|
|
1024
1033
|
end
|
|
1025
1034
|
|
|
1035
|
+
# Returns the SMTP Envelope From value of the mail object, as a single
|
|
1036
|
+
# string of an address spec.
|
|
1037
|
+
#
|
|
1038
|
+
# Defaults to Return-Path, Sender, or the first From address.
|
|
1039
|
+
#
|
|
1040
|
+
# Example:
|
|
1041
|
+
#
|
|
1042
|
+
# mail.smtp_envelope_from = 'Mikel <mikel@test.lindsaar.net>'
|
|
1043
|
+
# mail.smtp_envelope_from #=> 'mikel@test.lindsaar.net'
|
|
1044
|
+
#
|
|
1045
|
+
# Also allows you to set the value by passing a value as a parameter
|
|
1046
|
+
#
|
|
1047
|
+
# Example:
|
|
1048
|
+
#
|
|
1049
|
+
# mail.smtp_envelope_from 'Mikel <mikel@test.lindsaar.net>'
|
|
1050
|
+
# mail.smtp_envelope_from #=> 'mikel@test.lindsaar.net'
|
|
1051
|
+
def smtp_envelope_from( val = nil )
|
|
1052
|
+
if val
|
|
1053
|
+
self.smtp_envelope_from = val
|
|
1054
|
+
else
|
|
1055
|
+
@smtp_envelope_from || return_path || sender || from_addrs.first
|
|
1056
|
+
end
|
|
1057
|
+
end
|
|
1058
|
+
|
|
1059
|
+
# Sets the From address on the SMTP Envelope.
|
|
1060
|
+
#
|
|
1061
|
+
# Example:
|
|
1062
|
+
#
|
|
1063
|
+
# mail.smtp_envelope_from = 'Mikel <mikel@test.lindsaar.net>'
|
|
1064
|
+
# mail.smtp_envelope_from #=> 'mikel@test.lindsaar.net'
|
|
1065
|
+
def smtp_envelope_from=( val )
|
|
1066
|
+
@smtp_envelope_from = val
|
|
1067
|
+
end
|
|
1068
|
+
|
|
1069
|
+
# Returns the SMTP Envelope To value of the mail object.
|
|
1070
|
+
#
|
|
1071
|
+
# Defaults to #destinations: To, Cc, and Bcc addresses.
|
|
1072
|
+
#
|
|
1073
|
+
# Example:
|
|
1074
|
+
#
|
|
1075
|
+
# mail.smtp_envelope_to = 'Mikel <mikel@test.lindsaar.net>'
|
|
1076
|
+
# mail.smtp_envelope_to #=> 'mikel@test.lindsaar.net'
|
|
1077
|
+
#
|
|
1078
|
+
# Also allows you to set the value by passing a value as a parameter
|
|
1079
|
+
#
|
|
1080
|
+
# Example:
|
|
1081
|
+
#
|
|
1082
|
+
# mail.smtp_envelope_to ['Mikel <mikel@test.lindsaar.net>', 'Lindsaar <lindsaar@test.lindsaar.net>']
|
|
1083
|
+
# mail.smtp_envelope_to #=> ['mikel@test.lindsaar.net', 'lindsaar@test.lindsaar.net']
|
|
1084
|
+
def smtp_envelope_to( val = nil )
|
|
1085
|
+
if val
|
|
1086
|
+
self.smtp_envelope_to = val
|
|
1087
|
+
else
|
|
1088
|
+
@smtp_envelope_to || destinations
|
|
1089
|
+
end
|
|
1090
|
+
end
|
|
1091
|
+
|
|
1092
|
+
# Sets the To addresses on the SMTP Envelope.
|
|
1093
|
+
#
|
|
1094
|
+
# Example:
|
|
1095
|
+
#
|
|
1096
|
+
# mail.smtp_envelope_to = 'Mikel <mikel@test.lindsaar.net>'
|
|
1097
|
+
# mail.smtp_envelope_to #=> 'mikel@test.lindsaar.net'
|
|
1098
|
+
#
|
|
1099
|
+
# mail.smtp_envelope_to = ['Mikel <mikel@test.lindsaar.net>', 'Lindsaar <lindsaar@test.lindsaar.net>']
|
|
1100
|
+
# mail.smtp_envelope_to #=> ['mikel@test.lindsaar.net', 'lindsaar@test.lindsaar.net']
|
|
1101
|
+
def smtp_envelope_to=( val )
|
|
1102
|
+
@smtp_envelope_to =
|
|
1103
|
+
case val
|
|
1104
|
+
when Array, NilClass
|
|
1105
|
+
val
|
|
1106
|
+
else
|
|
1107
|
+
[val]
|
|
1108
|
+
end
|
|
1109
|
+
end
|
|
1110
|
+
|
|
1026
1111
|
# Returns the decoded value of the subject field, as a single string.
|
|
1027
1112
|
#
|
|
1028
1113
|
# Example:
|
|
@@ -1309,7 +1394,7 @@ module Mail
|
|
|
1309
1394
|
header.has_date?
|
|
1310
1395
|
end
|
|
1311
1396
|
|
|
1312
|
-
# Returns true if the message has a
|
|
1397
|
+
# Returns true if the message has a Mime-Version field, the field may or may
|
|
1313
1398
|
# not have a value, but the field exists or not.
|
|
1314
1399
|
def has_mime_version?
|
|
1315
1400
|
header.has_mime_version?
|
|
@@ -1515,8 +1600,8 @@ module Mail
|
|
|
1515
1600
|
end
|
|
1516
1601
|
|
|
1517
1602
|
# Returns an AttachmentsList object, which holds all of the attachments in
|
|
1518
|
-
# the receiver object (either the
|
|
1519
|
-
# of
|
|
1603
|
+
# the receiver object (either the entire email or a part within) and all
|
|
1604
|
+
# of its descendants.
|
|
1520
1605
|
#
|
|
1521
1606
|
# It also allows you to add attachments to the mail object directly, like so:
|
|
1522
1607
|
#
|
|
@@ -1559,9 +1644,7 @@ module Mail
|
|
|
1559
1644
|
# Accessor for html_part
|
|
1560
1645
|
def html_part(&block)
|
|
1561
1646
|
if block_given?
|
|
1562
|
-
|
|
1563
|
-
add_multipart_alternate_header unless html_part.blank?
|
|
1564
|
-
add_part(@html_part)
|
|
1647
|
+
self.html_part = Mail::Part.new(:content_type => 'text/html', &block)
|
|
1565
1648
|
else
|
|
1566
1649
|
@html_part || find_first_mime_type('text/html')
|
|
1567
1650
|
end
|
|
@@ -1570,9 +1653,7 @@ module Mail
|
|
|
1570
1653
|
# Accessor for text_part
|
|
1571
1654
|
def text_part(&block)
|
|
1572
1655
|
if block_given?
|
|
1573
|
-
|
|
1574
|
-
add_multipart_alternate_header unless html_part.blank?
|
|
1575
|
-
add_part(@text_part)
|
|
1656
|
+
self.text_part = Mail::Part.new(:content_type => 'text/plain', &block)
|
|
1576
1657
|
else
|
|
1577
1658
|
@text_part || find_first_mime_type('text/plain')
|
|
1578
1659
|
end
|
|
@@ -1581,36 +1662,54 @@ module Mail
|
|
|
1581
1662
|
# Helper to add a html part to a multipart/alternative email. If this and
|
|
1582
1663
|
# text_part are both defined in a message, then it will be a multipart/alternative
|
|
1583
1664
|
# message and set itself that way.
|
|
1584
|
-
def html_part=(msg
|
|
1665
|
+
def html_part=(msg)
|
|
1666
|
+
# Assign the html part and set multipart/alternative if there's a text part.
|
|
1585
1667
|
if msg
|
|
1586
1668
|
@html_part = msg
|
|
1587
|
-
|
|
1588
|
-
|
|
1669
|
+
@html_part.content_type = 'text/html' unless @html_part.has_content_type?
|
|
1670
|
+
add_multipart_alternate_header if text_part
|
|
1671
|
+
add_part @html_part
|
|
1672
|
+
|
|
1673
|
+
# If nil, delete the html part and back out of multipart/alternative.
|
|
1674
|
+
elsif @html_part
|
|
1675
|
+
parts.delete_if { |p| p.object_id == @html_part.object_id }
|
|
1676
|
+
@html_part = nil
|
|
1677
|
+
if text_part
|
|
1678
|
+
self.content_type = nil
|
|
1679
|
+
body.boundary = nil
|
|
1680
|
+
end
|
|
1589
1681
|
end
|
|
1590
|
-
add_multipart_alternate_header unless text_part.blank?
|
|
1591
|
-
add_part(@html_part)
|
|
1592
1682
|
end
|
|
1593
1683
|
|
|
1594
1684
|
# Helper to add a text part to a multipart/alternative email. If this and
|
|
1595
1685
|
# html_part are both defined in a message, then it will be a multipart/alternative
|
|
1596
1686
|
# message and set itself that way.
|
|
1597
|
-
def text_part=(msg
|
|
1687
|
+
def text_part=(msg)
|
|
1688
|
+
# Assign the text part and set multipart/alternative if there's an html part.
|
|
1598
1689
|
if msg
|
|
1599
1690
|
@text_part = msg
|
|
1600
|
-
|
|
1601
|
-
|
|
1691
|
+
@text_part.content_type = 'text/plain' unless @text_part.has_content_type?
|
|
1692
|
+
add_multipart_alternate_header if html_part
|
|
1693
|
+
add_part @text_part
|
|
1694
|
+
|
|
1695
|
+
# If nil, delete the text part and back out of multipart/alternative.
|
|
1696
|
+
elsif @text_part
|
|
1697
|
+
parts.delete_if { |p| p.object_id == @text_part.object_id }
|
|
1698
|
+
@text_part = nil
|
|
1699
|
+
if html_part
|
|
1700
|
+
self.content_type = nil
|
|
1701
|
+
body.boundary = nil
|
|
1702
|
+
end
|
|
1602
1703
|
end
|
|
1603
|
-
add_multipart_alternate_header unless html_part.blank?
|
|
1604
|
-
add_part(@text_part)
|
|
1605
1704
|
end
|
|
1606
1705
|
|
|
1607
1706
|
# Adds a part to the parts list or creates the part list
|
|
1608
1707
|
def add_part(part)
|
|
1609
1708
|
if !body.multipart? && !self.body.decoded.blank?
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1709
|
+
@text_part = Mail::Part.new('Content-Type: text/plain;')
|
|
1710
|
+
@text_part.body = body.decoded
|
|
1711
|
+
self.body << @text_part
|
|
1712
|
+
add_multipart_alternate_header
|
|
1614
1713
|
end
|
|
1615
1714
|
add_boundary
|
|
1616
1715
|
self.body << part
|
|
@@ -1646,7 +1745,7 @@ module Mail
|
|
|
1646
1745
|
# m.add_file(:filename => 'filename.png', :content => File.read('/path/to/file.jpg'))
|
|
1647
1746
|
#
|
|
1648
1747
|
# Note also that if you add a file to an existing message, Mail will convert that message
|
|
1649
|
-
# to a MIME multipart email, moving whatever plain text body you had into
|
|
1748
|
+
# to a MIME multipart email, moving whatever plain text body you had into its own text
|
|
1650
1749
|
# plain part.
|
|
1651
1750
|
#
|
|
1652
1751
|
# Example:
|
|
@@ -1683,7 +1782,7 @@ module Mail
|
|
|
1683
1782
|
self.body << text_part
|
|
1684
1783
|
end
|
|
1685
1784
|
|
|
1686
|
-
# Encodes the message, calls encode on all
|
|
1785
|
+
# Encodes the message, calls encode on all its parts, gets an email message
|
|
1687
1786
|
# ready to send
|
|
1688
1787
|
def ready_to_send!
|
|
1689
1788
|
identify_and_set_transfer_encoding
|
|
@@ -1875,14 +1974,15 @@ module Mail
|
|
|
1875
1974
|
# Additionally, I allow for the case where someone might have put whitespace
|
|
1876
1975
|
# on the "gap line"
|
|
1877
1976
|
def parse_message
|
|
1878
|
-
header_part, body_part = raw_source.split(/#{CRLF}#{WSP}*#{CRLF}(?!#{WSP})/m, 2)
|
|
1977
|
+
header_part, body_part = raw_source.lstrip.split(/#{CRLF}#{CRLF}|#{CRLF}#{WSP}*#{CRLF}(?!#{WSP})/m, 2)
|
|
1879
1978
|
self.header = header_part
|
|
1880
1979
|
self.body = body_part
|
|
1881
1980
|
end
|
|
1882
1981
|
|
|
1883
1982
|
def raw_source=(value)
|
|
1884
|
-
value.force_encoding("binary") if RUBY_VERSION >= "1.9.1"
|
|
1885
1983
|
@raw_source = value.to_crlf
|
|
1984
|
+
@raw_source.force_encoding("binary") if RUBY_VERSION >= "1.9.1"
|
|
1985
|
+
@raw_source
|
|
1886
1986
|
end
|
|
1887
1987
|
|
|
1888
1988
|
# see comments to body=. We take data and process it lazily
|
|
@@ -1904,11 +2004,11 @@ module Mail
|
|
|
1904
2004
|
|
|
1905
2005
|
|
|
1906
2006
|
def process_body_raw
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
2007
|
+
@body = Mail::Body.new(@body_raw)
|
|
2008
|
+
@body_raw = nil
|
|
2009
|
+
separate_parts if @separate_parts
|
|
1910
2010
|
|
|
1911
|
-
|
|
2011
|
+
add_encoding_to_body
|
|
1912
2012
|
end
|
|
1913
2013
|
|
|
1914
2014
|
def set_envelope_header
|
|
@@ -1938,16 +2038,19 @@ module Mail
|
|
|
1938
2038
|
end
|
|
1939
2039
|
|
|
1940
2040
|
def add_required_fields
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
add_message_id unless (has_message_id? || self.class == Mail::Part)
|
|
1944
|
-
add_date unless has_date?
|
|
1945
|
-
add_mime_version unless has_mime_version?
|
|
2041
|
+
add_required_message_fields
|
|
2042
|
+
add_multipart_mixed_header if body.multipart?
|
|
1946
2043
|
add_content_type unless has_content_type?
|
|
1947
2044
|
add_charset unless has_charset?
|
|
1948
2045
|
add_content_transfer_encoding unless has_content_transfer_encoding?
|
|
1949
2046
|
end
|
|
1950
2047
|
|
|
2048
|
+
def add_required_message_fields
|
|
2049
|
+
add_date unless has_date?
|
|
2050
|
+
add_mime_version unless has_mime_version?
|
|
2051
|
+
add_message_id unless has_message_id?
|
|
2052
|
+
end
|
|
2053
|
+
|
|
1951
2054
|
def add_multipart_alternate_header
|
|
1952
2055
|
header['content-type'] = ContentTypeField.with_boundary('multipart/alternative').value
|
|
1953
2056
|
header['content_type'].parameters[:charset] = @charset
|
|
@@ -2032,7 +2135,7 @@ module Mail
|
|
|
2032
2135
|
if perform_deliveries
|
|
2033
2136
|
delivery_method.deliver!(self)
|
|
2034
2137
|
end
|
|
2035
|
-
rescue
|
|
2138
|
+
rescue => e # Net::SMTP errors or sendmail pipe errors
|
|
2036
2139
|
raise e if raise_delivery_errors
|
|
2037
2140
|
end
|
|
2038
2141
|
end
|
data/lib/mail/multibyte/chars.rb
CHANGED
|
@@ -364,7 +364,7 @@ module Mail #:nodoc:
|
|
|
364
364
|
# "ÉL QUE SE ENTERÓ".mb_chars.titleize # => "Él Que Se Enteró"
|
|
365
365
|
# "日本語".mb_chars.titleize # => "日本語"
|
|
366
366
|
def titleize
|
|
367
|
-
chars(downcase.to_s.gsub(/\b('
|
|
367
|
+
chars(downcase.to_s.gsub(/\b('?\S)/u) { Unicode.apply_mapping $1, :uppercase_mapping })
|
|
368
368
|
end
|
|
369
369
|
alias_method :titlecase, :titleize
|
|
370
370
|
|
|
@@ -412,7 +412,7 @@ module Mail #:nodoc:
|
|
|
412
412
|
chars(Unicode.tidy_bytes(@wrapped_string, force))
|
|
413
413
|
end
|
|
414
414
|
|
|
415
|
-
|
|
415
|
+
%w(capitalize downcase lstrip reverse rstrip slice strip tidy_bytes upcase).each do |method|
|
|
416
416
|
# Only define a corresponding bang method for methods defined in the proxy; On 1.9 the proxy will
|
|
417
417
|
# exclude lstrip!, rstrip! and strip! because they are already work as expected on multibyte strings.
|
|
418
418
|
if public_method_defined?(method)
|
|
@@ -341,7 +341,7 @@ module Mail
|
|
|
341
341
|
def load
|
|
342
342
|
begin
|
|
343
343
|
@codepoints, @composition_exclusion, @composition_map, @boundary, @cp1252 = File.open(self.class.filename, 'rb') { |f| Marshal.load f.read }
|
|
344
|
-
rescue
|
|
344
|
+
rescue => e
|
|
345
345
|
raise IOError.new("Couldn't load the Unicode tables for UTF8Handler (#{e.message}), Mail::Multibyte is unusable")
|
|
346
346
|
end
|
|
347
347
|
|
|
@@ -391,8 +391,10 @@ module Mail
|
|
|
391
391
|
end
|
|
392
392
|
end
|
|
393
393
|
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
394
|
+
unless defined?(ActiveSupport)
|
|
395
|
+
module ActiveSupport
|
|
396
|
+
unless const_defined?(:Multibyte)
|
|
397
|
+
Multibyte = Mail::Multibyte
|
|
398
|
+
end
|
|
397
399
|
end
|
|
398
400
|
end
|