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
data/lib/mail/message.rb
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
# encoding: utf-8
|
|
2
|
+
# frozen_string_literal: true
|
|
2
3
|
require "yaml"
|
|
3
4
|
|
|
4
5
|
module Mail
|
|
@@ -46,7 +47,7 @@ module Mail
|
|
|
46
47
|
# (i.e., a line with nothing preceding the CRLF).
|
|
47
48
|
class Message
|
|
48
49
|
|
|
49
|
-
include
|
|
50
|
+
include Constants
|
|
50
51
|
include Utilities
|
|
51
52
|
|
|
52
53
|
# ==Making an email
|
|
@@ -105,9 +106,12 @@ module Mail
|
|
|
105
106
|
@html_part = nil
|
|
106
107
|
@errors = nil
|
|
107
108
|
@header = nil
|
|
108
|
-
@charset =
|
|
109
|
+
@charset = self.class.default_charset
|
|
109
110
|
@defaulted_charset = true
|
|
110
111
|
|
|
112
|
+
@smtp_envelope_from = nil
|
|
113
|
+
@smtp_envelope_to = nil
|
|
114
|
+
|
|
111
115
|
@perform_deliveries = true
|
|
112
116
|
@raise_delivery_errors = true
|
|
113
117
|
|
|
@@ -122,7 +126,7 @@ module Mail
|
|
|
122
126
|
if args.flatten.first.respond_to?(:each_pair)
|
|
123
127
|
init_with_hash(args.flatten.first)
|
|
124
128
|
else
|
|
125
|
-
init_with_string(args.flatten[0].to_s
|
|
129
|
+
init_with_string(args.flatten[0].to_s)
|
|
126
130
|
end
|
|
127
131
|
|
|
128
132
|
if block_given?
|
|
@@ -169,7 +173,7 @@ module Mail
|
|
|
169
173
|
# obj.mail.deliver
|
|
170
174
|
#
|
|
171
175
|
# Would cause Mail to call obj.deliver_mail passing itself as a parameter,
|
|
172
|
-
# which then can just yield and let Mail do
|
|
176
|
+
# which then can just yield and let Mail do its own private do_delivery
|
|
173
177
|
# method.
|
|
174
178
|
attr_accessor :delivery_handler
|
|
175
179
|
|
|
@@ -204,6 +208,10 @@ module Mail
|
|
|
204
208
|
# define a delivery_handler
|
|
205
209
|
attr_accessor :raise_delivery_errors
|
|
206
210
|
|
|
211
|
+
def self.default_charset; @@default_charset; end
|
|
212
|
+
def self.default_charset=(charset); @@default_charset = charset; end
|
|
213
|
+
self.default_charset = 'UTF-8'
|
|
214
|
+
|
|
207
215
|
def register_for_delivery_notification(observer)
|
|
208
216
|
STDERR.puts("Message#register_for_delivery_notification is deprecated, please call Mail.register_observer instead")
|
|
209
217
|
Mail.register_observer(observer)
|
|
@@ -237,7 +245,7 @@ module Mail
|
|
|
237
245
|
# This method bypasses checking perform_deliveries and raise_delivery_errors,
|
|
238
246
|
# so use with caution.
|
|
239
247
|
#
|
|
240
|
-
# It still however fires off the
|
|
248
|
+
# It still however fires off the interceptors and calls the observers callbacks if they are defined.
|
|
241
249
|
#
|
|
242
250
|
# Returns self
|
|
243
251
|
def deliver!
|
|
@@ -350,17 +358,23 @@ module Mail
|
|
|
350
358
|
return false unless other.respond_to?(:encoded)
|
|
351
359
|
|
|
352
360
|
if self.message_id && other.message_id
|
|
353
|
-
|
|
361
|
+
self.encoded == other.encoded
|
|
354
362
|
else
|
|
355
363
|
self_message_id, other_message_id = self.message_id, other.message_id
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
364
|
+
begin
|
|
365
|
+
self.message_id, other.message_id = '<temp@test>', '<temp@test>'
|
|
366
|
+
self.encoded == other.encoded
|
|
367
|
+
ensure
|
|
368
|
+
self.message_id, other.message_id = self_message_id, other_message_id
|
|
369
|
+
end
|
|
361
370
|
end
|
|
362
371
|
end
|
|
363
372
|
|
|
373
|
+
def initialize_copy(original)
|
|
374
|
+
super
|
|
375
|
+
@header = @header.dup
|
|
376
|
+
end
|
|
377
|
+
|
|
364
378
|
# Provides access to the raw source of the message as it was when it
|
|
365
379
|
# was instantiated. This is set at initialization and so is untouched
|
|
366
380
|
# by the parsers or decoder / encoders
|
|
@@ -938,8 +952,8 @@ module Mail
|
|
|
938
952
|
#
|
|
939
953
|
# Example:
|
|
940
954
|
#
|
|
941
|
-
# mail.
|
|
942
|
-
# mail.
|
|
955
|
+
# mail.resent_sender = 'Mikel <mikel@test.lindsaar.net>'
|
|
956
|
+
# mail.resent_sender #=> 'mikel@test.lindsaar.net'
|
|
943
957
|
def resent_sender=( val )
|
|
944
958
|
header[:resent_sender] = val
|
|
945
959
|
end
|
|
@@ -1023,6 +1037,82 @@ module Mail
|
|
|
1023
1037
|
header[:sender] = val
|
|
1024
1038
|
end
|
|
1025
1039
|
|
|
1040
|
+
# Returns the SMTP Envelope From value of the mail object, as a single
|
|
1041
|
+
# string of an address spec.
|
|
1042
|
+
#
|
|
1043
|
+
# Defaults to Return-Path, Sender, or the first From address.
|
|
1044
|
+
#
|
|
1045
|
+
# Example:
|
|
1046
|
+
#
|
|
1047
|
+
# mail.smtp_envelope_from = 'Mikel <mikel@test.lindsaar.net>'
|
|
1048
|
+
# mail.smtp_envelope_from #=> 'mikel@test.lindsaar.net'
|
|
1049
|
+
#
|
|
1050
|
+
# Also allows you to set the value by passing a value as a parameter
|
|
1051
|
+
#
|
|
1052
|
+
# Example:
|
|
1053
|
+
#
|
|
1054
|
+
# mail.smtp_envelope_from 'Mikel <mikel@test.lindsaar.net>'
|
|
1055
|
+
# mail.smtp_envelope_from #=> 'mikel@test.lindsaar.net'
|
|
1056
|
+
def smtp_envelope_from( val = nil )
|
|
1057
|
+
if val
|
|
1058
|
+
self.smtp_envelope_from = val
|
|
1059
|
+
else
|
|
1060
|
+
@smtp_envelope_from || return_path || sender || from_addrs.first
|
|
1061
|
+
end
|
|
1062
|
+
end
|
|
1063
|
+
|
|
1064
|
+
# Sets the From address on the SMTP Envelope.
|
|
1065
|
+
#
|
|
1066
|
+
# Example:
|
|
1067
|
+
#
|
|
1068
|
+
# mail.smtp_envelope_from = 'Mikel <mikel@test.lindsaar.net>'
|
|
1069
|
+
# mail.smtp_envelope_from #=> 'mikel@test.lindsaar.net'
|
|
1070
|
+
def smtp_envelope_from=( val )
|
|
1071
|
+
@smtp_envelope_from = val
|
|
1072
|
+
end
|
|
1073
|
+
|
|
1074
|
+
# Returns the SMTP Envelope To value of the mail object.
|
|
1075
|
+
#
|
|
1076
|
+
# Defaults to #destinations: To, Cc, and Bcc addresses.
|
|
1077
|
+
#
|
|
1078
|
+
# Example:
|
|
1079
|
+
#
|
|
1080
|
+
# mail.smtp_envelope_to = 'Mikel <mikel@test.lindsaar.net>'
|
|
1081
|
+
# mail.smtp_envelope_to #=> 'mikel@test.lindsaar.net'
|
|
1082
|
+
#
|
|
1083
|
+
# Also allows you to set the value by passing a value as a parameter
|
|
1084
|
+
#
|
|
1085
|
+
# Example:
|
|
1086
|
+
#
|
|
1087
|
+
# mail.smtp_envelope_to ['Mikel <mikel@test.lindsaar.net>', 'Lindsaar <lindsaar@test.lindsaar.net>']
|
|
1088
|
+
# mail.smtp_envelope_to #=> ['mikel@test.lindsaar.net', 'lindsaar@test.lindsaar.net']
|
|
1089
|
+
def smtp_envelope_to( val = nil )
|
|
1090
|
+
if val
|
|
1091
|
+
self.smtp_envelope_to = val
|
|
1092
|
+
else
|
|
1093
|
+
@smtp_envelope_to || destinations
|
|
1094
|
+
end
|
|
1095
|
+
end
|
|
1096
|
+
|
|
1097
|
+
# Sets the To addresses on the SMTP Envelope.
|
|
1098
|
+
#
|
|
1099
|
+
# Example:
|
|
1100
|
+
#
|
|
1101
|
+
# mail.smtp_envelope_to = 'Mikel <mikel@test.lindsaar.net>'
|
|
1102
|
+
# mail.smtp_envelope_to #=> 'mikel@test.lindsaar.net'
|
|
1103
|
+
#
|
|
1104
|
+
# mail.smtp_envelope_to = ['Mikel <mikel@test.lindsaar.net>', 'Lindsaar <lindsaar@test.lindsaar.net>']
|
|
1105
|
+
# mail.smtp_envelope_to #=> ['mikel@test.lindsaar.net', 'lindsaar@test.lindsaar.net']
|
|
1106
|
+
def smtp_envelope_to=( val )
|
|
1107
|
+
@smtp_envelope_to =
|
|
1108
|
+
case val
|
|
1109
|
+
when Array, NilClass
|
|
1110
|
+
val
|
|
1111
|
+
else
|
|
1112
|
+
[val]
|
|
1113
|
+
end
|
|
1114
|
+
end
|
|
1115
|
+
|
|
1026
1116
|
# Returns the decoded value of the subject field, as a single string.
|
|
1027
1117
|
#
|
|
1028
1118
|
# Example:
|
|
@@ -1309,7 +1399,7 @@ module Mail
|
|
|
1309
1399
|
header.has_date?
|
|
1310
1400
|
end
|
|
1311
1401
|
|
|
1312
|
-
# Returns true if the message has a
|
|
1402
|
+
# Returns true if the message has a Mime-Version field, the field may or may
|
|
1313
1403
|
# not have a value, but the field exists or not.
|
|
1314
1404
|
def has_mime_version?
|
|
1315
1405
|
header.has_mime_version?
|
|
@@ -1326,7 +1416,7 @@ module Mail
|
|
|
1326
1416
|
end
|
|
1327
1417
|
|
|
1328
1418
|
def has_content_transfer_encoding?
|
|
1329
|
-
header[:content_transfer_encoding] && header[:content_transfer_encoding].errors
|
|
1419
|
+
header[:content_transfer_encoding] && Utilities.blank?(header[:content_transfer_encoding].errors)
|
|
1330
1420
|
end
|
|
1331
1421
|
|
|
1332
1422
|
def has_transfer_encoding? # :nodoc:
|
|
@@ -1515,8 +1605,8 @@ module Mail
|
|
|
1515
1605
|
end
|
|
1516
1606
|
|
|
1517
1607
|
# Returns an AttachmentsList object, which holds all of the attachments in
|
|
1518
|
-
# the receiver object (either the
|
|
1519
|
-
# of
|
|
1608
|
+
# the receiver object (either the entire email or a part within) and all
|
|
1609
|
+
# of its descendants.
|
|
1520
1610
|
#
|
|
1521
1611
|
# It also allows you to add attachments to the mail object directly, like so:
|
|
1522
1612
|
#
|
|
@@ -1559,9 +1649,7 @@ module Mail
|
|
|
1559
1649
|
# Accessor for html_part
|
|
1560
1650
|
def html_part(&block)
|
|
1561
1651
|
if block_given?
|
|
1562
|
-
|
|
1563
|
-
add_multipart_alternate_header unless html_part.blank?
|
|
1564
|
-
add_part(@html_part)
|
|
1652
|
+
self.html_part = Mail::Part.new(:content_type => 'text/html', &block)
|
|
1565
1653
|
else
|
|
1566
1654
|
@html_part || find_first_mime_type('text/html')
|
|
1567
1655
|
end
|
|
@@ -1570,9 +1658,7 @@ module Mail
|
|
|
1570
1658
|
# Accessor for text_part
|
|
1571
1659
|
def text_part(&block)
|
|
1572
1660
|
if block_given?
|
|
1573
|
-
|
|
1574
|
-
add_multipart_alternate_header unless html_part.blank?
|
|
1575
|
-
add_part(@text_part)
|
|
1661
|
+
self.text_part = Mail::Part.new(:content_type => 'text/plain', &block)
|
|
1576
1662
|
else
|
|
1577
1663
|
@text_part || find_first_mime_type('text/plain')
|
|
1578
1664
|
end
|
|
@@ -1581,36 +1667,58 @@ module Mail
|
|
|
1581
1667
|
# Helper to add a html part to a multipart/alternative email. If this and
|
|
1582
1668
|
# text_part are both defined in a message, then it will be a multipart/alternative
|
|
1583
1669
|
# message and set itself that way.
|
|
1584
|
-
def html_part=(msg
|
|
1670
|
+
def html_part=(msg)
|
|
1671
|
+
# Assign the html part and set multipart/alternative if there's a text part.
|
|
1585
1672
|
if msg
|
|
1673
|
+
msg = Mail::Part.new(:body => msg) unless msg.kind_of?(Mail::Message)
|
|
1674
|
+
|
|
1586
1675
|
@html_part = msg
|
|
1587
|
-
|
|
1588
|
-
|
|
1676
|
+
@html_part.content_type = 'text/html' unless @html_part.has_content_type?
|
|
1677
|
+
add_multipart_alternate_header if text_part
|
|
1678
|
+
add_part @html_part
|
|
1679
|
+
|
|
1680
|
+
# If nil, delete the html part and back out of multipart/alternative.
|
|
1681
|
+
elsif @html_part
|
|
1682
|
+
parts.delete_if { |p| p.object_id == @html_part.object_id }
|
|
1683
|
+
@html_part = nil
|
|
1684
|
+
if text_part
|
|
1685
|
+
self.content_type = nil
|
|
1686
|
+
body.boundary = nil
|
|
1687
|
+
end
|
|
1589
1688
|
end
|
|
1590
|
-
add_multipart_alternate_header unless text_part.blank?
|
|
1591
|
-
add_part(@html_part)
|
|
1592
1689
|
end
|
|
1593
1690
|
|
|
1594
1691
|
# Helper to add a text part to a multipart/alternative email. If this and
|
|
1595
1692
|
# html_part are both defined in a message, then it will be a multipart/alternative
|
|
1596
1693
|
# message and set itself that way.
|
|
1597
|
-
def text_part=(msg
|
|
1694
|
+
def text_part=(msg)
|
|
1695
|
+
# Assign the text part and set multipart/alternative if there's an html part.
|
|
1598
1696
|
if msg
|
|
1697
|
+
msg = Mail::Part.new(:body => msg) unless msg.kind_of?(Mail::Message)
|
|
1698
|
+
|
|
1599
1699
|
@text_part = msg
|
|
1600
|
-
|
|
1601
|
-
|
|
1700
|
+
@text_part.content_type = 'text/plain' unless @text_part.has_content_type?
|
|
1701
|
+
add_multipart_alternate_header if html_part
|
|
1702
|
+
add_part @text_part
|
|
1703
|
+
|
|
1704
|
+
# If nil, delete the text part and back out of multipart/alternative.
|
|
1705
|
+
elsif @text_part
|
|
1706
|
+
parts.delete_if { |p| p.object_id == @text_part.object_id }
|
|
1707
|
+
@text_part = nil
|
|
1708
|
+
if html_part
|
|
1709
|
+
self.content_type = nil
|
|
1710
|
+
body.boundary = nil
|
|
1711
|
+
end
|
|
1602
1712
|
end
|
|
1603
|
-
add_multipart_alternate_header unless html_part.blank?
|
|
1604
|
-
add_part(@text_part)
|
|
1605
1713
|
end
|
|
1606
1714
|
|
|
1607
1715
|
# Adds a part to the parts list or creates the part list
|
|
1608
1716
|
def add_part(part)
|
|
1609
|
-
if !body.multipart? && !self.body.decoded
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1717
|
+
if !body.multipart? && !Utilities.blank?(self.body.decoded)
|
|
1718
|
+
@text_part = Mail::Part.new('Content-Type: text/plain;')
|
|
1719
|
+
@text_part.body = body.decoded
|
|
1720
|
+
self.body << @text_part
|
|
1721
|
+
add_multipart_alternate_header
|
|
1614
1722
|
end
|
|
1615
1723
|
add_boundary
|
|
1616
1724
|
self.body << part
|
|
@@ -1646,7 +1754,7 @@ module Mail
|
|
|
1646
1754
|
# m.add_file(:filename => 'filename.png', :content => File.read('/path/to/file.jpg'))
|
|
1647
1755
|
#
|
|
1648
1756
|
# 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
|
|
1757
|
+
# to a MIME multipart email, moving whatever plain text body you had into its own text
|
|
1650
1758
|
# plain part.
|
|
1651
1759
|
#
|
|
1652
1760
|
# Example:
|
|
@@ -1662,14 +1770,17 @@ module Mail
|
|
|
1662
1770
|
#
|
|
1663
1771
|
# See also #attachments
|
|
1664
1772
|
def add_file(values)
|
|
1665
|
-
convert_to_multipart unless self.multipart? || self.body.decoded
|
|
1773
|
+
convert_to_multipart unless self.multipart? || Utilities.blank?(self.body.decoded)
|
|
1666
1774
|
add_multipart_mixed_header
|
|
1667
1775
|
if values.is_a?(String)
|
|
1668
1776
|
basename = File.basename(values)
|
|
1669
1777
|
filedata = File.open(values, 'rb') { |f| f.read }
|
|
1670
1778
|
else
|
|
1671
1779
|
basename = values[:filename]
|
|
1672
|
-
filedata = values
|
|
1780
|
+
filedata = values
|
|
1781
|
+
unless filedata[:content]
|
|
1782
|
+
filedata = values.merge(:content=>File.open(values[:filename], 'rb') { |f| f.read })
|
|
1783
|
+
end
|
|
1673
1784
|
end
|
|
1674
1785
|
self.attachments[basename] = filedata
|
|
1675
1786
|
end
|
|
@@ -1683,7 +1794,7 @@ module Mail
|
|
|
1683
1794
|
self.body << text_part
|
|
1684
1795
|
end
|
|
1685
1796
|
|
|
1686
|
-
# Encodes the message, calls encode on all
|
|
1797
|
+
# Encodes the message, calls encode on all its parts, gets an email message
|
|
1687
1798
|
# ready to send
|
|
1688
1799
|
def ready_to_send!
|
|
1689
1800
|
identify_and_set_transfer_encoding
|
|
@@ -1754,7 +1865,7 @@ module Mail
|
|
|
1754
1865
|
case
|
|
1755
1866
|
when k == 'delivery_handler'
|
|
1756
1867
|
begin
|
|
1757
|
-
m.delivery_handler = Object.const_get(v) unless
|
|
1868
|
+
m.delivery_handler = Object.const_get(v) unless Utilities.blank?(v)
|
|
1758
1869
|
rescue NameError
|
|
1759
1870
|
end
|
|
1760
1871
|
when k == 'transport_encoding'
|
|
@@ -1864,6 +1975,8 @@ module Mail
|
|
|
1864
1975
|
|
|
1865
1976
|
private
|
|
1866
1977
|
|
|
1978
|
+
HEADER_SEPARATOR = /#{CRLF}#{CRLF}|#{CRLF}#{WSP}*#{CRLF}(?!#{WSP})/m
|
|
1979
|
+
|
|
1867
1980
|
# 2.1. General Description
|
|
1868
1981
|
# A message consists of header fields (collectively called "the header
|
|
1869
1982
|
# of the message") followed, optionally, by a body. The header is a
|
|
@@ -1875,14 +1988,14 @@ module Mail
|
|
|
1875
1988
|
# Additionally, I allow for the case where someone might have put whitespace
|
|
1876
1989
|
# on the "gap line"
|
|
1877
1990
|
def parse_message
|
|
1878
|
-
header_part, body_part = raw_source.split(
|
|
1991
|
+
header_part, body_part = raw_source.lstrip.split(HEADER_SEPARATOR, 2)
|
|
1879
1992
|
self.header = header_part
|
|
1880
1993
|
self.body = body_part
|
|
1881
1994
|
end
|
|
1882
1995
|
|
|
1883
1996
|
def raw_source=(value)
|
|
1884
|
-
value.force_encoding(
|
|
1885
|
-
@raw_source =
|
|
1997
|
+
value = value.dup.force_encoding(Encoding::BINARY) if RUBY_VERSION >= "1.9.1"
|
|
1998
|
+
@raw_source = ::Mail::Utilities.to_crlf(value)
|
|
1886
1999
|
end
|
|
1887
2000
|
|
|
1888
2001
|
# see comments to body=. We take data and process it lazily
|
|
@@ -1904,18 +2017,18 @@ module Mail
|
|
|
1904
2017
|
|
|
1905
2018
|
|
|
1906
2019
|
def process_body_raw
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
2020
|
+
@body = Mail::Body.new(@body_raw)
|
|
2021
|
+
@body_raw = nil
|
|
2022
|
+
separate_parts if @separate_parts
|
|
1910
2023
|
|
|
1911
|
-
|
|
2024
|
+
add_encoding_to_body
|
|
1912
2025
|
end
|
|
1913
2026
|
|
|
1914
2027
|
def set_envelope_header
|
|
1915
2028
|
raw_string = raw_source.to_s
|
|
1916
2029
|
if match_data = raw_source.to_s.match(/\AFrom\s(#{TEXT}+)#{CRLF}/m)
|
|
1917
2030
|
set_envelope(match_data[1])
|
|
1918
|
-
self.raw_source = raw_string.sub(match_data[0], "")
|
|
2031
|
+
self.raw_source = raw_string.sub(match_data[0], "")
|
|
1919
2032
|
end
|
|
1920
2033
|
end
|
|
1921
2034
|
|
|
@@ -1938,16 +2051,19 @@ module Mail
|
|
|
1938
2051
|
end
|
|
1939
2052
|
|
|
1940
2053
|
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?
|
|
2054
|
+
add_required_message_fields
|
|
2055
|
+
add_multipart_mixed_header if body.multipart?
|
|
1946
2056
|
add_content_type unless has_content_type?
|
|
1947
|
-
add_charset
|
|
2057
|
+
add_charset if text? && !has_charset?
|
|
1948
2058
|
add_content_transfer_encoding unless has_content_transfer_encoding?
|
|
1949
2059
|
end
|
|
1950
2060
|
|
|
2061
|
+
def add_required_message_fields
|
|
2062
|
+
add_date unless has_date?
|
|
2063
|
+
add_mime_version unless has_mime_version?
|
|
2064
|
+
add_message_id unless has_message_id?
|
|
2065
|
+
end
|
|
2066
|
+
|
|
1951
2067
|
def add_multipart_alternate_header
|
|
1952
2068
|
header['content-type'] = ContentTypeField.with_boundary('multipart/alternative').value
|
|
1953
2069
|
header['content_type'].parameters[:charset] = @charset
|
|
@@ -2032,26 +2148,13 @@ module Mail
|
|
|
2032
2148
|
if perform_deliveries
|
|
2033
2149
|
delivery_method.deliver!(self)
|
|
2034
2150
|
end
|
|
2035
|
-
rescue
|
|
2151
|
+
rescue => e # Net::SMTP errors or sendmail pipe errors
|
|
2036
2152
|
raise e if raise_delivery_errors
|
|
2037
2153
|
end
|
|
2038
2154
|
end
|
|
2039
2155
|
|
|
2040
2156
|
def decode_body_as_text
|
|
2041
|
-
|
|
2042
|
-
if charset
|
|
2043
|
-
if RUBY_VERSION < '1.9'
|
|
2044
|
-
require 'iconv'
|
|
2045
|
-
return Iconv.conv("UTF-8//TRANSLIT//IGNORE", charset, body_text)
|
|
2046
|
-
else
|
|
2047
|
-
if encoding = Encoding.find(charset) rescue nil
|
|
2048
|
-
body_text.force_encoding(encoding)
|
|
2049
|
-
return body_text.encode(Encoding::UTF_8, :undef => :replace, :invalid => :replace, :replace => '')
|
|
2050
|
-
end
|
|
2051
|
-
end
|
|
2052
|
-
end
|
|
2053
|
-
body_text
|
|
2157
|
+
Encodings.transcode_charset decode_body, charset, 'UTF-8'
|
|
2054
2158
|
end
|
|
2055
|
-
|
|
2056
2159
|
end
|
|
2057
2160
|
end
|
data/lib/mail/multibyte/chars.rb
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
# encoding: utf-8
|
|
2
|
+
# frozen_string_literal: true
|
|
2
3
|
|
|
3
4
|
module Mail #:nodoc:
|
|
4
5
|
module Multibyte #:nodoc:
|
|
@@ -364,7 +365,7 @@ module Mail #:nodoc:
|
|
|
364
365
|
# "ÉL QUE SE ENTERÓ".mb_chars.titleize # => "Él Que Se Enteró"
|
|
365
366
|
# "日本語".mb_chars.titleize # => "日本語"
|
|
366
367
|
def titleize
|
|
367
|
-
chars(downcase.to_s.gsub(/\b('
|
|
368
|
+
chars(downcase.to_s.gsub(/\b('?\S)/u) { Unicode.apply_mapping $1, :uppercase_mapping })
|
|
368
369
|
end
|
|
369
370
|
alias_method :titlecase, :titleize
|
|
370
371
|
|
|
@@ -412,7 +413,7 @@ module Mail #:nodoc:
|
|
|
412
413
|
chars(Unicode.tidy_bytes(@wrapped_string, force))
|
|
413
414
|
end
|
|
414
415
|
|
|
415
|
-
|
|
416
|
+
%w(capitalize downcase lstrip reverse rstrip slice strip tidy_bytes upcase).each do |method|
|
|
416
417
|
# Only define a corresponding bang method for methods defined in the proxy; On 1.9 the proxy will
|
|
417
418
|
# exclude lstrip!, rstrip! and strip! because they are already work as expected on multibyte strings.
|
|
418
419
|
if public_method_defined?(method)
|
|
@@ -1,6 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
1
2
|
module Mail
|
|
2
3
|
module Multibyte
|
|
3
4
|
module Unicode
|
|
5
|
+
# Adapted from https://github.com/rails/rails/blob/master/activesupport/lib/active_support/multibyte/unicode.rb
|
|
6
|
+
# under the MIT license
|
|
7
|
+
# The Unicode version that is supported by the implementation
|
|
8
|
+
UNICODE_VERSION = '7.0.0'
|
|
9
|
+
|
|
10
|
+
# Holds data about a codepoint in the Unicode database.
|
|
11
|
+
class Codepoint
|
|
12
|
+
attr_accessor :code, :combining_class, :decomp_type, :decomp_mapping, :uppercase_mapping, :lowercase_mapping
|
|
13
|
+
|
|
14
|
+
# Initializing Codepoint object with default values
|
|
15
|
+
def initialize
|
|
16
|
+
@combining_class = 0
|
|
17
|
+
@uppercase_mapping = 0
|
|
18
|
+
@lowercase_mapping = 0
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def swapcase_mapping
|
|
22
|
+
uppercase_mapping > 0 ? uppercase_mapping : lowercase_mapping
|
|
23
|
+
end
|
|
24
|
+
end
|
|
4
25
|
|
|
5
26
|
extend self
|
|
6
27
|
|
|
@@ -8,9 +29,6 @@ module Mail
|
|
|
8
29
|
# information about normalization.
|
|
9
30
|
NORMALIZATION_FORMS = [:c, :kc, :d, :kd]
|
|
10
31
|
|
|
11
|
-
# The Unicode version that is supported by the implementation
|
|
12
|
-
UNICODE_VERSION = '5.2.0'
|
|
13
|
-
|
|
14
32
|
# The default normalization used for operations that require normalization. It can be set to any of the
|
|
15
33
|
# normalizations in NORMALIZATION_FORMS.
|
|
16
34
|
#
|
|
@@ -308,11 +326,6 @@ module Mail
|
|
|
308
326
|
end.pack('U*')
|
|
309
327
|
end
|
|
310
328
|
|
|
311
|
-
# Holds data about a codepoint in the Unicode database
|
|
312
|
-
class Codepoint
|
|
313
|
-
attr_accessor :code, :combining_class, :decomp_type, :decomp_mapping, :uppercase_mapping, :lowercase_mapping
|
|
314
|
-
end
|
|
315
|
-
|
|
316
329
|
# Holds static data from the Unicode database
|
|
317
330
|
class UnicodeDatabase
|
|
318
331
|
ATTRIBUTES = :codepoints, :composition_exclusion, :composition_map, :boundary, :cp1252
|
|
@@ -341,7 +354,7 @@ module Mail
|
|
|
341
354
|
def load
|
|
342
355
|
begin
|
|
343
356
|
@codepoints, @composition_exclusion, @composition_map, @boundary, @cp1252 = File.open(self.class.filename, 'rb') { |f| Marshal.load f.read }
|
|
344
|
-
rescue
|
|
357
|
+
rescue => e
|
|
345
358
|
raise IOError.new("Couldn't load the Unicode tables for UTF8Handler (#{e.message}), Mail::Multibyte is unusable")
|
|
346
359
|
end
|
|
347
360
|
|
|
@@ -390,9 +403,3 @@ module Mail
|
|
|
390
403
|
end
|
|
391
404
|
end
|
|
392
405
|
end
|
|
393
|
-
|
|
394
|
-
module ActiveSupport
|
|
395
|
-
unless const_defined?(:Multibyte)
|
|
396
|
-
Multibyte = Mail::Multibyte
|
|
397
|
-
end
|
|
398
|
-
end
|
data/lib/mail/multibyte/utils.rb
CHANGED
data/lib/mail/multibyte.rb
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
3
2
|
module Mail
|
|
4
3
|
|
|
5
4
|
# A delivery method implementation which sends via exim.
|
|
@@ -38,17 +37,14 @@ module Mail
|
|
|
38
37
|
#
|
|
39
38
|
# mail.deliver!
|
|
40
39
|
class Exim < Sendmail
|
|
41
|
-
include Mail::CheckDeliveryParams
|
|
42
|
-
|
|
43
40
|
def initialize(values)
|
|
44
41
|
self.settings = { :location => '/usr/sbin/exim',
|
|
45
42
|
:arguments => '-i -t' }.merge(values)
|
|
46
43
|
end
|
|
47
44
|
|
|
48
45
|
def self.call(path, arguments, destinations, mail)
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
io.puts mail.encoded.to_lf
|
|
46
|
+
popen "#{path} #{arguments}" do |io|
|
|
47
|
+
io.puts ::Mail::Utilities.to_lf(mail.encoded)
|
|
52
48
|
io.flush
|
|
53
49
|
end
|
|
54
50
|
end
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
1
2
|
require 'mail/check_delivery_params'
|
|
2
3
|
|
|
3
4
|
module Mail
|
|
@@ -28,7 +29,7 @@ module Mail
|
|
|
28
29
|
attr_accessor :settings
|
|
29
30
|
|
|
30
31
|
def deliver!(mail)
|
|
31
|
-
|
|
32
|
+
check_delivery_params(mail)
|
|
32
33
|
|
|
33
34
|
if ::File.respond_to?(:makedirs)
|
|
34
35
|
::File.makedirs settings[:location]
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
1
2
|
require 'mail/check_delivery_params'
|
|
2
3
|
|
|
3
4
|
module Mail
|
|
@@ -41,27 +42,49 @@ module Mail
|
|
|
41
42
|
|
|
42
43
|
def initialize(values)
|
|
43
44
|
self.settings = { :location => '/usr/sbin/sendmail',
|
|
44
|
-
:arguments => '-i
|
|
45
|
+
:arguments => '-i' }.merge(values)
|
|
45
46
|
end
|
|
46
47
|
|
|
47
48
|
attr_accessor :settings
|
|
48
49
|
|
|
49
50
|
def deliver!(mail)
|
|
50
|
-
|
|
51
|
+
smtp_from, smtp_to, message = check_delivery_params(mail)
|
|
51
52
|
|
|
52
|
-
|
|
53
|
-
|
|
53
|
+
from = "-f #{self.class.shellquote(smtp_from)}"
|
|
54
|
+
to = smtp_to.map { |_to| self.class.shellquote(_to) }.join(' ')
|
|
54
55
|
|
|
55
|
-
arguments =
|
|
56
|
-
|
|
57
|
-
self.class.call(settings[:location], arguments, mail.destinations.collect(&:escape_for_shell).join(" "), mail)
|
|
56
|
+
arguments = "#{settings[:arguments]} #{from} --"
|
|
57
|
+
self.class.call(settings[:location], arguments, to, message)
|
|
58
58
|
end
|
|
59
59
|
|
|
60
|
-
def self.call(path, arguments, destinations,
|
|
61
|
-
|
|
62
|
-
io.puts
|
|
60
|
+
def self.call(path, arguments, destinations, encoded_message)
|
|
61
|
+
popen "#{path} #{arguments} #{destinations}" do |io|
|
|
62
|
+
io.puts ::Mail::Utilities.to_lf(encoded_message)
|
|
63
63
|
io.flush
|
|
64
64
|
end
|
|
65
65
|
end
|
|
66
|
+
|
|
67
|
+
if RUBY_VERSION < '1.9.0'
|
|
68
|
+
def self.popen(command, &block)
|
|
69
|
+
IO.popen "#{command} 2>&1", 'w+', &block
|
|
70
|
+
end
|
|
71
|
+
else
|
|
72
|
+
def self.popen(command, &block)
|
|
73
|
+
IO.popen command, 'w+', :err => :out, &block
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# The following is an adaptation of ruby 1.9.2's shellwords.rb file,
|
|
78
|
+
# it is modified to include '+' in the allowed list to allow for
|
|
79
|
+
# sendmail to accept email addresses as the sender with a + in them.
|
|
80
|
+
def self.shellquote(address)
|
|
81
|
+
# Process as a single byte sequence because not all shell
|
|
82
|
+
# implementations are multibyte aware.
|
|
83
|
+
#
|
|
84
|
+
# A LF cannot be escaped with a backslash because a backslash + LF
|
|
85
|
+
# combo is regarded as line continuation and simply ignored. Strip it.
|
|
86
|
+
escaped = address.gsub(/([^A-Za-z0-9_\s\+\-.,:\/@])/n, "\\\\\\1").gsub("\n", '')
|
|
87
|
+
%("#{escaped}")
|
|
88
|
+
end
|
|
66
89
|
end
|
|
67
90
|
end
|