mail 2.4.4 → 2.6.3
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 +156 -0
- data/CONTRIBUTING.md +21 -6
- data/Dependencies.txt +0 -1
- data/Gemfile +10 -21
- data/MIT-LICENSE +20 -0
- data/README.md +52 -32
- data/Rakefile +11 -22
- data/lib/mail/attachments_list.rb +2 -2
- data/lib/mail/body.rb +33 -9
- data/lib/mail/check_delivery_params.rb +20 -0
- data/lib/mail/configuration.rb +1 -1
- data/lib/mail/{patterns.rb → constants.rb} +26 -6
- data/lib/mail/core_extensions/nil.rb +4 -2
- 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 +19 -6
- data/lib/mail/elements/address.rb +82 -141
- data/lib/mail/elements/address_list.rb +9 -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/elements.rb +12 -12
- data/lib/mail/encodings/quoted_printable.rb +4 -3
- data/lib/mail/encodings/unix_to_unix.rb +17 -0
- data/lib/mail/encodings.rb +53 -38
- data/lib/mail/envelope.rb +0 -5
- data/lib/mail/field.rb +131 -118
- 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 +32 -22
- data/lib/mail/fields/common/common_date.rb +0 -7
- data/lib/mail/fields/common/common_field.rb +10 -3
- data/lib/mail/fields/common/common_message_id.rb +9 -5
- data/lib/mail/fields/common/parameter_hash.rb +3 -3
- data/lib/mail/fields/content_disposition_field.rb +1 -0
- 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 +5 -2
- data/lib/mail/fields/date_field.rb +14 -14
- data/lib/mail/fields/from_field.rb +2 -2
- data/lib/mail/fields/in_reply_to_field.rb +2 -1
- data/lib/mail/fields/keywords_field.rb +1 -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 +44 -31
- data/lib/mail/fields.rb +32 -32
- data/lib/mail/header.rb +47 -37
- data/lib/mail/mail.rb +15 -1
- data/lib/mail/matchers/has_sent_mail.rb +36 -3
- data/lib/mail/message.rb +164 -57
- data/lib/mail/multibyte/chars.rb +4 -4
- data/lib/mail/multibyte/unicode.rb +9 -1
- data/lib/mail/network/delivery_methods/exim.rb +2 -3
- data/lib/mail/network/delivery_methods/file_delivery.rb +5 -0
- data/lib/mail/network/delivery_methods/sendmail.rb +35 -8
- data/lib/mail/network/delivery_methods/smtp.rb +34 -45
- data/lib/mail/network/delivery_methods/smtp_connection.rb +9 -22
- data/lib/mail/network/delivery_methods/test_mailer.rb +6 -2
- data/lib/mail/network/retriever_methods/imap.rb +32 -19
- data/lib/mail/network/retriever_methods/pop3.rb +2 -2
- data/lib/mail/network/retriever_methods/test_retriever.rb +11 -15
- data/lib/mail/network.rb +9 -9
- 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 +66 -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 +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 +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/utilities.rb +70 -60
- data/lib/mail/values/unicode_tables.dat +0 -0
- data/lib/mail/version.rb +7 -15
- data/lib/mail/version_specific/ruby_1_8.rb +25 -4
- data/lib/mail/version_specific/ruby_1_9.rb +110 -30
- data/lib/mail.rb +20 -19
- metadata +129 -73
- data/Gemfile.lock +0 -36
- data/lib/VERSION +0 -4
- 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 -5341
- 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
data/lib/mail/message.rb
CHANGED
|
@@ -46,7 +46,7 @@ module Mail
|
|
|
46
46
|
# (i.e., a line with nothing preceding the CRLF).
|
|
47
47
|
class Message
|
|
48
48
|
|
|
49
|
-
include
|
|
49
|
+
include Constants
|
|
50
50
|
include Utilities
|
|
51
51
|
|
|
52
52
|
# ==Making an email
|
|
@@ -105,9 +105,12 @@ module Mail
|
|
|
105
105
|
@html_part = nil
|
|
106
106
|
@errors = nil
|
|
107
107
|
@header = nil
|
|
108
|
-
@charset =
|
|
108
|
+
@charset = self.class.default_charset
|
|
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
|
|
|
@@ -204,6 +207,10 @@ module Mail
|
|
|
204
207
|
# define a delivery_handler
|
|
205
208
|
attr_accessor :raise_delivery_errors
|
|
206
209
|
|
|
210
|
+
def self.default_charset; @@default_charset; end
|
|
211
|
+
def self.default_charset=(charset); @@default_charset = charset; end
|
|
212
|
+
self.default_charset = 'UTF-8'
|
|
213
|
+
|
|
207
214
|
def register_for_delivery_notification(observer)
|
|
208
215
|
STDERR.puts("Message#register_for_delivery_notification is deprecated, please call Mail.register_observer instead")
|
|
209
216
|
Mail.register_observer(observer)
|
|
@@ -237,7 +244,7 @@ module Mail
|
|
|
237
244
|
# This method bypasses checking perform_deliveries and raise_delivery_errors,
|
|
238
245
|
# so use with caution.
|
|
239
246
|
#
|
|
240
|
-
# It still however fires off the
|
|
247
|
+
# It still however fires off the interceptors and calls the observers callbacks if they are defined.
|
|
241
248
|
#
|
|
242
249
|
# Returns self
|
|
243
250
|
def deliver!
|
|
@@ -350,17 +357,23 @@ module Mail
|
|
|
350
357
|
return false unless other.respond_to?(:encoded)
|
|
351
358
|
|
|
352
359
|
if self.message_id && other.message_id
|
|
353
|
-
|
|
360
|
+
self.encoded == other.encoded
|
|
354
361
|
else
|
|
355
362
|
self_message_id, other_message_id = self.message_id, other.message_id
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
363
|
+
begin
|
|
364
|
+
self.message_id, other.message_id = '<temp@test>', '<temp@test>'
|
|
365
|
+
self.encoded == other.encoded
|
|
366
|
+
ensure
|
|
367
|
+
self.message_id, other.message_id = self_message_id, other_message_id
|
|
368
|
+
end
|
|
361
369
|
end
|
|
362
370
|
end
|
|
363
371
|
|
|
372
|
+
def initialize_copy(original)
|
|
373
|
+
super
|
|
374
|
+
@header = @header.dup
|
|
375
|
+
end
|
|
376
|
+
|
|
364
377
|
# Provides access to the raw source of the message as it was when it
|
|
365
378
|
# was instantiated. This is set at initialization and so is untouched
|
|
366
379
|
# by the parsers or decoder / encoders
|
|
@@ -938,8 +951,8 @@ module Mail
|
|
|
938
951
|
#
|
|
939
952
|
# Example:
|
|
940
953
|
#
|
|
941
|
-
# mail.
|
|
942
|
-
# mail.
|
|
954
|
+
# mail.resent_sender = 'Mikel <mikel@test.lindsaar.net>'
|
|
955
|
+
# mail.resent_sender #=> 'mikel@test.lindsaar.net'
|
|
943
956
|
def resent_sender=( val )
|
|
944
957
|
header[:resent_sender] = val
|
|
945
958
|
end
|
|
@@ -1023,6 +1036,82 @@ module Mail
|
|
|
1023
1036
|
header[:sender] = val
|
|
1024
1037
|
end
|
|
1025
1038
|
|
|
1039
|
+
# Returns the SMTP Envelope From value of the mail object, as a single
|
|
1040
|
+
# string of an address spec.
|
|
1041
|
+
#
|
|
1042
|
+
# Defaults to Return-Path, Sender, or the first From address.
|
|
1043
|
+
#
|
|
1044
|
+
# Example:
|
|
1045
|
+
#
|
|
1046
|
+
# mail.smtp_envelope_from = 'Mikel <mikel@test.lindsaar.net>'
|
|
1047
|
+
# mail.smtp_envelope_from #=> 'mikel@test.lindsaar.net'
|
|
1048
|
+
#
|
|
1049
|
+
# Also allows you to set the value by passing a value as a parameter
|
|
1050
|
+
#
|
|
1051
|
+
# Example:
|
|
1052
|
+
#
|
|
1053
|
+
# mail.smtp_envelope_from 'Mikel <mikel@test.lindsaar.net>'
|
|
1054
|
+
# mail.smtp_envelope_from #=> 'mikel@test.lindsaar.net'
|
|
1055
|
+
def smtp_envelope_from( val = nil )
|
|
1056
|
+
if val
|
|
1057
|
+
self.smtp_envelope_from = val
|
|
1058
|
+
else
|
|
1059
|
+
@smtp_envelope_from || return_path || sender || from_addrs.first
|
|
1060
|
+
end
|
|
1061
|
+
end
|
|
1062
|
+
|
|
1063
|
+
# Sets the From address on the SMTP Envelope.
|
|
1064
|
+
#
|
|
1065
|
+
# Example:
|
|
1066
|
+
#
|
|
1067
|
+
# mail.smtp_envelope_from = 'Mikel <mikel@test.lindsaar.net>'
|
|
1068
|
+
# mail.smtp_envelope_from #=> 'mikel@test.lindsaar.net'
|
|
1069
|
+
def smtp_envelope_from=( val )
|
|
1070
|
+
@smtp_envelope_from = val
|
|
1071
|
+
end
|
|
1072
|
+
|
|
1073
|
+
# Returns the SMTP Envelope To value of the mail object.
|
|
1074
|
+
#
|
|
1075
|
+
# Defaults to #destinations: To, Cc, and Bcc addresses.
|
|
1076
|
+
#
|
|
1077
|
+
# Example:
|
|
1078
|
+
#
|
|
1079
|
+
# mail.smtp_envelope_to = 'Mikel <mikel@test.lindsaar.net>'
|
|
1080
|
+
# mail.smtp_envelope_to #=> 'mikel@test.lindsaar.net'
|
|
1081
|
+
#
|
|
1082
|
+
# Also allows you to set the value by passing a value as a parameter
|
|
1083
|
+
#
|
|
1084
|
+
# Example:
|
|
1085
|
+
#
|
|
1086
|
+
# mail.smtp_envelope_to ['Mikel <mikel@test.lindsaar.net>', 'Lindsaar <lindsaar@test.lindsaar.net>']
|
|
1087
|
+
# mail.smtp_envelope_to #=> ['mikel@test.lindsaar.net', 'lindsaar@test.lindsaar.net']
|
|
1088
|
+
def smtp_envelope_to( val = nil )
|
|
1089
|
+
if val
|
|
1090
|
+
self.smtp_envelope_to = val
|
|
1091
|
+
else
|
|
1092
|
+
@smtp_envelope_to || destinations
|
|
1093
|
+
end
|
|
1094
|
+
end
|
|
1095
|
+
|
|
1096
|
+
# Sets the To addresses on the SMTP Envelope.
|
|
1097
|
+
#
|
|
1098
|
+
# Example:
|
|
1099
|
+
#
|
|
1100
|
+
# mail.smtp_envelope_to = 'Mikel <mikel@test.lindsaar.net>'
|
|
1101
|
+
# mail.smtp_envelope_to #=> 'mikel@test.lindsaar.net'
|
|
1102
|
+
#
|
|
1103
|
+
# mail.smtp_envelope_to = ['Mikel <mikel@test.lindsaar.net>', 'Lindsaar <lindsaar@test.lindsaar.net>']
|
|
1104
|
+
# mail.smtp_envelope_to #=> ['mikel@test.lindsaar.net', 'lindsaar@test.lindsaar.net']
|
|
1105
|
+
def smtp_envelope_to=( val )
|
|
1106
|
+
@smtp_envelope_to =
|
|
1107
|
+
case val
|
|
1108
|
+
when Array, NilClass
|
|
1109
|
+
val
|
|
1110
|
+
else
|
|
1111
|
+
[val]
|
|
1112
|
+
end
|
|
1113
|
+
end
|
|
1114
|
+
|
|
1026
1115
|
# Returns the decoded value of the subject field, as a single string.
|
|
1027
1116
|
#
|
|
1028
1117
|
# Example:
|
|
@@ -1309,7 +1398,7 @@ module Mail
|
|
|
1309
1398
|
header.has_date?
|
|
1310
1399
|
end
|
|
1311
1400
|
|
|
1312
|
-
# Returns true if the message has a
|
|
1401
|
+
# Returns true if the message has a Mime-Version field, the field may or may
|
|
1313
1402
|
# not have a value, but the field exists or not.
|
|
1314
1403
|
def has_mime_version?
|
|
1315
1404
|
header.has_mime_version?
|
|
@@ -1411,7 +1500,7 @@ module Mail
|
|
|
1411
1500
|
|
|
1412
1501
|
# Returns the MIME media type of part we are on, this is taken from the content-type header
|
|
1413
1502
|
def mime_type
|
|
1414
|
-
|
|
1503
|
+
has_content_type? ? header[:content_type].string : nil rescue nil
|
|
1415
1504
|
end
|
|
1416
1505
|
|
|
1417
1506
|
def message_content_type
|
|
@@ -1422,7 +1511,7 @@ module Mail
|
|
|
1422
1511
|
# Returns the character set defined in the content type field
|
|
1423
1512
|
def charset
|
|
1424
1513
|
if @header
|
|
1425
|
-
|
|
1514
|
+
has_content_type? ? content_type_parameters['charset'] : @charset
|
|
1426
1515
|
else
|
|
1427
1516
|
@charset
|
|
1428
1517
|
end
|
|
@@ -1515,8 +1604,8 @@ module Mail
|
|
|
1515
1604
|
end
|
|
1516
1605
|
|
|
1517
1606
|
# Returns an AttachmentsList object, which holds all of the attachments in
|
|
1518
|
-
# the receiver object (either the
|
|
1519
|
-
# of
|
|
1607
|
+
# the receiver object (either the entire email or a part within) and all
|
|
1608
|
+
# of its descendants.
|
|
1520
1609
|
#
|
|
1521
1610
|
# It also allows you to add attachments to the mail object directly, like so:
|
|
1522
1611
|
#
|
|
@@ -1559,9 +1648,7 @@ module Mail
|
|
|
1559
1648
|
# Accessor for html_part
|
|
1560
1649
|
def html_part(&block)
|
|
1561
1650
|
if block_given?
|
|
1562
|
-
|
|
1563
|
-
add_multipart_alternate_header unless html_part.blank?
|
|
1564
|
-
add_part(@html_part)
|
|
1651
|
+
self.html_part = Mail::Part.new(:content_type => 'text/html', &block)
|
|
1565
1652
|
else
|
|
1566
1653
|
@html_part || find_first_mime_type('text/html')
|
|
1567
1654
|
end
|
|
@@ -1570,9 +1657,7 @@ module Mail
|
|
|
1570
1657
|
# Accessor for text_part
|
|
1571
1658
|
def text_part(&block)
|
|
1572
1659
|
if block_given?
|
|
1573
|
-
|
|
1574
|
-
add_multipart_alternate_header unless html_part.blank?
|
|
1575
|
-
add_part(@text_part)
|
|
1660
|
+
self.text_part = Mail::Part.new(:content_type => 'text/plain', &block)
|
|
1576
1661
|
else
|
|
1577
1662
|
@text_part || find_first_mime_type('text/plain')
|
|
1578
1663
|
end
|
|
@@ -1581,36 +1666,54 @@ module Mail
|
|
|
1581
1666
|
# Helper to add a html part to a multipart/alternative email. If this and
|
|
1582
1667
|
# text_part are both defined in a message, then it will be a multipart/alternative
|
|
1583
1668
|
# message and set itself that way.
|
|
1584
|
-
def html_part=(msg
|
|
1669
|
+
def html_part=(msg)
|
|
1670
|
+
# Assign the html part and set multipart/alternative if there's a text part.
|
|
1585
1671
|
if msg
|
|
1586
1672
|
@html_part = msg
|
|
1587
|
-
|
|
1588
|
-
|
|
1673
|
+
@html_part.content_type = 'text/html' unless @html_part.has_content_type?
|
|
1674
|
+
add_multipart_alternate_header if text_part
|
|
1675
|
+
add_part @html_part
|
|
1676
|
+
|
|
1677
|
+
# If nil, delete the html part and back out of multipart/alternative.
|
|
1678
|
+
elsif @html_part
|
|
1679
|
+
parts.delete_if { |p| p.object_id == @html_part.object_id }
|
|
1680
|
+
@html_part = nil
|
|
1681
|
+
if text_part
|
|
1682
|
+
self.content_type = nil
|
|
1683
|
+
body.boundary = nil
|
|
1684
|
+
end
|
|
1589
1685
|
end
|
|
1590
|
-
add_multipart_alternate_header unless text_part.blank?
|
|
1591
|
-
add_part(@html_part)
|
|
1592
1686
|
end
|
|
1593
1687
|
|
|
1594
1688
|
# Helper to add a text part to a multipart/alternative email. If this and
|
|
1595
1689
|
# html_part are both defined in a message, then it will be a multipart/alternative
|
|
1596
1690
|
# message and set itself that way.
|
|
1597
|
-
def text_part=(msg
|
|
1691
|
+
def text_part=(msg)
|
|
1692
|
+
# Assign the text part and set multipart/alternative if there's an html part.
|
|
1598
1693
|
if msg
|
|
1599
1694
|
@text_part = msg
|
|
1600
|
-
|
|
1601
|
-
|
|
1695
|
+
@text_part.content_type = 'text/plain' unless @text_part.has_content_type?
|
|
1696
|
+
add_multipart_alternate_header if html_part
|
|
1697
|
+
add_part @text_part
|
|
1698
|
+
|
|
1699
|
+
# If nil, delete the text part and back out of multipart/alternative.
|
|
1700
|
+
elsif @text_part
|
|
1701
|
+
parts.delete_if { |p| p.object_id == @text_part.object_id }
|
|
1702
|
+
@text_part = nil
|
|
1703
|
+
if html_part
|
|
1704
|
+
self.content_type = nil
|
|
1705
|
+
body.boundary = nil
|
|
1706
|
+
end
|
|
1602
1707
|
end
|
|
1603
|
-
add_multipart_alternate_header unless html_part.blank?
|
|
1604
|
-
add_part(@text_part)
|
|
1605
1708
|
end
|
|
1606
1709
|
|
|
1607
1710
|
# Adds a part to the parts list or creates the part list
|
|
1608
1711
|
def add_part(part)
|
|
1609
1712
|
if !body.multipart? && !self.body.decoded.blank?
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1713
|
+
@text_part = Mail::Part.new('Content-Type: text/plain;')
|
|
1714
|
+
@text_part.body = body.decoded
|
|
1715
|
+
self.body << @text_part
|
|
1716
|
+
add_multipart_alternate_header
|
|
1614
1717
|
end
|
|
1615
1718
|
add_boundary
|
|
1616
1719
|
self.body << part
|
|
@@ -1646,7 +1749,7 @@ module Mail
|
|
|
1646
1749
|
# m.add_file(:filename => 'filename.png', :content => File.read('/path/to/file.jpg'))
|
|
1647
1750
|
#
|
|
1648
1751
|
# 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
|
|
1752
|
+
# to a MIME multipart email, moving whatever plain text body you had into its own text
|
|
1650
1753
|
# plain part.
|
|
1651
1754
|
#
|
|
1652
1755
|
# Example:
|
|
@@ -1683,7 +1786,7 @@ module Mail
|
|
|
1683
1786
|
self.body << text_part
|
|
1684
1787
|
end
|
|
1685
1788
|
|
|
1686
|
-
# Encodes the message, calls encode on all
|
|
1789
|
+
# Encodes the message, calls encode on all its parts, gets an email message
|
|
1687
1790
|
# ready to send
|
|
1688
1791
|
def ready_to_send!
|
|
1689
1792
|
identify_and_set_transfer_encoding
|
|
@@ -1864,6 +1967,8 @@ module Mail
|
|
|
1864
1967
|
|
|
1865
1968
|
private
|
|
1866
1969
|
|
|
1970
|
+
HEADER_SEPARATOR = /#{CRLF}#{CRLF}|#{CRLF}#{WSP}*#{CRLF}(?!#{WSP})/m
|
|
1971
|
+
|
|
1867
1972
|
# 2.1. General Description
|
|
1868
1973
|
# A message consists of header fields (collectively called "the header
|
|
1869
1974
|
# of the message") followed, optionally, by a body. The header is a
|
|
@@ -1875,15 +1980,13 @@ module Mail
|
|
|
1875
1980
|
# Additionally, I allow for the case where someone might have put whitespace
|
|
1876
1981
|
# on the "gap line"
|
|
1877
1982
|
def parse_message
|
|
1878
|
-
header_part, body_part = raw_source.split(
|
|
1879
|
-
# index = raw_source.index(/#{CRLF}#{WSP}*#{CRLF}/m, 2)
|
|
1880
|
-
# self.header = (index) ? header_part[0,index] : nil
|
|
1881
|
-
# lazy_body ( [raw_source, index+1])
|
|
1983
|
+
header_part, body_part = raw_source.lstrip.split(HEADER_SEPARATOR, 2)
|
|
1882
1984
|
self.header = header_part
|
|
1883
1985
|
self.body = body_part
|
|
1884
1986
|
end
|
|
1885
1987
|
|
|
1886
1988
|
def raw_source=(value)
|
|
1989
|
+
value = value.dup.force_encoding(Encoding::BINARY) if RUBY_VERSION >= "1.9.1"
|
|
1887
1990
|
@raw_source = value.to_crlf
|
|
1888
1991
|
end
|
|
1889
1992
|
|
|
@@ -1906,17 +2009,18 @@ module Mail
|
|
|
1906
2009
|
|
|
1907
2010
|
|
|
1908
2011
|
def process_body_raw
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
2012
|
+
@body = Mail::Body.new(@body_raw)
|
|
2013
|
+
@body_raw = nil
|
|
2014
|
+
separate_parts if @separate_parts
|
|
1912
2015
|
|
|
1913
|
-
|
|
2016
|
+
add_encoding_to_body
|
|
1914
2017
|
end
|
|
1915
2018
|
|
|
1916
2019
|
def set_envelope_header
|
|
1917
|
-
|
|
2020
|
+
raw_string = raw_source.to_s
|
|
2021
|
+
if match_data = raw_source.to_s.match(/\AFrom\s(#{TEXT}+)#{CRLF}/m)
|
|
1918
2022
|
set_envelope(match_data[1])
|
|
1919
|
-
self.raw_source = match_data[
|
|
2023
|
+
self.raw_source = raw_string.sub(match_data[0], "")
|
|
1920
2024
|
end
|
|
1921
2025
|
end
|
|
1922
2026
|
|
|
@@ -1939,16 +2043,19 @@ module Mail
|
|
|
1939
2043
|
end
|
|
1940
2044
|
|
|
1941
2045
|
def add_required_fields
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
add_message_id unless (has_message_id? || self.class == Mail::Part)
|
|
1945
|
-
add_date unless has_date?
|
|
1946
|
-
add_mime_version unless has_mime_version?
|
|
2046
|
+
add_required_message_fields
|
|
2047
|
+
add_multipart_mixed_header if body.multipart?
|
|
1947
2048
|
add_content_type unless has_content_type?
|
|
1948
2049
|
add_charset unless has_charset?
|
|
1949
2050
|
add_content_transfer_encoding unless has_content_transfer_encoding?
|
|
1950
2051
|
end
|
|
1951
2052
|
|
|
2053
|
+
def add_required_message_fields
|
|
2054
|
+
add_date unless has_date?
|
|
2055
|
+
add_mime_version unless has_mime_version?
|
|
2056
|
+
add_message_id unless has_message_id?
|
|
2057
|
+
end
|
|
2058
|
+
|
|
1952
2059
|
def add_multipart_alternate_header
|
|
1953
2060
|
header['content-type'] = ContentTypeField.with_boundary('multipart/alternative').value
|
|
1954
2061
|
header['content_type'].parameters[:charset] = @charset
|
|
@@ -2033,7 +2140,7 @@ module Mail
|
|
|
2033
2140
|
if perform_deliveries
|
|
2034
2141
|
delivery_method.deliver!(self)
|
|
2035
2142
|
end
|
|
2036
|
-
rescue
|
|
2143
|
+
rescue => e # Net::SMTP errors or sendmail pipe errors
|
|
2037
2144
|
raise e if raise_delivery_errors
|
|
2038
2145
|
end
|
|
2039
2146
|
end
|
|
@@ -2047,7 +2154,7 @@ module Mail
|
|
|
2047
2154
|
else
|
|
2048
2155
|
if encoding = Encoding.find(charset) rescue nil
|
|
2049
2156
|
body_text.force_encoding(encoding)
|
|
2050
|
-
return body_text.encode(Encoding::UTF_8)
|
|
2157
|
+
return body_text.encode(Encoding::UTF_8, :undef => :replace, :invalid => :replace, :replace => '')
|
|
2051
2158
|
end
|
|
2052
2159
|
end
|
|
2053
2160
|
end
|
data/lib/mail/multibyte/chars.rb
CHANGED
|
@@ -339,7 +339,7 @@ module Mail #:nodoc:
|
|
|
339
339
|
# Example:
|
|
340
340
|
# 'Laurent, où sont les tests ?'.mb_chars.upcase.to_s # => "LAURENT, OÙ SONT LES TESTS ?"
|
|
341
341
|
def upcase
|
|
342
|
-
chars(Unicode.apply_mapping(@wrapped_string
|
|
342
|
+
chars(Unicode.apply_mapping(@wrapped_string, :uppercase_mapping))
|
|
343
343
|
end
|
|
344
344
|
|
|
345
345
|
# Convert characters in the string to lowercase.
|
|
@@ -347,7 +347,7 @@ module Mail #:nodoc:
|
|
|
347
347
|
# Example:
|
|
348
348
|
# 'VĚDA A VÝZKUM'.mb_chars.downcase.to_s # => "věda a výzkum"
|
|
349
349
|
def downcase
|
|
350
|
-
chars(Unicode.apply_mapping(@wrapped_string
|
|
350
|
+
chars(Unicode.apply_mapping(@wrapped_string, :lowercase_mapping))
|
|
351
351
|
end
|
|
352
352
|
|
|
353
353
|
# Converts the first character to uppercase and the remainder to lowercase.
|
|
@@ -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
|
|
|
@@ -390,3 +390,11 @@ module Mail
|
|
|
390
390
|
end
|
|
391
391
|
end
|
|
392
392
|
end
|
|
393
|
+
|
|
394
|
+
unless defined?(ActiveSupport)
|
|
395
|
+
module ActiveSupport
|
|
396
|
+
unless const_defined?(:Multibyte)
|
|
397
|
+
Multibyte = Mail::Multibyte
|
|
398
|
+
end
|
|
399
|
+
end
|
|
400
|
+
end
|
|
@@ -36,14 +36,13 @@ module Mail
|
|
|
36
36
|
#
|
|
37
37
|
# mail.deliver!
|
|
38
38
|
class Exim < Sendmail
|
|
39
|
-
|
|
40
39
|
def initialize(values)
|
|
41
40
|
self.settings = { :location => '/usr/sbin/exim',
|
|
42
41
|
:arguments => '-i -t' }.merge(values)
|
|
43
42
|
end
|
|
44
43
|
|
|
45
|
-
def self.call(path, arguments, mail)
|
|
46
|
-
|
|
44
|
+
def self.call(path, arguments, destinations, mail)
|
|
45
|
+
popen "#{path} #{arguments}" do |io|
|
|
47
46
|
io.puts mail.encoded.to_lf
|
|
48
47
|
io.flush
|
|
49
48
|
end
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
require 'mail/check_delivery_params'
|
|
2
|
+
|
|
1
3
|
module Mail
|
|
2
4
|
|
|
3
5
|
# FileDelivery class delivers emails into multiple files based on the destination
|
|
@@ -11,6 +13,7 @@ module Mail
|
|
|
11
13
|
# Make sure the path you specify with :location is writable by the Ruby process
|
|
12
14
|
# running Mail.
|
|
13
15
|
class FileDelivery
|
|
16
|
+
include Mail::CheckDeliveryParams
|
|
14
17
|
|
|
15
18
|
if RUBY_VERSION >= '1.9.1'
|
|
16
19
|
require 'fileutils'
|
|
@@ -25,6 +28,8 @@ module Mail
|
|
|
25
28
|
attr_accessor :settings
|
|
26
29
|
|
|
27
30
|
def deliver!(mail)
|
|
31
|
+
check_delivery_params(mail)
|
|
32
|
+
|
|
28
33
|
if ::File.respond_to?(:makedirs)
|
|
29
34
|
::File.makedirs settings[:location]
|
|
30
35
|
else
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
require 'mail/check_delivery_params'
|
|
2
|
+
|
|
1
3
|
module Mail
|
|
2
4
|
# A delivery method implementation which sends via sendmail.
|
|
3
5
|
#
|
|
@@ -35,28 +37,53 @@ module Mail
|
|
|
35
37
|
#
|
|
36
38
|
# mail.deliver!
|
|
37
39
|
class Sendmail
|
|
40
|
+
include Mail::CheckDeliveryParams
|
|
38
41
|
|
|
39
42
|
def initialize(values)
|
|
40
43
|
self.settings = { :location => '/usr/sbin/sendmail',
|
|
41
|
-
:arguments => '-i
|
|
44
|
+
:arguments => '-i' }.merge(values)
|
|
42
45
|
end
|
|
43
46
|
|
|
44
47
|
attr_accessor :settings
|
|
45
48
|
|
|
46
49
|
def deliver!(mail)
|
|
47
|
-
|
|
48
|
-
return_path = "-f " + '"' + envelope_from.escape_for_shell + '"' if envelope_from
|
|
50
|
+
smtp_from, smtp_to, message = check_delivery_params(mail)
|
|
49
51
|
|
|
50
|
-
|
|
52
|
+
from = "-f #{self.class.shellquote(smtp_from)}"
|
|
53
|
+
to = smtp_to.map { |_to| self.class.shellquote(_to) }.join(' ')
|
|
51
54
|
|
|
52
|
-
|
|
55
|
+
arguments = "#{settings[:arguments]} #{from} --"
|
|
56
|
+
self.class.call(settings[:location], arguments, to, message)
|
|
53
57
|
end
|
|
54
58
|
|
|
55
|
-
def self.call(path, arguments, destinations,
|
|
56
|
-
|
|
57
|
-
io.puts
|
|
59
|
+
def self.call(path, arguments, destinations, encoded_message)
|
|
60
|
+
popen "#{path} #{arguments} #{destinations}" do |io|
|
|
61
|
+
io.puts encoded_message.to_lf
|
|
58
62
|
io.flush
|
|
59
63
|
end
|
|
60
64
|
end
|
|
65
|
+
|
|
66
|
+
if RUBY_VERSION < '1.9.0'
|
|
67
|
+
def self.popen(command, &block)
|
|
68
|
+
IO.popen "#{command} 2>&1", 'w+', &block
|
|
69
|
+
end
|
|
70
|
+
else
|
|
71
|
+
def self.popen(command, &block)
|
|
72
|
+
IO.popen command, 'w+', :err => :out, &block
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# The following is an adaptation of ruby 1.9.2's shellwords.rb file,
|
|
77
|
+
# it is modified to include '+' in the allowed list to allow for
|
|
78
|
+
# sendmail to accept email addresses as the sender with a + in them.
|
|
79
|
+
def self.shellquote(address)
|
|
80
|
+
# Process as a single byte sequence because not all shell
|
|
81
|
+
# implementations are multibyte aware.
|
|
82
|
+
#
|
|
83
|
+
# A LF cannot be escaped with a backslash because a backslash + LF
|
|
84
|
+
# combo is regarded as line continuation and simply ignored. Strip it.
|
|
85
|
+
escaped = address.gsub(/([^A-Za-z0-9_\s\+\-.,:\/@])/n, "\\\\\\1").gsub("\n", '')
|
|
86
|
+
%("#{escaped}")
|
|
87
|
+
end
|
|
61
88
|
end
|
|
62
89
|
end
|