mail 2.6.1 → 2.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/MIT-LICENSE +1 -1
- data/README.md +92 -80
- data/lib/mail/attachments_list.rb +11 -5
- data/lib/mail/body.rb +81 -44
- data/lib/mail/check_delivery_params.rb +50 -10
- data/lib/mail/configuration.rb +3 -0
- data/lib/mail/{patterns.rb → constants.rb} +26 -6
- data/lib/mail/core_extensions/smtp.rb +20 -16
- data/lib/mail/core_extensions/string.rb +1 -27
- data/lib/mail/elements/address.rb +81 -93
- data/lib/mail/elements/address_list.rb +12 -29
- data/lib/mail/elements/content_disposition_element.rb +9 -15
- data/lib/mail/elements/content_location_element.rb +8 -12
- data/lib/mail/elements/content_transfer_encoding_element.rb +6 -10
- data/lib/mail/elements/content_type_element.rb +9 -19
- data/lib/mail/elements/date_time_element.rb +7 -14
- data/lib/mail/elements/envelope_from_element.rb +15 -21
- data/lib/mail/elements/message_ids_element.rb +12 -14
- data/lib/mail/elements/mime_version_element.rb +7 -14
- data/lib/mail/elements/phrase_list.rb +7 -9
- data/lib/mail/elements/received_element.rb +10 -15
- data/lib/mail/elements.rb +1 -0
- data/lib/mail/encodings/7bit.rb +6 -15
- data/lib/mail/encodings/8bit.rb +5 -18
- data/lib/mail/encodings/base64.rb +15 -10
- data/lib/mail/encodings/binary.rb +4 -22
- data/lib/mail/encodings/identity.rb +24 -0
- data/lib/mail/encodings/quoted_printable.rb +13 -7
- data/lib/mail/encodings/transfer_encoding.rb +47 -28
- data/lib/mail/encodings/unix_to_unix.rb +20 -0
- data/lib/mail/encodings.rb +121 -82
- data/lib/mail/envelope.rb +2 -1
- data/lib/mail/field.rb +114 -62
- data/lib/mail/field_list.rb +2 -1
- data/lib/mail/fields/bcc_field.rb +17 -5
- data/lib/mail/fields/cc_field.rb +2 -2
- data/lib/mail/fields/comments_field.rb +2 -1
- data/lib/mail/fields/common/address_container.rb +3 -2
- data/lib/mail/fields/common/common_address.rb +40 -14
- data/lib/mail/fields/common/common_date.rb +2 -1
- data/lib/mail/fields/common/common_field.rb +6 -11
- data/lib/mail/fields/common/common_message_id.rb +3 -2
- data/lib/mail/fields/common/parameter_hash.rb +5 -4
- data/lib/mail/fields/content_description_field.rb +2 -1
- data/lib/mail/fields/content_disposition_field.rb +14 -13
- data/lib/mail/fields/content_id_field.rb +5 -4
- data/lib/mail/fields/content_location_field.rb +3 -2
- data/lib/mail/fields/content_transfer_encoding_field.rb +3 -2
- data/lib/mail/fields/content_type_field.rb +7 -11
- data/lib/mail/fields/date_field.rb +4 -4
- 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 +3 -3
- data/lib/mail/fields/message_id_field.rb +3 -2
- data/lib/mail/fields/mime_version_field.rb +4 -3
- data/lib/mail/fields/optional_field.rb +5 -1
- data/lib/mail/fields/received_field.rb +5 -4
- 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_date_field.rb +2 -2
- data/lib/mail/fields/resent_from_field.rb +2 -2
- data/lib/mail/fields/resent_message_id_field.rb +2 -1
- data/lib/mail/fields/resent_sender_field.rb +2 -2
- data/lib/mail/fields/resent_to_field.rb +2 -2
- data/lib/mail/fields/return_path_field.rb +2 -2
- data/lib/mail/fields/sender_field.rb +2 -2
- data/lib/mail/fields/structured_field.rb +1 -0
- data/lib/mail/fields/subject_field.rb +2 -1
- data/lib/mail/fields/to_field.rb +2 -2
- data/lib/mail/fields/unstructured_field.rb +28 -10
- data/lib/mail/fields.rb +1 -0
- data/lib/mail/header.rb +18 -14
- data/lib/mail/indifferent_hash.rb +1 -0
- data/lib/mail/mail.rb +6 -11
- data/lib/mail/matchers/attachment_matchers.rb +29 -0
- data/lib/mail/matchers/has_sent_mail.rb +53 -9
- data/lib/mail/message.rb +99 -89
- data/lib/mail/multibyte/chars.rb +32 -30
- data/lib/mail/multibyte/unicode.rb +31 -26
- data/lib/mail/multibyte/utils.rb +1 -0
- data/lib/mail/multibyte.rb +65 -15
- data/lib/mail/network/delivery_methods/exim.rb +7 -10
- data/lib/mail/network/delivery_methods/file_delivery.rb +5 -8
- data/lib/mail/network/delivery_methods/logger_delivery.rb +37 -0
- data/lib/mail/network/delivery_methods/sendmail.rb +17 -11
- data/lib/mail/network/delivery_methods/smtp.rb +60 -53
- data/lib/mail/network/delivery_methods/smtp_connection.rb +11 -6
- data/lib/mail/network/delivery_methods/test_mailer.rb +6 -8
- data/lib/mail/network/retriever_methods/base.rb +1 -0
- data/lib/mail/network/retriever_methods/imap.rb +19 -5
- data/lib/mail/network/retriever_methods/pop3.rb +4 -1
- data/lib/mail/network/retriever_methods/test_retriever.rb +2 -1
- data/lib/mail/network.rb +2 -0
- data/lib/mail/parser_tools.rb +15 -0
- data/lib/mail/parsers/address_lists_parser.rb +33208 -104
- data/lib/mail/parsers/address_lists_parser.rl +172 -0
- data/lib/mail/parsers/content_disposition_parser.rb +877 -49
- data/lib/mail/parsers/content_disposition_parser.rl +82 -0
- data/lib/mail/parsers/content_location_parser.rb +804 -23
- data/lib/mail/parsers/content_location_parser.rl +71 -0
- data/lib/mail/parsers/content_transfer_encoding_parser.rb +502 -19
- data/lib/mail/parsers/content_transfer_encoding_parser.rl +64 -0
- data/lib/mail/parsers/content_type_parser.rb +1024 -46
- data/lib/mail/parsers/content_type_parser.rl +83 -0
- data/lib/mail/parsers/date_time_parser.rb +872 -23
- data/lib/mail/parsers/date_time_parser.rl +62 -0
- data/lib/mail/parsers/envelope_from_parser.rb +3570 -34
- data/lib/mail/parsers/envelope_from_parser.rl +82 -0
- data/lib/mail/parsers/message_ids_parser.rb +2840 -25
- data/lib/mail/parsers/message_ids_parser.rl +82 -0
- data/lib/mail/parsers/mime_version_parser.rb +492 -26
- data/lib/mail/parsers/mime_version_parser.rl +61 -0
- data/lib/mail/parsers/phrase_lists_parser.rb +862 -17
- data/lib/mail/parsers/phrase_lists_parser.rl +83 -0
- data/lib/mail/parsers/received_parser.rb +8765 -36
- data/lib/mail/parsers/received_parser.rl +84 -0
- data/lib/mail/parsers/rfc2045_content_transfer_encoding.rl +13 -0
- data/lib/mail/parsers/rfc2045_content_type.rl +25 -0
- data/lib/mail/parsers/rfc2045_mime.rl +16 -0
- data/lib/mail/parsers/rfc2183_content_disposition.rl +15 -0
- data/lib/mail/parsers/rfc3629_utf8.rl +19 -0
- data/lib/mail/parsers/rfc5234_abnf_core_rules.rl +22 -0
- data/lib/mail/parsers/rfc5322.rl +59 -0
- data/lib/mail/parsers/rfc5322_address.rl +72 -0
- data/lib/mail/parsers/{ragel/date_time.rl → rfc5322_date_time.rl} +8 -1
- data/lib/mail/parsers/rfc5322_lexical_tokens.rl +60 -0
- data/lib/mail/parsers.rb +17 -24
- data/lib/mail/part.rb +8 -5
- data/lib/mail/parts_list.rb +31 -14
- data/lib/mail/utilities.rb +112 -13
- 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 +52 -8
- data/lib/mail/version_specific/ruby_1_9.rb +143 -24
- data/lib/mail.rb +8 -14
- metadata +71 -81
- data/CHANGELOG.rdoc +0 -752
- data/CONTRIBUTING.md +0 -60
- data/Dependencies.txt +0 -2
- data/Gemfile +0 -15
- data/Rakefile +0 -29
- data/TODO.rdoc +0 -9
- data/VERSION +0 -4
- data/lib/mail/core_extensions/nil.rb +0 -19
- data/lib/mail/core_extensions/object.rb +0 -13
- data/lib/mail/core_extensions/string/access.rb +0 -145
- data/lib/mail/core_extensions/string/multibyte.rb +0 -78
- data/lib/mail/multibyte/exceptions.rb +0 -8
- data/lib/mail/parsers/ragel/common.rl +0 -184
- data/lib/mail/parsers/ragel/parser_info.rb +0 -61
- data/lib/mail/parsers/ragel/ruby/machines/address_lists_machine.rb +0 -14864
- data/lib/mail/parsers/ragel/ruby/machines/address_lists_machine.rb.rl +0 -37
- data/lib/mail/parsers/ragel/ruby/machines/content_disposition_machine.rb +0 -751
- data/lib/mail/parsers/ragel/ruby/machines/content_disposition_machine.rb.rl +0 -37
- data/lib/mail/parsers/ragel/ruby/machines/content_location_machine.rb +0 -614
- data/lib/mail/parsers/ragel/ruby/machines/content_location_machine.rb.rl +0 -37
- data/lib/mail/parsers/ragel/ruby/machines/content_transfer_encoding_machine.rb +0 -447
- data/lib/mail/parsers/ragel/ruby/machines/content_transfer_encoding_machine.rb.rl +0 -37
- data/lib/mail/parsers/ragel/ruby/machines/content_type_machine.rb +0 -825
- data/lib/mail/parsers/ragel/ruby/machines/content_type_machine.rb.rl +0 -37
- data/lib/mail/parsers/ragel/ruby/machines/date_time_machine.rb +0 -817
- data/lib/mail/parsers/ragel/ruby/machines/date_time_machine.rb.rl +0 -37
- data/lib/mail/parsers/ragel/ruby/machines/envelope_from_machine.rb +0 -2129
- data/lib/mail/parsers/ragel/ruby/machines/envelope_from_machine.rb.rl +0 -37
- data/lib/mail/parsers/ragel/ruby/machines/message_ids_machine.rb +0 -1570
- data/lib/mail/parsers/ragel/ruby/machines/message_ids_machine.rb.rl +0 -37
- data/lib/mail/parsers/ragel/ruby/machines/mime_version_machine.rb +0 -440
- data/lib/mail/parsers/ragel/ruby/machines/mime_version_machine.rb.rl +0 -37
- data/lib/mail/parsers/ragel/ruby/machines/phrase_lists_machine.rb +0 -564
- data/lib/mail/parsers/ragel/ruby/machines/phrase_lists_machine.rb.rl +0 -37
- data/lib/mail/parsers/ragel/ruby/machines/rb_actions.rl +0 -51
- data/lib/mail/parsers/ragel/ruby/machines/received_machine.rb +0 -5144
- data/lib/mail/parsers/ragel/ruby/machines/received_machine.rb.rl +0 -37
- data/lib/mail/parsers/ragel/ruby/parser.rb.rl.erb +0 -37
- data/lib/mail/parsers/ragel/ruby.rb +0 -39
- data/lib/mail/parsers/ragel.rb +0 -17
data/lib/mail/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
|
@@ -55,15 +56,23 @@ module Mail
|
|
55
56
|
#
|
56
57
|
# ===Making an email via a block
|
57
58
|
#
|
58
|
-
# mail = Mail.new do
|
59
|
-
#
|
60
|
-
#
|
61
|
-
# subject 'This is a test email'
|
62
|
-
#
|
59
|
+
# mail = Mail.new do |m|
|
60
|
+
# m.from 'mikel@test.lindsaar.net'
|
61
|
+
# m.to 'you@test.lindsaar.net'
|
62
|
+
# m.subject 'This is a test email'
|
63
|
+
# m.body File.read('body.txt')
|
63
64
|
# end
|
64
65
|
#
|
65
66
|
# mail.to_s #=> "From: mikel@test.lindsaar.net\r\nTo: you@...
|
66
67
|
#
|
68
|
+
# If may also pass a block with no arguments, in which case it will
|
69
|
+
# be evaluated in the scope of the new message instance:
|
70
|
+
#
|
71
|
+
# mail = Mail.new do
|
72
|
+
# from 'mikel@test.lindsaar.net'
|
73
|
+
# # …
|
74
|
+
# end
|
75
|
+
#
|
67
76
|
# ===Making an email via passing a string
|
68
77
|
#
|
69
78
|
# mail = Mail.new("To: mikel@test.lindsaar.net\r\nSubject: Hello\r\n\r\nHi there!")
|
@@ -105,7 +114,7 @@ module Mail
|
|
105
114
|
@html_part = nil
|
106
115
|
@errors = nil
|
107
116
|
@header = nil
|
108
|
-
@charset =
|
117
|
+
@charset = self.class.default_charset
|
109
118
|
@defaulted_charset = true
|
110
119
|
|
111
120
|
@smtp_envelope_from = nil
|
@@ -128,8 +137,23 @@ module Mail
|
|
128
137
|
init_with_string(args.flatten[0].to_s)
|
129
138
|
end
|
130
139
|
|
140
|
+
# Support both builder styles:
|
141
|
+
#
|
142
|
+
# Mail.new do
|
143
|
+
# to 'recipient@example.com'
|
144
|
+
# end
|
145
|
+
#
|
146
|
+
# and
|
147
|
+
#
|
148
|
+
# Mail.new do |m|
|
149
|
+
# m.to 'recipient@example.com'
|
150
|
+
# end
|
131
151
|
if block_given?
|
132
|
-
|
152
|
+
if block.arity.zero? || (RUBY_VERSION < '1.9' && block.arity < 1)
|
153
|
+
instance_eval(&block)
|
154
|
+
else
|
155
|
+
yield self
|
156
|
+
end
|
133
157
|
end
|
134
158
|
|
135
159
|
self
|
@@ -207,8 +231,12 @@ module Mail
|
|
207
231
|
# define a delivery_handler
|
208
232
|
attr_accessor :raise_delivery_errors
|
209
233
|
|
234
|
+
def self.default_charset; @@default_charset; end
|
235
|
+
def self.default_charset=(charset); @@default_charset = charset; end
|
236
|
+
self.default_charset = 'UTF-8'
|
237
|
+
|
210
238
|
def register_for_delivery_notification(observer)
|
211
|
-
|
239
|
+
warn("Message#register_for_delivery_notification is deprecated, please call Mail.register_observer instead")
|
212
240
|
Mail.register_observer(observer)
|
213
241
|
end
|
214
242
|
|
@@ -220,7 +248,7 @@ module Mail
|
|
220
248
|
Mail.inform_interceptors(self)
|
221
249
|
end
|
222
250
|
|
223
|
-
# Delivers
|
251
|
+
# Delivers a mail object.
|
224
252
|
#
|
225
253
|
# Examples:
|
226
254
|
#
|
@@ -355,13 +383,8 @@ module Mail
|
|
355
383
|
if self.message_id && other.message_id
|
356
384
|
self.encoded == other.encoded
|
357
385
|
else
|
358
|
-
|
359
|
-
|
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
|
386
|
+
dup.tap { |m| m.message_id = '<temp@test>' }.encoded ==
|
387
|
+
other.dup.tap { |m| m.message_id = '<temp@test>' }.encoded
|
365
388
|
end
|
366
389
|
end
|
367
390
|
|
@@ -1188,8 +1211,8 @@ module Mail
|
|
1188
1211
|
def default( sym, val = nil )
|
1189
1212
|
if val
|
1190
1213
|
header[sym] = val
|
1191
|
-
|
1192
|
-
|
1214
|
+
elsif field = header[sym]
|
1215
|
+
field.default
|
1193
1216
|
end
|
1194
1217
|
end
|
1195
1218
|
|
@@ -1235,14 +1258,13 @@ module Mail
|
|
1235
1258
|
def body(value = nil)
|
1236
1259
|
if value
|
1237
1260
|
self.body = value
|
1238
|
-
# add_encoding_to_body
|
1239
1261
|
else
|
1240
1262
|
process_body_raw if @body_raw
|
1241
1263
|
@body
|
1242
1264
|
end
|
1243
1265
|
end
|
1244
1266
|
|
1245
|
-
def body_encoding(value)
|
1267
|
+
def body_encoding(value = nil)
|
1246
1268
|
if value.nil?
|
1247
1269
|
body.encoding
|
1248
1270
|
else
|
@@ -1251,7 +1273,7 @@ module Mail
|
|
1251
1273
|
end
|
1252
1274
|
|
1253
1275
|
def body_encoding=(value)
|
1254
|
-
|
1276
|
+
body.encoding = value
|
1255
1277
|
end
|
1256
1278
|
|
1257
1279
|
# Returns the list of addresses this message should be sent to by
|
@@ -1411,11 +1433,11 @@ module Mail
|
|
1411
1433
|
end
|
1412
1434
|
|
1413
1435
|
def has_content_transfer_encoding?
|
1414
|
-
header[:content_transfer_encoding] && header[:content_transfer_encoding].errors
|
1436
|
+
header[:content_transfer_encoding] && Utilities.blank?(header[:content_transfer_encoding].errors)
|
1415
1437
|
end
|
1416
1438
|
|
1417
1439
|
def has_transfer_encoding? # :nodoc:
|
1418
|
-
|
1440
|
+
warn(":has_transfer_encoding? is deprecated in Mail 1.4.3. Please use has_content_transfer_encoding?\n#{caller}")
|
1419
1441
|
has_content_transfer_encoding?
|
1420
1442
|
end
|
1421
1443
|
|
@@ -1463,34 +1485,26 @@ module Mail
|
|
1463
1485
|
if !body.empty?
|
1464
1486
|
# Only give a warning if this isn't an attachment, has non US-ASCII and the user
|
1465
1487
|
# has not specified an encoding explicitly.
|
1466
|
-
if @defaulted_charset && body.raw_source.
|
1488
|
+
if @defaulted_charset && !body.raw_source.ascii_only? && !self.attachment?
|
1467
1489
|
warning = "Non US-ASCII detected and no charset defined.\nDefaulting to UTF-8, set your own if this is incorrect.\n"
|
1468
|
-
|
1490
|
+
warn(warning)
|
1469
1491
|
end
|
1470
1492
|
header[:content_type].parameters['charset'] = @charset
|
1471
1493
|
end
|
1472
1494
|
end
|
1473
1495
|
|
1474
1496
|
# Adds a content transfer encoding
|
1475
|
-
#
|
1476
|
-
# Otherwise raises a warning
|
1477
1497
|
def add_content_transfer_encoding
|
1478
|
-
|
1479
|
-
header[:content_transfer_encoding] = '7bit'
|
1480
|
-
else
|
1481
|
-
warning = "Non US-ASCII detected and no content-transfer-encoding defined.\nDefaulting to 8bit, set your own if this is incorrect.\n"
|
1482
|
-
STDERR.puts(warning)
|
1483
|
-
header[:content_transfer_encoding] = '8bit'
|
1484
|
-
end
|
1498
|
+
header[:content_transfer_encoding] ||= body.default_encoding
|
1485
1499
|
end
|
1486
1500
|
|
1487
1501
|
def add_transfer_encoding # :nodoc:
|
1488
|
-
|
1502
|
+
warn(":add_transfer_encoding is deprecated in Mail 1.4.3. Please use add_content_transfer_encoding\n#{caller}")
|
1489
1503
|
add_content_transfer_encoding
|
1490
1504
|
end
|
1491
1505
|
|
1492
1506
|
def transfer_encoding # :nodoc:
|
1493
|
-
|
1507
|
+
warn(":transfer_encoding is deprecated in Mail 1.4.3. Please use content_transfer_encoding\n#{caller}")
|
1494
1508
|
content_transfer_encoding
|
1495
1509
|
end
|
1496
1510
|
|
@@ -1500,7 +1514,7 @@ module Mail
|
|
1500
1514
|
end
|
1501
1515
|
|
1502
1516
|
def message_content_type
|
1503
|
-
|
1517
|
+
warn(":message_content_type is deprecated in Mail 1.4.3. Please use mime_type\n#{caller}")
|
1504
1518
|
mime_type
|
1505
1519
|
end
|
1506
1520
|
|
@@ -1532,7 +1546,7 @@ module Mail
|
|
1532
1546
|
|
1533
1547
|
# Returns the content type parameters
|
1534
1548
|
def mime_parameters
|
1535
|
-
|
1549
|
+
warn(':mime_parameters is deprecated in Mail 1.4.3, please use :content_type_parameters instead')
|
1536
1550
|
content_type_parameters
|
1537
1551
|
end
|
1538
1552
|
|
@@ -1558,7 +1572,14 @@ module Mail
|
|
1558
1572
|
|
1559
1573
|
# returns the part in a multipart/report email that has the content-type delivery-status
|
1560
1574
|
def delivery_status_part
|
1561
|
-
|
1575
|
+
unless defined? @delivery_status_part
|
1576
|
+
@delivery_status_part =
|
1577
|
+
if delivery_status_report?
|
1578
|
+
parts.detect(&:delivery_status_report_part?)
|
1579
|
+
end
|
1580
|
+
end
|
1581
|
+
|
1582
|
+
@delivery_status_part
|
1562
1583
|
end
|
1563
1584
|
|
1564
1585
|
def bounced?
|
@@ -1665,6 +1686,8 @@ module Mail
|
|
1665
1686
|
def html_part=(msg)
|
1666
1687
|
# Assign the html part and set multipart/alternative if there's a text part.
|
1667
1688
|
if msg
|
1689
|
+
msg = Mail::Part.new(:body => msg) unless msg.kind_of?(Mail::Message)
|
1690
|
+
|
1668
1691
|
@html_part = msg
|
1669
1692
|
@html_part.content_type = 'text/html' unless @html_part.has_content_type?
|
1670
1693
|
add_multipart_alternate_header if text_part
|
@@ -1687,6 +1710,8 @@ module Mail
|
|
1687
1710
|
def text_part=(msg)
|
1688
1711
|
# Assign the text part and set multipart/alternative if there's an html part.
|
1689
1712
|
if msg
|
1713
|
+
msg = Mail::Part.new(:body => msg) unless msg.kind_of?(Mail::Message)
|
1714
|
+
|
1690
1715
|
@text_part = msg
|
1691
1716
|
@text_part.content_type = 'text/plain' unless @text_part.has_content_type?
|
1692
1717
|
add_multipart_alternate_header if html_part
|
@@ -1705,7 +1730,7 @@ module Mail
|
|
1705
1730
|
|
1706
1731
|
# Adds a part to the parts list or creates the part list
|
1707
1732
|
def add_part(part)
|
1708
|
-
if !body.multipart? && !self.body.decoded
|
1733
|
+
if !body.multipart? && !Utilities.blank?(self.body.decoded)
|
1709
1734
|
@text_part = Mail::Part.new('Content-Type: text/plain;')
|
1710
1735
|
@text_part.body = body.decoded
|
1711
1736
|
self.body << @text_part
|
@@ -1761,14 +1786,14 @@ module Mail
|
|
1761
1786
|
#
|
1762
1787
|
# See also #attachments
|
1763
1788
|
def add_file(values)
|
1764
|
-
convert_to_multipart unless self.multipart? || self.body.decoded
|
1789
|
+
convert_to_multipart unless self.multipart? || Utilities.blank?(self.body.decoded)
|
1765
1790
|
add_multipart_mixed_header
|
1766
1791
|
if values.is_a?(String)
|
1767
1792
|
basename = File.basename(values)
|
1768
1793
|
filedata = File.open(values, 'rb') { |f| f.read }
|
1769
1794
|
else
|
1770
1795
|
basename = values[:filename]
|
1771
|
-
filedata = values
|
1796
|
+
filedata = values
|
1772
1797
|
end
|
1773
1798
|
self.attachments[basename] = filedata
|
1774
1799
|
end
|
@@ -1786,7 +1811,6 @@ module Mail
|
|
1786
1811
|
# ready to send
|
1787
1812
|
def ready_to_send!
|
1788
1813
|
identify_and_set_transfer_encoding
|
1789
|
-
parts.sort!([ "text/plain", "text/enriched", "text/html", "multipart/alternative" ])
|
1790
1814
|
parts.each do |part|
|
1791
1815
|
part.transport_encoding = transport_encoding
|
1792
1816
|
part.ready_to_send!
|
@@ -1795,7 +1819,7 @@ module Mail
|
|
1795
1819
|
end
|
1796
1820
|
|
1797
1821
|
def encode!
|
1798
|
-
|
1822
|
+
warn("Deprecated in 1.1.0 in favour of :ready_to_send! as it is less confusing with encoding and decoding.")
|
1799
1823
|
ready_to_send!
|
1800
1824
|
end
|
1801
1825
|
|
@@ -1811,16 +1835,13 @@ module Mail
|
|
1811
1835
|
end
|
1812
1836
|
|
1813
1837
|
def without_attachments!
|
1814
|
-
|
1815
|
-
|
1816
|
-
parts.delete_if { |p| p.attachment? }
|
1817
|
-
body_raw = if parts.empty?
|
1818
|
-
''
|
1819
|
-
else
|
1820
|
-
body.encoded
|
1821
|
-
end
|
1838
|
+
if has_attachments?
|
1839
|
+
parts.delete_if { |p| p.attachment? }
|
1822
1840
|
|
1823
|
-
|
1841
|
+
reencoded = parts.empty? ? '' : body.encoded(content_transfer_encoding)
|
1842
|
+
@body = nil # So the new parts won't be added to the existing body
|
1843
|
+
self.body = reencoded
|
1844
|
+
end
|
1824
1845
|
|
1825
1846
|
self
|
1826
1847
|
end
|
@@ -1853,7 +1874,7 @@ module Mail
|
|
1853
1874
|
case
|
1854
1875
|
when k == 'delivery_handler'
|
1855
1876
|
begin
|
1856
|
-
m.delivery_handler = Object.const_get(v) unless
|
1877
|
+
m.delivery_handler = Object.const_get(v) unless Utilities.blank?(v)
|
1857
1878
|
rescue NameError
|
1858
1879
|
end
|
1859
1880
|
when k == 'transport_encoding'
|
@@ -1963,6 +1984,8 @@ module Mail
|
|
1963
1984
|
|
1964
1985
|
private
|
1965
1986
|
|
1987
|
+
HEADER_SEPARATOR = /#{Constants::CRLF}#{Constants::CRLF}/
|
1988
|
+
|
1966
1989
|
# 2.1. General Description
|
1967
1990
|
# A message consists of header fields (collectively called "the header
|
1968
1991
|
# of the message") followed, optionally, by a body. The header is a
|
@@ -1970,19 +1993,14 @@ module Mail
|
|
1970
1993
|
# this standard. The body is simply a sequence of characters that
|
1971
1994
|
# follows the header and is separated from the header by an empty line
|
1972
1995
|
# (i.e., a line with nothing preceding the CRLF).
|
1973
|
-
#
|
1974
|
-
# Additionally, I allow for the case where someone might have put whitespace
|
1975
|
-
# on the "gap line"
|
1976
1996
|
def parse_message
|
1977
|
-
header_part, body_part = raw_source.lstrip.split(
|
1997
|
+
header_part, body_part = raw_source.lstrip.split(HEADER_SEPARATOR, 2)
|
1978
1998
|
self.header = header_part
|
1979
1999
|
self.body = body_part
|
1980
2000
|
end
|
1981
2001
|
|
1982
2002
|
def raw_source=(value)
|
1983
|
-
@raw_source = value
|
1984
|
-
@raw_source.force_encoding("binary") if RUBY_VERSION >= "1.9.1"
|
1985
|
-
@raw_source
|
2003
|
+
@raw_source = value
|
1986
2004
|
end
|
1987
2005
|
|
1988
2006
|
# see comments to body=. We take data and process it lazily
|
@@ -1994,11 +2012,9 @@ module Mail
|
|
1994
2012
|
@body_raw = nil
|
1995
2013
|
add_encoding_to_body
|
1996
2014
|
when @body && @body.multipart?
|
1997
|
-
|
1998
|
-
add_encoding_to_body
|
2015
|
+
self.text_part = value
|
1999
2016
|
else
|
2000
2017
|
@body_raw = value
|
2001
|
-
# process_body_raw
|
2002
2018
|
end
|
2003
2019
|
end
|
2004
2020
|
|
@@ -2013,9 +2029,9 @@ module Mail
|
|
2013
2029
|
|
2014
2030
|
def set_envelope_header
|
2015
2031
|
raw_string = raw_source.to_s
|
2016
|
-
if match_data =
|
2032
|
+
if match_data = raw_string.match(/\AFrom\s(#{TEXT}+)#{Constants::CRLF}/m)
|
2017
2033
|
set_envelope(match_data[1])
|
2018
|
-
self.raw_source = raw_string.sub(match_data[0], "")
|
2034
|
+
self.raw_source = raw_string.sub(match_data[0], "")
|
2019
2035
|
end
|
2020
2036
|
end
|
2021
2037
|
|
@@ -2023,6 +2039,13 @@ module Mail
|
|
2023
2039
|
body.split!(boundary)
|
2024
2040
|
end
|
2025
2041
|
|
2042
|
+
def allowed_encodings
|
2043
|
+
case mime_type
|
2044
|
+
when 'message/rfc822'
|
2045
|
+
[Encodings::SevenBit, Encodings::EightBit, Encodings::Binary]
|
2046
|
+
end
|
2047
|
+
end
|
2048
|
+
|
2026
2049
|
def add_encoding_to_body
|
2027
2050
|
if has_content_transfer_encoding?
|
2028
2051
|
@body.encoding = content_transfer_encoding
|
@@ -2030,18 +2053,18 @@ module Mail
|
|
2030
2053
|
end
|
2031
2054
|
|
2032
2055
|
def identify_and_set_transfer_encoding
|
2033
|
-
|
2034
|
-
|
2035
|
-
|
2036
|
-
|
2037
|
-
|
2056
|
+
if body && body.multipart?
|
2057
|
+
self.content_transfer_encoding = @transport_encoding
|
2058
|
+
else
|
2059
|
+
self.content_transfer_encoding = body.negotiate_best_encoding(@transport_encoding, allowed_encodings).to_s
|
2060
|
+
end
|
2038
2061
|
end
|
2039
2062
|
|
2040
2063
|
def add_required_fields
|
2041
2064
|
add_required_message_fields
|
2042
2065
|
add_multipart_mixed_header if body.multipart?
|
2043
2066
|
add_content_type unless has_content_type?
|
2044
|
-
add_charset
|
2067
|
+
add_charset if text? && !has_charset?
|
2045
2068
|
add_content_transfer_encoding unless has_content_transfer_encoding?
|
2046
2069
|
end
|
2047
2070
|
|
@@ -2117,10 +2140,10 @@ module Mail
|
|
2117
2140
|
content_disp_name = header[:content_disposition].filename rescue nil
|
2118
2141
|
content_loc_name = header[:content_location].location rescue nil
|
2119
2142
|
case
|
2120
|
-
when content_type && content_type_name
|
2121
|
-
filename = content_type_name
|
2122
2143
|
when content_disposition && content_disp_name
|
2123
2144
|
filename = content_disp_name
|
2145
|
+
when content_type && content_type_name
|
2146
|
+
filename = content_type_name
|
2124
2147
|
when content_location && content_loc_name
|
2125
2148
|
filename = content_loc_name
|
2126
2149
|
else
|
@@ -2141,20 +2164,7 @@ module Mail
|
|
2141
2164
|
end
|
2142
2165
|
|
2143
2166
|
def decode_body_as_text
|
2144
|
-
|
2145
|
-
if charset
|
2146
|
-
if RUBY_VERSION < '1.9'
|
2147
|
-
require 'iconv'
|
2148
|
-
return Iconv.conv("UTF-8//TRANSLIT//IGNORE", charset, body_text)
|
2149
|
-
else
|
2150
|
-
if encoding = Encoding.find(charset) rescue nil
|
2151
|
-
body_text.force_encoding(encoding)
|
2152
|
-
return body_text.encode(Encoding::UTF_8, :undef => :replace, :invalid => :replace, :replace => '')
|
2153
|
-
end
|
2154
|
-
end
|
2155
|
-
end
|
2156
|
-
body_text
|
2167
|
+
Encodings.transcode_charset decode_body, charset, 'UTF-8'
|
2157
2168
|
end
|
2158
|
-
|
2159
2169
|
end
|
2160
2170
|
end
|
data/lib/mail/multibyte/chars.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
require 'mail/multibyte/unicode'
|
2
4
|
|
3
5
|
module Mail #:nodoc:
|
4
6
|
module Multibyte #:nodoc:
|
@@ -39,7 +41,7 @@ module Mail #:nodoc:
|
|
39
41
|
if RUBY_VERSION >= "1.9"
|
40
42
|
# Creates a new Chars instance by wrapping _string_.
|
41
43
|
def initialize(string)
|
42
|
-
@wrapped_string = string
|
44
|
+
@wrapped_string = string.dup
|
43
45
|
@wrapped_string.force_encoding(Encoding::UTF_8) unless @wrapped_string.frozen?
|
44
46
|
end
|
45
47
|
else
|
@@ -102,7 +104,7 @@ module Mail #:nodoc:
|
|
102
104
|
# Returns a new Chars object containing the _other_ object concatenated to the string.
|
103
105
|
#
|
104
106
|
# Example:
|
105
|
-
# ('Café'
|
107
|
+
# (Mail::Multibyte.mb_chars('Café') + ' périferôl').to_s # => "Café périferôl"
|
106
108
|
def +(other)
|
107
109
|
chars(@wrapped_string + other)
|
108
110
|
end
|
@@ -110,7 +112,7 @@ module Mail #:nodoc:
|
|
110
112
|
# Like <tt>String#=~</tt> only it returns the character offset (in codepoints) instead of the byte offset.
|
111
113
|
#
|
112
114
|
# Example:
|
113
|
-
# 'Café périferôl'
|
115
|
+
# Mail::Multibyte.mb_chars('Café périferôl') =~ /ô/ # => 12
|
114
116
|
def =~(other)
|
115
117
|
translate_offset(@wrapped_string =~ other)
|
116
118
|
end
|
@@ -118,7 +120,7 @@ module Mail #:nodoc:
|
|
118
120
|
# Inserts the passed string at specified codepoint offsets.
|
119
121
|
#
|
120
122
|
# Example:
|
121
|
-
# 'Café'.
|
123
|
+
# Mail::Multibyte.mb_chars('Café').insert(4, ' périferôl').to_s # => "Café périferôl"
|
122
124
|
def insert(offset, fragment)
|
123
125
|
unpacked = Unicode.u_unpack(@wrapped_string)
|
124
126
|
unless offset > unpacked.length
|
@@ -134,7 +136,7 @@ module Mail #:nodoc:
|
|
134
136
|
# Returns +true+ if contained string contains _other_. Returns +false+ otherwise.
|
135
137
|
#
|
136
138
|
# Example:
|
137
|
-
# 'Café'.
|
139
|
+
# Mail::Multibyte.mb_chars('Café').include?('é') # => true
|
138
140
|
def include?(other)
|
139
141
|
# We have to redefine this method because Enumerable defines it.
|
140
142
|
@wrapped_string.include?(other)
|
@@ -143,8 +145,8 @@ module Mail #:nodoc:
|
|
143
145
|
# Returns the position _needle_ in the string, counting in codepoints. Returns +nil+ if _needle_ isn't found.
|
144
146
|
#
|
145
147
|
# Example:
|
146
|
-
# 'Café périferôl'.
|
147
|
-
# 'Café périferôl'.
|
148
|
+
# Mail::Multibyte.mb_chars('Café périferôl').index('ô') # => 12
|
149
|
+
# Mail::Multibyte.mb_chars('Café périferôl').index(/\w/u) # => 0
|
148
150
|
def index(needle, offset=0)
|
149
151
|
wrapped_offset = first(offset).wrapped_string.length
|
150
152
|
index = @wrapped_string.index(needle, wrapped_offset)
|
@@ -156,8 +158,8 @@ module Mail #:nodoc:
|
|
156
158
|
# string. Returns +nil+ if _needle_ isn't found.
|
157
159
|
#
|
158
160
|
# Example:
|
159
|
-
# 'Café périferôl'.
|
160
|
-
# 'Café périferôl'.
|
161
|
+
# Mail::Multibyte.mb_chars('Café périferôl').rindex('é') # => 6
|
162
|
+
# Mail::Multibyte.mb_chars('Café périferôl').rindex(/\w/u) # => 13
|
161
163
|
def rindex(needle, offset=nil)
|
162
164
|
offset ||= length
|
163
165
|
wrapped_offset = first(offset).wrapped_string.length
|
@@ -189,7 +191,7 @@ module Mail #:nodoc:
|
|
189
191
|
# Returns the codepoint of the first character in the string.
|
190
192
|
#
|
191
193
|
# Example:
|
192
|
-
# 'こんにちは'.
|
194
|
+
# Mail::Multibyte.mb_chars('こんにちは').ord # => 12371
|
193
195
|
def ord
|
194
196
|
Unicode.u_unpack(@wrapped_string)[0]
|
195
197
|
end
|
@@ -198,10 +200,10 @@ module Mail #:nodoc:
|
|
198
200
|
#
|
199
201
|
# Example:
|
200
202
|
#
|
201
|
-
# "¾ cup".
|
203
|
+
# Mail::Multibyte.mb_chars("¾ cup").rjust(8).to_s
|
202
204
|
# # => " ¾ cup"
|
203
205
|
#
|
204
|
-
# "¾ cup".
|
206
|
+
# Mail::Multibyte.mb_chars("¾ cup").rjust(8, " ").to_s # Use non-breaking whitespace
|
205
207
|
# # => " ¾ cup"
|
206
208
|
def rjust(integer, padstr=' ')
|
207
209
|
justify(integer, :right, padstr)
|
@@ -211,10 +213,10 @@ module Mail #:nodoc:
|
|
211
213
|
#
|
212
214
|
# Example:
|
213
215
|
#
|
214
|
-
# "¾ cup".
|
216
|
+
# Mail::Multibyte.mb_chars("¾ cup").rjust(8).to_s
|
215
217
|
# # => "¾ cup "
|
216
218
|
#
|
217
|
-
# "¾ cup".
|
219
|
+
# Mail::Multibyte.mb_chars("¾ cup").rjust(8, " ").to_s # Use non-breaking whitespace
|
218
220
|
# # => "¾ cup "
|
219
221
|
def ljust(integer, padstr=' ')
|
220
222
|
justify(integer, :left, padstr)
|
@@ -224,10 +226,10 @@ module Mail #:nodoc:
|
|
224
226
|
#
|
225
227
|
# Example:
|
226
228
|
#
|
227
|
-
# "¾ cup".
|
229
|
+
# Mail::Multibyte.mb_chars("¾ cup").center(8).to_s
|
228
230
|
# # => " ¾ cup "
|
229
231
|
#
|
230
|
-
# "¾ cup".
|
232
|
+
# Mail::Multibyte.mb_chars("¾ cup").center(8, " ").to_s # Use non-breaking whitespace
|
231
233
|
# # => " ¾ cup "
|
232
234
|
def center(integer, padstr=' ')
|
233
235
|
justify(integer, :center, padstr)
|
@@ -243,7 +245,7 @@ module Mail #:nodoc:
|
|
243
245
|
# instances instead of String. This makes chaining methods easier.
|
244
246
|
#
|
245
247
|
# Example:
|
246
|
-
# 'Café périferôl'.
|
248
|
+
# Mail::Multibyte.mb_chars('Café périferôl').split(/é/).map { |part| part.upcase.to_s } # => ["CAF", " P", "RIFERÔL"]
|
247
249
|
def split(*args)
|
248
250
|
@wrapped_string.split(*args).map { |i| i.mb_chars }
|
249
251
|
end
|
@@ -268,12 +270,12 @@ module Mail #:nodoc:
|
|
268
270
|
@wrapped_string[*args] = replace_by
|
269
271
|
else
|
270
272
|
result = Unicode.u_unpack(@wrapped_string)
|
271
|
-
if args[0].is_a?(
|
273
|
+
if args[0].is_a?(Integer)
|
272
274
|
raise IndexError, "index #{args[0]} out of string" if args[0] >= result.length
|
273
275
|
min = args[0]
|
274
276
|
max = args[1].nil? ? min : (min + args[1] - 1)
|
275
277
|
range = Range.new(min, max)
|
276
|
-
replace_by = [replace_by].pack('U') if replace_by.is_a?(
|
278
|
+
replace_by = [replace_by].pack('U') if replace_by.is_a?(Integer)
|
277
279
|
elsif args.first.is_a?(Range)
|
278
280
|
raise RangeError, "#{args[0]} out of range" if args[0].min >= result.length
|
279
281
|
range = args[0]
|
@@ -291,7 +293,7 @@ module Mail #:nodoc:
|
|
291
293
|
# Reverses all characters in the string.
|
292
294
|
#
|
293
295
|
# Example:
|
294
|
-
# 'Café'.
|
296
|
+
# Mail::Multibyte.mb_chars('Café').reverse.to_s # => 'éfaC'
|
295
297
|
def reverse
|
296
298
|
chars(Unicode.g_unpack(@wrapped_string).reverse.flatten.pack('U*'))
|
297
299
|
end
|
@@ -300,7 +302,7 @@ module Mail #:nodoc:
|
|
300
302
|
# character.
|
301
303
|
#
|
302
304
|
# Example:
|
303
|
-
# 'こんにちは'.
|
305
|
+
# Mail::Multibyte.mb_chars('こんにちは').slice(2..3).to_s # => "にち"
|
304
306
|
def slice(*args)
|
305
307
|
if args.size > 2
|
306
308
|
raise ArgumentError, "wrong number of arguments (#{args.size} for 1)" # Do as if we were native
|
@@ -337,7 +339,7 @@ module Mail #:nodoc:
|
|
337
339
|
# Convert characters in the string to uppercase.
|
338
340
|
#
|
339
341
|
# Example:
|
340
|
-
# 'Laurent, où sont les tests ?'.
|
342
|
+
# Mail::Multibyte.mb_chars('Laurent, où sont les tests ?').upcase.to_s # => "LAURENT, OÙ SONT LES TESTS ?"
|
341
343
|
def upcase
|
342
344
|
chars(Unicode.apply_mapping(@wrapped_string, :uppercase_mapping))
|
343
345
|
end
|
@@ -345,7 +347,7 @@ module Mail #:nodoc:
|
|
345
347
|
# Convert characters in the string to lowercase.
|
346
348
|
#
|
347
349
|
# Example:
|
348
|
-
# 'VĚDA A VÝZKUM'.
|
350
|
+
# Mail::Multibyte.mb_chars('VĚDA A VÝZKUM').downcase.to_s # => "věda a výzkum"
|
349
351
|
def downcase
|
350
352
|
chars(Unicode.apply_mapping(@wrapped_string, :lowercase_mapping))
|
351
353
|
end
|
@@ -353,7 +355,7 @@ module Mail #:nodoc:
|
|
353
355
|
# Converts the first character to uppercase and the remainder to lowercase.
|
354
356
|
#
|
355
357
|
# Example:
|
356
|
-
# 'über'.
|
358
|
+
# Mail::Multibyte.mb_chars('über').capitalize.to_s # => "Über"
|
357
359
|
def capitalize
|
358
360
|
(slice(0) || chars('')).upcase + (slice(1..-1) || chars('')).downcase
|
359
361
|
end
|
@@ -361,8 +363,8 @@ module Mail #:nodoc:
|
|
361
363
|
# Capitalizes the first letter of every word, when possible.
|
362
364
|
#
|
363
365
|
# Example:
|
364
|
-
# "ÉL QUE SE ENTERÓ".
|
365
|
-
# "日本語".
|
366
|
+
# Mail::Multibyte.mb_chars("ÉL QUE SE ENTERÓ").titleize # => "Él Que Se Enteró"
|
367
|
+
# Mail::Multibyte.mb_chars("日本語").titleize # => "日本語"
|
366
368
|
def titleize
|
367
369
|
chars(downcase.to_s.gsub(/\b('?\S)/u) { Unicode.apply_mapping $1, :uppercase_mapping })
|
368
370
|
end
|
@@ -382,7 +384,7 @@ module Mail #:nodoc:
|
|
382
384
|
#
|
383
385
|
# Example:
|
384
386
|
# 'é'.length # => 2
|
385
|
-
# 'é'.
|
387
|
+
# Mail::Multibyte.mb_chars('é').decompose.to_s.length # => 3
|
386
388
|
def decompose
|
387
389
|
chars(Unicode.decompose_codepoints(:canonical, Unicode.u_unpack(@wrapped_string)).pack('U*'))
|
388
390
|
end
|
@@ -391,7 +393,7 @@ module Mail #:nodoc:
|
|
391
393
|
#
|
392
394
|
# Example:
|
393
395
|
# 'é'.length # => 3
|
394
|
-
# 'é'.
|
396
|
+
# Mail::Multibyte.mb_chars('é').compose.to_s.length # => 2
|
395
397
|
def compose
|
396
398
|
chars(Unicode.compose_codepoints(Unicode.u_unpack(@wrapped_string)).pack('U*'))
|
397
399
|
end
|
@@ -399,8 +401,8 @@ module Mail #:nodoc:
|
|
399
401
|
# Returns the number of grapheme clusters in the string.
|
400
402
|
#
|
401
403
|
# Example:
|
402
|
-
# 'क्षि'.
|
403
|
-
# 'क्षि'.
|
404
|
+
# Mail::Multibyte.mb_chars('क्षि').length # => 4
|
405
|
+
# Mail::Multibyte.mb_chars('क्षि').g_length # => 3
|
404
406
|
def g_length
|
405
407
|
Unicode.g_unpack(@wrapped_string).length
|
406
408
|
end
|