mail 2.7.1 → 2.8.0.rc1
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 +4 -4
- data/README.md +45 -28
- data/lib/mail/attachments_list.rb +2 -5
- data/lib/mail/body.rb +24 -47
- data/lib/mail/constants.rb +27 -5
- data/lib/mail/elements/address.rb +27 -27
- data/lib/mail/elements/address_list.rb +1 -1
- data/lib/mail/elements/content_disposition_element.rb +1 -1
- data/lib/mail/elements/content_location_element.rb +1 -1
- data/lib/mail/elements/content_transfer_encoding_element.rb +1 -1
- data/lib/mail/elements/content_type_element.rb +8 -4
- data/lib/mail/elements/date_time_element.rb +1 -1
- data/lib/mail/elements/envelope_from_element.rb +13 -7
- data/lib/mail/elements/message_ids_element.rb +14 -5
- data/lib/mail/elements/mime_version_element.rb +1 -1
- data/lib/mail/elements/phrase_list.rb +7 -2
- data/lib/mail/elements/received_element.rb +20 -6
- data/lib/mail/encodings/7bit.rb +5 -0
- data/lib/mail/encodings/base64.rb +2 -2
- data/lib/mail/encodings/quoted_printable.rb +2 -2
- data/lib/mail/encodings.rb +30 -59
- data/lib/mail/envelope.rb +11 -14
- data/lib/mail/field.rb +37 -53
- data/lib/mail/field_list.rb +60 -7
- data/lib/mail/fields/bcc_field.rb +34 -52
- data/lib/mail/fields/cc_field.rb +28 -49
- data/lib/mail/fields/comments_field.rb +27 -37
- data/lib/mail/fields/common_address_field.rb +170 -0
- data/lib/mail/fields/common_date_field.rb +58 -0
- data/lib/mail/fields/common_field.rb +77 -0
- data/lib/mail/fields/common_message_id_field.rb +42 -0
- data/lib/mail/fields/content_description_field.rb +7 -14
- data/lib/mail/fields/content_disposition_field.rb +13 -38
- data/lib/mail/fields/content_id_field.rb +24 -51
- data/lib/mail/fields/content_location_field.rb +11 -25
- data/lib/mail/fields/content_transfer_encoding_field.rb +31 -31
- data/lib/mail/fields/content_type_field.rb +46 -71
- data/lib/mail/fields/date_field.rb +23 -51
- data/lib/mail/fields/from_field.rb +28 -49
- data/lib/mail/fields/in_reply_to_field.rb +38 -49
- data/lib/mail/fields/keywords_field.rb +18 -31
- data/lib/mail/fields/message_id_field.rb +25 -71
- data/lib/mail/fields/mime_version_field.rb +19 -30
- data/lib/mail/fields/named_structured_field.rb +11 -0
- data/lib/mail/fields/named_unstructured_field.rb +11 -0
- data/lib/mail/fields/optional_field.rb +5 -6
- data/lib/mail/fields/{common/parameter_hash.rb → parameter_hash.rb} +12 -10
- data/lib/mail/fields/received_field.rb +43 -57
- data/lib/mail/fields/references_field.rb +35 -49
- data/lib/mail/fields/reply_to_field.rb +28 -49
- data/lib/mail/fields/resent_bcc_field.rb +28 -49
- data/lib/mail/fields/resent_cc_field.rb +28 -49
- data/lib/mail/fields/resent_date_field.rb +5 -29
- data/lib/mail/fields/resent_from_field.rb +28 -49
- data/lib/mail/fields/resent_message_id_field.rb +5 -29
- data/lib/mail/fields/resent_sender_field.rb +27 -56
- data/lib/mail/fields/resent_to_field.rb +28 -49
- data/lib/mail/fields/return_path_field.rb +50 -54
- data/lib/mail/fields/sender_field.rb +34 -55
- data/lib/mail/fields/structured_field.rb +3 -30
- data/lib/mail/fields/subject_field.rb +9 -11
- data/lib/mail/fields/to_field.rb +28 -49
- data/lib/mail/fields/unstructured_field.rb +16 -48
- data/lib/mail/header.rb +69 -110
- data/lib/mail/matchers/attachment_matchers.rb +15 -0
- data/lib/mail/message.rb +46 -64
- data/lib/mail/multibyte/chars.rb +8 -166
- data/lib/mail/multibyte/utils.rb +26 -43
- data/lib/mail/multibyte.rb +1 -11
- data/lib/mail/network/delivery_methods/exim.rb +5 -4
- data/lib/mail/network/delivery_methods/file_delivery.rb +11 -10
- data/lib/mail/network/delivery_methods/logger_delivery.rb +2 -5
- data/lib/mail/network/delivery_methods/sendmail.rb +27 -35
- data/lib/mail/network/delivery_methods/smtp.rb +3 -3
- data/lib/mail/network/delivery_methods/smtp_connection.rb +3 -12
- data/lib/mail/network/delivery_methods/test_mailer.rb +4 -2
- data/lib/mail/network/retriever_methods/base.rb +8 -8
- data/lib/mail/network/retriever_methods/imap.rb +2 -2
- data/lib/mail/network/retriever_methods/pop3.rb +2 -2
- data/lib/mail/network/retriever_methods/test_retriever.rb +2 -1
- data/lib/mail/parsers/address_lists_parser.rb +33070 -33064
- data/lib/mail/parsers/address_lists_parser.rl +7 -0
- data/lib/mail/parsers/content_disposition_parser.rb +833 -827
- data/lib/mail/parsers/content_disposition_parser.rl +7 -0
- data/lib/mail/parsers/content_location_parser.rb +770 -764
- data/lib/mail/parsers/content_location_parser.rl +7 -0
- data/lib/mail/parsers/content_transfer_encoding_parser.rb +474 -468
- data/lib/mail/parsers/content_transfer_encoding_parser.rl +7 -0
- data/lib/mail/parsers/content_type_parser.rb +971 -965
- data/lib/mail/parsers/content_type_parser.rl +7 -0
- data/lib/mail/parsers/date_time_parser.rb +838 -832
- data/lib/mail/parsers/date_time_parser.rl +7 -0
- data/lib/mail/parsers/envelope_from_parser.rb +3623 -3529
- data/lib/mail/parsers/envelope_from_parser.rl +7 -0
- data/lib/mail/parsers/message_ids_parser.rb +5107 -2800
- data/lib/mail/parsers/message_ids_parser.rl +12 -1
- data/lib/mail/parsers/mime_version_parser.rb +463 -457
- data/lib/mail/parsers/mime_version_parser.rl +7 -0
- data/lib/mail/parsers/phrase_lists_parser.rb +836 -830
- data/lib/mail/parsers/phrase_lists_parser.rl +8 -1
- data/lib/mail/parsers/received_parser.rb +8688 -8682
- data/lib/mail/parsers/received_parser.rl +7 -0
- data/lib/mail/parsers/rfc5322.rl +28 -13
- data/lib/mail/parsers.rb +11 -17
- data/lib/mail/part.rb +5 -9
- data/lib/mail/parts_list.rb +57 -0
- data/lib/mail/smtp_envelope.rb +57 -0
- data/lib/mail/utilities.rb +307 -69
- data/lib/mail/version.rb +3 -3
- data/lib/mail/yaml.rb +30 -0
- data/lib/mail.rb +0 -20
- metadata +74 -21
- data/lib/mail/check_delivery_params.rb +0 -60
- data/lib/mail/core_extensions/smtp.rb +0 -28
- data/lib/mail/core_extensions/string.rb +0 -17
- data/lib/mail/fields/common/address_container.rb +0 -17
- data/lib/mail/fields/common/common_address.rb +0 -161
- data/lib/mail/fields/common/common_date.rb +0 -36
- data/lib/mail/fields/common/common_field.rb +0 -52
- data/lib/mail/fields/common/common_message_id.rb +0 -49
- data/lib/mail/version_specific/ruby_1_8.rb +0 -163
- data/lib/mail/version_specific/ruby_1_9.rb +0 -278
data/lib/mail/message.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
# frozen_string_literal: true
|
3
|
-
require
|
3
|
+
require 'mail/constants'
|
4
|
+
require 'mail/utilities'
|
5
|
+
require 'mail/yaml'
|
4
6
|
|
5
7
|
module Mail
|
6
8
|
# The Message class provides a single point of access to all things to do with an
|
@@ -46,10 +48,6 @@ module Mail
|
|
46
48
|
# follows the header and is separated from the header by an empty line
|
47
49
|
# (i.e., a line with nothing preceding the CRLF).
|
48
50
|
class Message
|
49
|
-
|
50
|
-
include Constants
|
51
|
-
include Utilities
|
52
|
-
|
53
51
|
# ==Making an email
|
54
52
|
#
|
55
53
|
# You can make an new mail object via a block, passing a string, file or direct assignment.
|
@@ -149,7 +147,7 @@ module Mail
|
|
149
147
|
# m.to 'recipient@example.com'
|
150
148
|
# end
|
151
149
|
if block_given?
|
152
|
-
if block.arity.zero?
|
150
|
+
if block.arity.zero?
|
153
151
|
instance_eval(&block)
|
154
152
|
else
|
155
153
|
yield self
|
@@ -235,11 +233,6 @@ module Mail
|
|
235
233
|
def self.default_charset=(charset); @@default_charset = charset; end
|
236
234
|
self.default_charset = 'UTF-8'
|
237
235
|
|
238
|
-
def register_for_delivery_notification(observer)
|
239
|
-
warn("Message#register_for_delivery_notification is deprecated, please call Mail.register_observer instead")
|
240
|
-
Mail.register_observer(observer)
|
241
|
-
end
|
242
|
-
|
243
236
|
def inform_observers
|
244
237
|
Mail.inform_observers(self)
|
245
238
|
end
|
@@ -301,7 +294,7 @@ module Mail
|
|
301
294
|
reply.references ||= bracketed_message_id
|
302
295
|
end
|
303
296
|
if subject
|
304
|
-
reply.subject = subject =~ /^Re:/i ? subject : "
|
297
|
+
reply.subject = subject =~ /^Re:/i ? subject : "Re: #{subject}"
|
305
298
|
end
|
306
299
|
if reply_to || from
|
307
300
|
reply.to = self[reply_to ? :reply_to : :from].to_s
|
@@ -406,9 +399,9 @@ module Mail
|
|
406
399
|
end
|
407
400
|
|
408
401
|
# Sets the envelope from for the email
|
409
|
-
def set_envelope(
|
402
|
+
def set_envelope(val)
|
410
403
|
@raw_envelope = val
|
411
|
-
@envelope = Mail::Envelope.
|
404
|
+
@envelope = Mail::Envelope.parse(val) rescue nil
|
412
405
|
end
|
413
406
|
|
414
407
|
# The raw_envelope is the From mikel@test.lindsaar.net Mon May 2 16:07:05 2009
|
@@ -1339,7 +1332,7 @@ module Mail
|
|
1339
1332
|
# mail['foo'] = '1234'
|
1340
1333
|
# mail['foo'].to_s #=> '1234'
|
1341
1334
|
def [](name)
|
1342
|
-
header[underscoreize(name)]
|
1335
|
+
header[Utilities.underscoreize(name)]
|
1343
1336
|
end
|
1344
1337
|
|
1345
1338
|
# Method Missing in this implementation allows you to set any of the
|
@@ -1385,7 +1378,7 @@ module Mail
|
|
1385
1378
|
#:nodoc:
|
1386
1379
|
# Only take the structured fields, as we could take _anything_ really
|
1387
1380
|
# as it could become an optional field... "but therin lies the dark side"
|
1388
|
-
field_name = underscoreize(name).chomp("=")
|
1381
|
+
field_name = Utilities.underscoreize(name).chomp("=")
|
1389
1382
|
if Mail::Field::KNOWN_FIELDS.include?(field_name)
|
1390
1383
|
if args.empty?
|
1391
1384
|
header[field_name]
|
@@ -1436,11 +1429,6 @@ module Mail
|
|
1436
1429
|
header[:content_transfer_encoding] && Utilities.blank?(header[:content_transfer_encoding].errors)
|
1437
1430
|
end
|
1438
1431
|
|
1439
|
-
def has_transfer_encoding? # :nodoc:
|
1440
|
-
warn(":has_transfer_encoding? is deprecated in Mail 1.4.3. Please use has_content_transfer_encoding?\n#{caller}")
|
1441
|
-
has_content_transfer_encoding?
|
1442
|
-
end
|
1443
|
-
|
1444
1432
|
# Creates a new empty Message-ID field and inserts it in the correct order
|
1445
1433
|
# into the Header. The MessageIdField object will automatically generate
|
1446
1434
|
# a unique message ID if you try and encode it or output it to_s without
|
@@ -1489,7 +1477,9 @@ module Mail
|
|
1489
1477
|
warning = "Non US-ASCII detected and no charset defined.\nDefaulting to UTF-8, set your own if this is incorrect.\n"
|
1490
1478
|
warn(warning)
|
1491
1479
|
end
|
1492
|
-
|
1480
|
+
if @charset
|
1481
|
+
header[:content_type].parameters['charset'] = @charset
|
1482
|
+
end
|
1493
1483
|
end
|
1494
1484
|
end
|
1495
1485
|
|
@@ -1498,26 +1488,11 @@ module Mail
|
|
1498
1488
|
header[:content_transfer_encoding] ||= body.default_encoding
|
1499
1489
|
end
|
1500
1490
|
|
1501
|
-
def add_transfer_encoding # :nodoc:
|
1502
|
-
warn(":add_transfer_encoding is deprecated in Mail 1.4.3. Please use add_content_transfer_encoding\n#{caller}")
|
1503
|
-
add_content_transfer_encoding
|
1504
|
-
end
|
1505
|
-
|
1506
|
-
def transfer_encoding # :nodoc:
|
1507
|
-
warn(":transfer_encoding is deprecated in Mail 1.4.3. Please use content_transfer_encoding\n#{caller}")
|
1508
|
-
content_transfer_encoding
|
1509
|
-
end
|
1510
|
-
|
1511
1491
|
# Returns the MIME media type of part we are on, this is taken from the content-type header
|
1512
1492
|
def mime_type
|
1513
1493
|
has_content_type? ? header[:content_type].string : nil rescue nil
|
1514
1494
|
end
|
1515
1495
|
|
1516
|
-
def message_content_type
|
1517
|
-
warn(":message_content_type is deprecated in Mail 1.4.3. Please use mime_type\n#{caller}")
|
1518
|
-
mime_type
|
1519
|
-
end
|
1520
|
-
|
1521
1496
|
# Returns the character set defined in the content type field
|
1522
1497
|
def charset
|
1523
1498
|
if @header
|
@@ -1544,12 +1519,6 @@ module Mail
|
|
1544
1519
|
has_content_type? ? header[:content_type].sub_type : nil rescue nil
|
1545
1520
|
end
|
1546
1521
|
|
1547
|
-
# Returns the content type parameters
|
1548
|
-
def mime_parameters
|
1549
|
-
warn(':mime_parameters is deprecated in Mail 1.4.3, please use :content_type_parameters instead')
|
1550
|
-
content_type_parameters
|
1551
|
-
end
|
1552
|
-
|
1553
1522
|
# Returns the content type parameters
|
1554
1523
|
def content_type_parameters
|
1555
1524
|
has_content_type? ? header[:content_type].parameters : nil rescue nil
|
@@ -1798,12 +1767,22 @@ module Mail
|
|
1798
1767
|
self.attachments[basename] = filedata
|
1799
1768
|
end
|
1800
1769
|
|
1770
|
+
MULTIPART_CONVERSION_CONTENT_FIELDS = [ :content_description, :content_disposition, :content_transfer_encoding, :content_type ]
|
1771
|
+
private_constant :MULTIPART_CONVERSION_CONTENT_FIELDS if respond_to?(:private_constant)
|
1772
|
+
|
1801
1773
|
def convert_to_multipart
|
1802
|
-
|
1803
|
-
|
1804
|
-
|
1805
|
-
|
1774
|
+
text_part = Mail::Part.new(:body => body.decoded)
|
1775
|
+
|
1776
|
+
MULTIPART_CONVERSION_CONTENT_FIELDS.each do |field_name|
|
1777
|
+
if value = send(field_name)
|
1778
|
+
writer = :"#{field_name}="
|
1779
|
+
text_part.send writer, value
|
1780
|
+
send writer, nil
|
1781
|
+
end
|
1782
|
+
end
|
1806
1783
|
text_part.charset = charset unless @defaulted_charset
|
1784
|
+
|
1785
|
+
self.body = ''
|
1807
1786
|
self.body << text_part
|
1808
1787
|
end
|
1809
1788
|
|
@@ -1818,11 +1797,6 @@ module Mail
|
|
1818
1797
|
add_required_fields
|
1819
1798
|
end
|
1820
1799
|
|
1821
|
-
def encode!
|
1822
|
-
warn("Deprecated in 1.1.0 in favour of :ready_to_send! as it is less confusing with encoding and decoding.")
|
1823
|
-
ready_to_send!
|
1824
|
-
end
|
1825
|
-
|
1826
1800
|
# Outputs an encoded string representation of the mail message including
|
1827
1801
|
# all headers, attachments, etc. This is an encoded email in US-ASCII,
|
1828
1802
|
# so it is able to be directly sent to an email server.
|
@@ -1836,7 +1810,7 @@ module Mail
|
|
1836
1810
|
|
1837
1811
|
def without_attachments!
|
1838
1812
|
if has_attachments?
|
1839
|
-
parts.
|
1813
|
+
parts.delete_attachments
|
1840
1814
|
|
1841
1815
|
reencoded = parts.empty? ? '' : body.encoded(content_transfer_encoding)
|
1842
1816
|
@body = nil # So the new parts won't be added to the existing body
|
@@ -1867,7 +1841,7 @@ module Mail
|
|
1867
1841
|
end
|
1868
1842
|
|
1869
1843
|
def self.from_yaml(str)
|
1870
|
-
hash = YAML.load(str)
|
1844
|
+
hash = Mail::YAML.load(str)
|
1871
1845
|
m = self.new(:headers => hash['headers'])
|
1872
1846
|
hash.delete('headers')
|
1873
1847
|
hash.each do |k,v|
|
@@ -1900,6 +1874,15 @@ module Mail
|
|
1900
1874
|
"#<#{self.class}:#{self.object_id}, Multipart: #{multipart?}, Headers: #{header.field_summary}>"
|
1901
1875
|
end
|
1902
1876
|
|
1877
|
+
def inspect_structure
|
1878
|
+
inspect +
|
1879
|
+
if self.multipart?
|
1880
|
+
"\n" + parts.inspect_structure
|
1881
|
+
else
|
1882
|
+
''
|
1883
|
+
end
|
1884
|
+
end
|
1885
|
+
|
1903
1886
|
def decoded
|
1904
1887
|
case
|
1905
1888
|
when self.text?
|
@@ -1984,7 +1967,7 @@ module Mail
|
|
1984
1967
|
|
1985
1968
|
private
|
1986
1969
|
|
1987
|
-
HEADER_SEPARATOR = /#{Constants::
|
1970
|
+
HEADER_SEPARATOR = /#{Constants::LAX_CRLF}#{Constants::LAX_CRLF}/
|
1988
1971
|
|
1989
1972
|
# 2.1. General Description
|
1990
1973
|
# A message consists of header fields (collectively called "the header
|
@@ -2029,7 +2012,7 @@ module Mail
|
|
2029
2012
|
|
2030
2013
|
def set_envelope_header
|
2031
2014
|
raw_string = raw_source.to_s
|
2032
|
-
if match_data = raw_string.match(/\AFrom\s(#{TEXT}
|
2015
|
+
if match_data = raw_string.match(/\AFrom\s+([^:\s]#{Constants::TEXT}*)#{Constants::LAX_CRLF}/m)
|
2033
2016
|
set_envelope(match_data[1])
|
2034
2017
|
self.raw_source = raw_string.sub(match_data[0], "")
|
2035
2018
|
end
|
@@ -2053,10 +2036,12 @@ module Mail
|
|
2053
2036
|
end
|
2054
2037
|
|
2055
2038
|
def identify_and_set_transfer_encoding
|
2056
|
-
if body
|
2057
|
-
|
2058
|
-
|
2059
|
-
|
2039
|
+
if body
|
2040
|
+
if body.multipart?
|
2041
|
+
self.content_transfer_encoding = @transport_encoding
|
2042
|
+
else
|
2043
|
+
self.content_transfer_encoding = body.negotiate_best_encoding(@transport_encoding, allowed_encodings).to_s
|
2044
|
+
end
|
2060
2045
|
end
|
2061
2046
|
end
|
2062
2047
|
|
@@ -2076,7 +2061,6 @@ module Mail
|
|
2076
2061
|
|
2077
2062
|
def add_multipart_alternate_header
|
2078
2063
|
header['content-type'] = ContentTypeField.with_boundary('multipart/alternative').value
|
2079
|
-
header['content_type'].parameters[:charset] = @charset
|
2080
2064
|
body.boundary = boundary
|
2081
2065
|
end
|
2082
2066
|
|
@@ -2084,7 +2068,6 @@ module Mail
|
|
2084
2068
|
unless body.boundary && boundary
|
2085
2069
|
header['content-type'] = 'multipart/mixed' unless header['content-type']
|
2086
2070
|
header['content-type'].parameters[:boundary] = ContentTypeField.generate_boundary
|
2087
|
-
header['content_type'].parameters[:charset] = @charset
|
2088
2071
|
body.boundary = boundary
|
2089
2072
|
end
|
2090
2073
|
end
|
@@ -2092,7 +2075,6 @@ module Mail
|
|
2092
2075
|
def add_multipart_mixed_header
|
2093
2076
|
unless header['content-type']
|
2094
2077
|
header['content-type'] = ContentTypeField.with_boundary('multipart/mixed').value
|
2095
|
-
header['content_type'].parameters[:charset] = @charset
|
2096
2078
|
body.boundary = boundary
|
2097
2079
|
end
|
2098
2080
|
end
|
@@ -2109,7 +2091,7 @@ module Mail
|
|
2109
2091
|
body_content = nil
|
2110
2092
|
|
2111
2093
|
passed_in_options.each_pair do |k,v|
|
2112
|
-
k = underscoreize(k).to_sym if k.class == String
|
2094
|
+
k = Utilities.underscoreize(k).to_sym if k.class == String
|
2113
2095
|
if k == :headers
|
2114
2096
|
self.headers(v)
|
2115
2097
|
elsif k == :body
|
data/lib/mail/multibyte/chars.rb
CHANGED
@@ -38,16 +38,10 @@ module Mail #:nodoc:
|
|
38
38
|
alias to_s wrapped_string
|
39
39
|
alias to_str wrapped_string
|
40
40
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
@wrapped_string.force_encoding(Encoding::UTF_8) unless @wrapped_string.frozen?
|
46
|
-
end
|
47
|
-
else
|
48
|
-
def initialize(string) #:nodoc:
|
49
|
-
@wrapped_string = string
|
50
|
-
end
|
41
|
+
# Creates a new Chars instance by wrapping _string_.
|
42
|
+
def initialize(string)
|
43
|
+
@wrapped_string = string.dup
|
44
|
+
@wrapped_string.force_encoding(Encoding::UTF_8) unless @wrapped_string.frozen?
|
51
45
|
end
|
52
46
|
|
53
47
|
# Forward all undefined methods to the wrapped string.
|
@@ -72,15 +66,6 @@ module Mail #:nodoc:
|
|
72
66
|
true
|
73
67
|
end
|
74
68
|
|
75
|
-
# Returns +true+ when the proxy class can handle the string. Returns +false+ otherwise.
|
76
|
-
def self.consumes?(string)
|
77
|
-
# Unpack is a little bit faster than regular expressions.
|
78
|
-
string.unpack('U*')
|
79
|
-
true
|
80
|
-
rescue ArgumentError
|
81
|
-
false
|
82
|
-
end
|
83
|
-
|
84
69
|
include Comparable
|
85
70
|
|
86
71
|
# Returns -1, 0, or 1, depending on whether the Chars object is to be sorted before,
|
@@ -94,151 +79,8 @@ module Mail #:nodoc:
|
|
94
79
|
@wrapped_string <=> other.to_s
|
95
80
|
end
|
96
81
|
|
97
|
-
|
98
|
-
|
99
|
-
# +false+ otherwise.
|
100
|
-
def self.wants?(string)
|
101
|
-
$KCODE == 'UTF8' && consumes?(string)
|
102
|
-
end
|
103
|
-
|
104
|
-
# Returns a new Chars object containing the _other_ object concatenated to the string.
|
105
|
-
#
|
106
|
-
# Example:
|
107
|
-
# (Mail::Multibyte.mb_chars('Café') + ' périferôl').to_s # => "Café périferôl"
|
108
|
-
def +(other)
|
109
|
-
chars(@wrapped_string + other)
|
110
|
-
end
|
111
|
-
|
112
|
-
# Like <tt>String#=~</tt> only it returns the character offset (in codepoints) instead of the byte offset.
|
113
|
-
#
|
114
|
-
# Example:
|
115
|
-
# Mail::Multibyte.mb_chars('Café périferôl') =~ /ô/ # => 12
|
116
|
-
def =~(other)
|
117
|
-
translate_offset(@wrapped_string =~ other)
|
118
|
-
end
|
119
|
-
|
120
|
-
# Inserts the passed string at specified codepoint offsets.
|
121
|
-
#
|
122
|
-
# Example:
|
123
|
-
# Mail::Multibyte.mb_chars('Café').insert(4, ' périferôl').to_s # => "Café périferôl"
|
124
|
-
def insert(offset, fragment)
|
125
|
-
unpacked = Unicode.u_unpack(@wrapped_string)
|
126
|
-
unless offset > unpacked.length
|
127
|
-
@wrapped_string.replace(
|
128
|
-
Unicode.u_unpack(@wrapped_string).insert(offset, *Unicode.u_unpack(fragment)).pack('U*')
|
129
|
-
)
|
130
|
-
else
|
131
|
-
raise IndexError, "index #{offset} out of string"
|
132
|
-
end
|
133
|
-
self
|
134
|
-
end
|
135
|
-
|
136
|
-
# Returns +true+ if contained string contains _other_. Returns +false+ otherwise.
|
137
|
-
#
|
138
|
-
# Example:
|
139
|
-
# Mail::Multibyte.mb_chars('Café').include?('é') # => true
|
140
|
-
def include?(other)
|
141
|
-
# We have to redefine this method because Enumerable defines it.
|
142
|
-
@wrapped_string.include?(other)
|
143
|
-
end
|
144
|
-
|
145
|
-
# Returns the position _needle_ in the string, counting in codepoints. Returns +nil+ if _needle_ isn't found.
|
146
|
-
#
|
147
|
-
# Example:
|
148
|
-
# Mail::Multibyte.mb_chars('Café périferôl').index('ô') # => 12
|
149
|
-
# Mail::Multibyte.mb_chars('Café périferôl').index(/\w/u) # => 0
|
150
|
-
def index(needle, offset=0)
|
151
|
-
wrapped_offset = first(offset).wrapped_string.length
|
152
|
-
index = @wrapped_string.index(needle, wrapped_offset)
|
153
|
-
index ? (Unicode.u_unpack(@wrapped_string.slice(0...index)).size) : nil
|
154
|
-
end
|
155
|
-
|
156
|
-
# Returns the position _needle_ in the string, counting in
|
157
|
-
# codepoints, searching backward from _offset_ or the end of the
|
158
|
-
# string. Returns +nil+ if _needle_ isn't found.
|
159
|
-
#
|
160
|
-
# Example:
|
161
|
-
# Mail::Multibyte.mb_chars('Café périferôl').rindex('é') # => 6
|
162
|
-
# Mail::Multibyte.mb_chars('Café périferôl').rindex(/\w/u) # => 13
|
163
|
-
def rindex(needle, offset=nil)
|
164
|
-
offset ||= length
|
165
|
-
wrapped_offset = first(offset).wrapped_string.length
|
166
|
-
index = @wrapped_string.rindex(needle, wrapped_offset)
|
167
|
-
index ? (Unicode.u_unpack(@wrapped_string.slice(0...index)).size) : nil
|
168
|
-
end
|
169
|
-
|
170
|
-
# Returns the number of codepoints in the string
|
171
|
-
def size
|
172
|
-
Unicode.u_unpack(@wrapped_string).size
|
173
|
-
end
|
174
|
-
alias_method :length, :size
|
175
|
-
|
176
|
-
# Strips entire range of Unicode whitespace from the right of the string.
|
177
|
-
def rstrip
|
178
|
-
chars(@wrapped_string.gsub(Unicode::TRAILERS_PAT, ''))
|
179
|
-
end
|
180
|
-
|
181
|
-
# Strips entire range of Unicode whitespace from the left of the string.
|
182
|
-
def lstrip
|
183
|
-
chars(@wrapped_string.gsub(Unicode::LEADERS_PAT, ''))
|
184
|
-
end
|
185
|
-
|
186
|
-
# Strips entire range of Unicode whitespace from the right and left of the string.
|
187
|
-
def strip
|
188
|
-
rstrip.lstrip
|
189
|
-
end
|
190
|
-
|
191
|
-
# Returns the codepoint of the first character in the string.
|
192
|
-
#
|
193
|
-
# Example:
|
194
|
-
# Mail::Multibyte.mb_chars('こんにちは').ord # => 12371
|
195
|
-
def ord
|
196
|
-
Unicode.u_unpack(@wrapped_string)[0]
|
197
|
-
end
|
198
|
-
|
199
|
-
# Works just like <tt>String#rjust</tt>, only integer specifies characters instead of bytes.
|
200
|
-
#
|
201
|
-
# Example:
|
202
|
-
#
|
203
|
-
# Mail::Multibyte.mb_chars("¾ cup").rjust(8).to_s
|
204
|
-
# # => " ¾ cup"
|
205
|
-
#
|
206
|
-
# Mail::Multibyte.mb_chars("¾ cup").rjust(8, " ").to_s # Use non-breaking whitespace
|
207
|
-
# # => " ¾ cup"
|
208
|
-
def rjust(integer, padstr=' ')
|
209
|
-
justify(integer, :right, padstr)
|
210
|
-
end
|
211
|
-
|
212
|
-
# Works just like <tt>String#ljust</tt>, only integer specifies characters instead of bytes.
|
213
|
-
#
|
214
|
-
# Example:
|
215
|
-
#
|
216
|
-
# Mail::Multibyte.mb_chars("¾ cup").rjust(8).to_s
|
217
|
-
# # => "¾ cup "
|
218
|
-
#
|
219
|
-
# Mail::Multibyte.mb_chars("¾ cup").rjust(8, " ").to_s # Use non-breaking whitespace
|
220
|
-
# # => "¾ cup "
|
221
|
-
def ljust(integer, padstr=' ')
|
222
|
-
justify(integer, :left, padstr)
|
223
|
-
end
|
224
|
-
|
225
|
-
# Works just like <tt>String#center</tt>, only integer specifies characters instead of bytes.
|
226
|
-
#
|
227
|
-
# Example:
|
228
|
-
#
|
229
|
-
# Mail::Multibyte.mb_chars("¾ cup").center(8).to_s
|
230
|
-
# # => " ¾ cup "
|
231
|
-
#
|
232
|
-
# Mail::Multibyte.mb_chars("¾ cup").center(8, " ").to_s # Use non-breaking whitespace
|
233
|
-
# # => " ¾ cup "
|
234
|
-
def center(integer, padstr=' ')
|
235
|
-
justify(integer, :center, padstr)
|
236
|
-
end
|
237
|
-
|
238
|
-
else
|
239
|
-
def =~(other)
|
240
|
-
@wrapped_string =~ other
|
241
|
-
end
|
82
|
+
def =~(other)
|
83
|
+
@wrapped_string =~ other
|
242
84
|
end
|
243
85
|
|
244
86
|
# Works just like <tt>String#split</tt>, with the exception that the items in the resulting list are Chars
|
@@ -331,7 +173,7 @@ module Mail #:nodoc:
|
|
331
173
|
#
|
332
174
|
# Example:
|
333
175
|
# s = 'こんにちは'
|
334
|
-
# s.mb_chars.limit(7) # => "
|
176
|
+
# s.mb_chars.limit(7) # => "こん"
|
335
177
|
def limit(limit)
|
336
178
|
slice(0...translate_offset(limit))
|
337
179
|
end
|
@@ -419,7 +261,7 @@ module Mail #:nodoc:
|
|
419
261
|
# exclude lstrip!, rstrip! and strip! because they are already work as expected on multibyte strings.
|
420
262
|
if public_method_defined?(method)
|
421
263
|
define_method("#{method}!") do |*args|
|
422
|
-
@wrapped_string = send(
|
264
|
+
@wrapped_string = send(method, *args).to_s
|
423
265
|
self
|
424
266
|
end
|
425
267
|
end
|
data/lib/mail/multibyte/utils.rb
CHANGED
@@ -3,59 +3,42 @@
|
|
3
3
|
|
4
4
|
module Mail #:nodoc:
|
5
5
|
module Multibyte #:nodoc:
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
VALID_CHARACTER[Encoding.default_external.to_s]
|
10
|
-
end
|
11
|
-
else
|
12
|
-
def self.valid_character
|
13
|
-
case $KCODE
|
14
|
-
when 'UTF8'
|
15
|
-
VALID_CHARACTER['UTF-8']
|
16
|
-
when 'SJIS'
|
17
|
-
VALID_CHARACTER['Shift_JIS']
|
18
|
-
end
|
19
|
-
end
|
6
|
+
# Returns a regular expression that matches valid characters in the current encoding
|
7
|
+
def self.valid_character
|
8
|
+
VALID_CHARACTER[Encoding.default_external.to_s]
|
20
9
|
end
|
21
10
|
|
22
|
-
if
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
string.split(//).all? { |c| expression =~ c }
|
32
|
-
else
|
33
|
-
true
|
34
|
-
end
|
11
|
+
# Returns true if string has valid utf-8 encoding
|
12
|
+
def self.is_utf8?(string)
|
13
|
+
case string.encoding
|
14
|
+
when Encoding::UTF_8
|
15
|
+
verify(string)
|
16
|
+
when Encoding::ASCII_8BIT, Encoding::US_ASCII
|
17
|
+
verify(to_utf8(string))
|
18
|
+
else
|
19
|
+
false
|
35
20
|
end
|
36
21
|
end
|
37
22
|
|
23
|
+
# Verifies the encoding of a string
|
24
|
+
def self.verify(string)
|
25
|
+
string.valid_encoding?
|
26
|
+
end
|
27
|
+
|
38
28
|
# Verifies the encoding of the string and raises an exception when it's not valid
|
39
29
|
def self.verify!(string)
|
40
30
|
raise EncodingError.new("Found characters with invalid encoding") unless verify(string)
|
41
31
|
end
|
42
32
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
if expression = valid_character
|
53
|
-
# Splits the string on character boundaries, which are determined based on $KCODE.
|
54
|
-
string.split(//).grep(expression).join
|
55
|
-
else
|
56
|
-
string
|
57
|
-
end
|
58
|
-
end
|
33
|
+
# Removes all invalid characters from the string.
|
34
|
+
#
|
35
|
+
# Note: this method is a no-op in Ruby 1.9
|
36
|
+
def self.clean(string)
|
37
|
+
string
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.to_utf8(string)
|
41
|
+
string.dup.force_encoding(Encoding::UTF_8)
|
59
42
|
end
|
60
43
|
end
|
61
44
|
end
|
data/lib/mail/multibyte.rb
CHANGED
@@ -19,7 +19,6 @@ module Mail #:nodoc:
|
|
19
19
|
|
20
20
|
self.proxy_class = Mail::Multibyte::Chars
|
21
21
|
|
22
|
-
if RUBY_VERSION >= "1.9"
|
23
22
|
# == Multibyte proxy
|
24
23
|
#
|
25
24
|
# +mb_chars+ is a multibyte safe proxy for string methods.
|
@@ -54,21 +53,12 @@ module Mail #:nodoc:
|
|
54
53
|
# For more information about the methods defined on the Chars proxy see Mail::Multibyte::Chars. For
|
55
54
|
# information about how to change the default Multibyte behaviour see Mail::Multibyte.
|
56
55
|
def self.mb_chars(str)
|
57
|
-
if
|
56
|
+
if is_utf8?(str)
|
58
57
|
proxy_class.new(str)
|
59
58
|
else
|
60
59
|
str
|
61
60
|
end
|
62
61
|
end
|
63
|
-
else
|
64
|
-
def self.mb_chars(str)
|
65
|
-
if proxy_class.wants?(str)
|
66
|
-
proxy_class.new(str)
|
67
|
-
else
|
68
|
-
str
|
69
|
-
end
|
70
|
-
end
|
71
|
-
end
|
72
62
|
|
73
63
|
# Regular expressions that describe valid byte sequences for a character
|
74
64
|
VALID_CHARACTER = {
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
module Mail
|
3
2
|
|
3
|
+
module Mail
|
4
4
|
# A delivery method implementation which sends via exim.
|
5
5
|
#
|
6
6
|
# To use this, first find out where the exim binary is on your computer,
|
@@ -39,11 +39,12 @@ module Mail
|
|
39
39
|
class Exim < Sendmail
|
40
40
|
DEFAULTS = {
|
41
41
|
:location => '/usr/sbin/exim',
|
42
|
-
:arguments =>
|
42
|
+
:arguments => %w[ -i -t ]
|
43
43
|
}
|
44
44
|
|
45
|
-
|
46
|
-
|
45
|
+
# Uses -t option to extract recipients from the message.
|
46
|
+
def destinations_for(envelope)
|
47
|
+
nil
|
47
48
|
end
|
48
49
|
end
|
49
50
|
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
require 'mail/
|
2
|
+
require 'mail/smtp_envelope'
|
3
3
|
|
4
4
|
module Mail
|
5
5
|
# FileDelivery class delivers emails into multiple files based on the destination
|
@@ -13,20 +13,16 @@ module Mail
|
|
13
13
|
# Make sure the path you specify with :location is writable by the Ruby process
|
14
14
|
# running Mail.
|
15
15
|
class FileDelivery
|
16
|
-
|
17
|
-
require 'fileutils'
|
18
|
-
else
|
19
|
-
require 'ftools'
|
20
|
-
end
|
16
|
+
require 'fileutils'
|
21
17
|
|
22
18
|
attr_accessor :settings
|
23
19
|
|
24
20
|
def initialize(values)
|
25
|
-
self.settings = { :location => './mails' }.merge!(values)
|
21
|
+
self.settings = { :location => './mails', :extension => '' }.merge!(values)
|
26
22
|
end
|
27
23
|
|
28
24
|
def deliver!(mail)
|
29
|
-
Mail::
|
25
|
+
envelope = Mail::SmtpEnvelope.new(mail)
|
30
26
|
|
31
27
|
if ::File.respond_to?(:makedirs)
|
32
28
|
::File.makedirs settings[:location]
|
@@ -34,8 +30,13 @@ module Mail
|
|
34
30
|
::FileUtils.mkdir_p settings[:location]
|
35
31
|
end
|
36
32
|
|
37
|
-
|
38
|
-
::File.
|
33
|
+
envelope.to.uniq.each do |to|
|
34
|
+
path = ::File.join(settings[:location], File.basename(to.to_s+settings[:extension]))
|
35
|
+
|
36
|
+
::File.open(path, 'a') do |f|
|
37
|
+
f.write envelope.message
|
38
|
+
f.write "\r\n\r\n"
|
39
|
+
end
|
39
40
|
end
|
40
41
|
end
|
41
42
|
end
|