mail 2.4.4 → 2.5.5
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 +140 -1
- data/CONTRIBUTING.md +4 -4
- data/Gemfile +14 -8
- data/MIT-LICENSE +20 -0
- data/README.md +24 -23
- data/Rakefile +3 -22
- data/lib/VERSION +2 -2
- data/lib/load_parsers.rb +35 -0
- data/lib/mail/attachments_list.rb +2 -2
- data/lib/mail/body.rb +5 -5
- data/lib/mail/check_delivery_params.rb +57 -0
- data/lib/mail/configuration.rb +1 -1
- data/lib/mail/core_extensions/nil.rb +4 -2
- data/lib/mail/core_extensions/object.rb +8 -8
- data/lib/mail/core_extensions/smtp.rb +12 -13
- data/lib/mail/core_extensions/string.rb +4 -4
- data/lib/mail/elements/address.rb +13 -5
- data/lib/mail/elements/envelope_from_element.rb +15 -2
- data/lib/mail/elements.rb +12 -12
- data/lib/mail/encodings/quoted_printable.rb +4 -3
- data/lib/mail/encodings.rb +66 -35
- data/lib/mail/field.rb +76 -99
- data/lib/mail/fields/bcc_field.rb +2 -2
- data/lib/mail/fields/cc_field.rb +2 -2
- data/lib/mail/fields/comments_field.rb +1 -1
- data/lib/mail/fields/common/common_address.rb +19 -4
- data/lib/mail/fields/common/common_field.rb +8 -2
- data/lib/mail/fields/common/common_message_id.rb +9 -5
- data/lib/mail/fields/content_disposition_field.rb +1 -0
- data/lib/mail/fields/content_id_field.rb +1 -2
- data/lib/mail/fields/content_transfer_encoding_field.rb +2 -2
- data/lib/mail/fields/content_type_field.rb +5 -2
- data/lib/mail/fields/date_field.rb +14 -14
- data/lib/mail/fields/from_field.rb +2 -2
- data/lib/mail/fields/in_reply_to_field.rb +2 -1
- data/lib/mail/fields/keywords_field.rb +1 -1
- data/lib/mail/fields/message_id_field.rb +2 -3
- data/lib/mail/fields/references_field.rb +2 -1
- data/lib/mail/fields/reply_to_field.rb +2 -2
- data/lib/mail/fields/resent_bcc_field.rb +2 -2
- data/lib/mail/fields/resent_cc_field.rb +2 -2
- data/lib/mail/fields/resent_from_field.rb +2 -2
- data/lib/mail/fields/resent_sender_field.rb +2 -2
- data/lib/mail/fields/resent_to_field.rb +2 -2
- data/lib/mail/fields/sender_field.rb +7 -7
- data/lib/mail/fields/to_field.rb +2 -2
- data/lib/mail/fields/unstructured_field.rb +34 -27
- data/lib/mail/fields.rb +32 -32
- data/lib/mail/header.rb +37 -14
- data/lib/mail/message.rb +140 -45
- data/lib/mail/multibyte/chars.rb +4 -4
- data/lib/mail/multibyte/unicode.rb +8 -0
- data/lib/mail/network/delivery_methods/exim.rb +6 -11
- data/lib/mail/network/delivery_methods/file_delivery.rb +7 -6
- data/lib/mail/network/delivery_methods/sendmail.rb +40 -11
- data/lib/mail/network/delivery_methods/smtp.rb +33 -47
- data/lib/mail/network/delivery_methods/smtp_connection.rb +7 -24
- data/lib/mail/network/delivery_methods/test_mailer.rb +9 -8
- data/lib/mail/network/retriever_methods/imap.rb +14 -6
- data/lib/mail/network/retriever_methods/pop3.rb +2 -2
- data/lib/mail/network/retriever_methods/test_retriever.rb +11 -15
- data/lib/mail/network.rb +9 -9
- data/lib/mail/parsers/content_transfer_encoding.rb +81 -42
- data/lib/mail/parsers/content_transfer_encoding.treetop +4 -6
- data/lib/mail/parsers/content_type.rb +16 -12
- data/lib/mail/parsers/content_type.treetop +2 -2
- data/lib/mail/parsers/rfc2045.rb +12 -55
- data/lib/mail/parsers/rfc2045.treetop +1 -2
- data/lib/mail/parsers/rfc2822.rb +127 -71
- data/lib/mail/parsers/rfc2822.treetop +22 -24
- data/lib/mail/part.rb +6 -2
- data/lib/mail/parts_list.rb +1 -1
- data/lib/mail/patterns.rb +1 -1
- data/lib/mail/utilities.rb +25 -17
- data/lib/mail/values/unicode_tables.dat +0 -0
- data/lib/mail/version_specific/ruby_1_8.rb +23 -2
- data/lib/mail/version_specific/ruby_1_9.rb +55 -21
- data/lib/mail.rb +18 -18
- metadata +89 -37
- data/Gemfile.lock +0 -36
- data/lib/mail/core_extensions/shell_escape.rb +0 -56
data/lib/mail/fields.rb
CHANGED
@@ -1,35 +1,35 @@
|
|
1
1
|
module Mail
|
2
|
-
|
3
|
-
|
4
|
-
|
2
|
+
register_autoload :UnstructuredField, 'mail/fields/unstructured_field'
|
3
|
+
register_autoload :StructuredField, 'mail/fields/structured_field'
|
4
|
+
register_autoload :OptionalField, 'mail/fields/optional_field'
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
6
|
+
register_autoload :BccField, 'mail/fields/bcc_field'
|
7
|
+
register_autoload :CcField, 'mail/fields/cc_field'
|
8
|
+
register_autoload :CommentsField, 'mail/fields/comments_field'
|
9
|
+
register_autoload :ContentDescriptionField, 'mail/fields/content_description_field'
|
10
|
+
register_autoload :ContentDispositionField, 'mail/fields/content_disposition_field'
|
11
|
+
register_autoload :ContentIdField, 'mail/fields/content_id_field'
|
12
|
+
register_autoload :ContentLocationField, 'mail/fields/content_location_field'
|
13
|
+
register_autoload :ContentTransferEncodingField, 'mail/fields/content_transfer_encoding_field'
|
14
|
+
register_autoload :ContentTypeField, 'mail/fields/content_type_field'
|
15
|
+
register_autoload :DateField, 'mail/fields/date_field'
|
16
|
+
register_autoload :FromField, 'mail/fields/from_field'
|
17
|
+
register_autoload :InReplyToField, 'mail/fields/in_reply_to_field'
|
18
|
+
register_autoload :KeywordsField, 'mail/fields/keywords_field'
|
19
|
+
register_autoload :MessageIdField, 'mail/fields/message_id_field'
|
20
|
+
register_autoload :MimeVersionField, 'mail/fields/mime_version_field'
|
21
|
+
register_autoload :ReceivedField, 'mail/fields/received_field'
|
22
|
+
register_autoload :ReferencesField, 'mail/fields/references_field'
|
23
|
+
register_autoload :ReplyToField, 'mail/fields/reply_to_field'
|
24
|
+
register_autoload :ResentBccField, 'mail/fields/resent_bcc_field'
|
25
|
+
register_autoload :ResentCcField, 'mail/fields/resent_cc_field'
|
26
|
+
register_autoload :ResentDateField, 'mail/fields/resent_date_field'
|
27
|
+
register_autoload :ResentFromField, 'mail/fields/resent_from_field'
|
28
|
+
register_autoload :ResentMessageIdField, 'mail/fields/resent_message_id_field'
|
29
|
+
register_autoload :ResentSenderField, 'mail/fields/resent_sender_field'
|
30
|
+
register_autoload :ResentToField, 'mail/fields/resent_to_field'
|
31
|
+
register_autoload :ReturnPathField, 'mail/fields/return_path_field'
|
32
|
+
register_autoload :SenderField, 'mail/fields/sender_field'
|
33
|
+
register_autoload :SubjectField, 'mail/fields/subject_field'
|
34
|
+
register_autoload :ToField, 'mail/fields/to_field'
|
35
35
|
end
|
data/lib/mail/header.rb
CHANGED
@@ -21,6 +21,20 @@ module Mail
|
|
21
21
|
include Utilities
|
22
22
|
include Enumerable
|
23
23
|
|
24
|
+
@@maximum_amount = 1000
|
25
|
+
|
26
|
+
# Large amount of headers in Email might create extra high CPU load
|
27
|
+
# Use this parameter to limit number of headers that will be parsed by
|
28
|
+
# mail library.
|
29
|
+
# Default: 1000
|
30
|
+
def self.maximum_amount
|
31
|
+
@@maximum_amount
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.maximum_amount=(value)
|
35
|
+
@@maximum_amount = value
|
36
|
+
end
|
37
|
+
|
24
38
|
# Creates a new header object.
|
25
39
|
#
|
26
40
|
# Accepts raw text or nothing. If given raw text will attempt to parse
|
@@ -36,7 +50,7 @@ module Mail
|
|
36
50
|
def initialize(header_text = nil, charset = nil)
|
37
51
|
@errors = []
|
38
52
|
@charset = charset
|
39
|
-
self.raw_source = header_text.to_crlf
|
53
|
+
self.raw_source = header_text.to_crlf.lstrip
|
40
54
|
split_header if header_text
|
41
55
|
end
|
42
56
|
|
@@ -73,14 +87,12 @@ module Mail
|
|
73
87
|
# h.fields = ['From: mikel@me.com', 'To: bob@you.com']
|
74
88
|
def fields=(unfolded_fields)
|
75
89
|
@fields = Mail::FieldList.new
|
76
|
-
warn "Warning: more than
|
77
|
-
unfolded_fields[0..
|
90
|
+
warn "Warning: more than #{self.class.maximum_amount} header fields only using the first #{self.class.maximum_amount}" if unfolded_fields.length > self.class.maximum_amount
|
91
|
+
unfolded_fields[0..(self.class.maximum_amount-1)].each do |field|
|
78
92
|
|
79
93
|
field = Field.new(field, nil, charset)
|
80
94
|
field.errors.each { |error| self.errors << error }
|
81
|
-
selected = select_field_for(field.name)
|
82
|
-
|
83
|
-
if selected.any? && limited_field?(field.name)
|
95
|
+
if limited_field?(field.name) && (selected = select_field_for(field.name)) && selected.any?
|
84
96
|
selected.first.update(field.name, field.value)
|
85
97
|
else
|
86
98
|
@fields << field
|
@@ -142,6 +154,9 @@ module Mail
|
|
142
154
|
# h['X-Mail-SPAM'] # => nil
|
143
155
|
def []=(name, value)
|
144
156
|
name = dasherize(name)
|
157
|
+
if name.include?(':')
|
158
|
+
raise ArgumentError, "Header names may not contain a colon: #{name.inspect}"
|
159
|
+
end
|
145
160
|
fn = name.downcase
|
146
161
|
selected = select_field_for(fn)
|
147
162
|
|
@@ -159,15 +174,15 @@ module Mail
|
|
159
174
|
# Need to insert in correct order for trace fields
|
160
175
|
self.fields << Field.new(name.to_s, value, charset)
|
161
176
|
end
|
177
|
+
if dasherize(fn) == "content-type"
|
178
|
+
# Update charset if specified in Content-Type
|
179
|
+
params = self[:content_type].parameters rescue nil
|
180
|
+
@charset = params && params[:charset]
|
181
|
+
end
|
162
182
|
end
|
163
183
|
|
164
184
|
def charset
|
165
|
-
|
166
|
-
if params
|
167
|
-
params[:charset]
|
168
|
-
else
|
169
|
-
@charset
|
170
|
-
end
|
185
|
+
@charset
|
171
186
|
end
|
172
187
|
|
173
188
|
def charset=(val)
|
@@ -186,6 +201,7 @@ module Mail
|
|
186
201
|
|
187
202
|
def encoded
|
188
203
|
buffer = ''
|
204
|
+
buffer.force_encoding('us-ascii') if buffer.respond_to?(:force_encoding)
|
189
205
|
fields.each do |field|
|
190
206
|
buffer << field.encoded
|
191
207
|
end
|
@@ -254,12 +270,19 @@ module Mail
|
|
254
270
|
end
|
255
271
|
|
256
272
|
def select_field_for(name)
|
257
|
-
fields.select { |f| f.responsible_for?(name
|
273
|
+
fields.select { |f| f.responsible_for?(name) }
|
258
274
|
end
|
259
275
|
|
260
276
|
def limited_field?(name)
|
261
277
|
LIMITED_FIELDS.include?(name.to_s.downcase)
|
262
278
|
end
|
263
|
-
|
279
|
+
|
280
|
+
# Enumerable support; yield each field in order to the block if there is one,
|
281
|
+
# or return an Enumerator for them if there isn't.
|
282
|
+
def each( &block )
|
283
|
+
return self.fields.each( &block ) if block
|
284
|
+
self.fields.each
|
285
|
+
end
|
286
|
+
|
264
287
|
end
|
265
288
|
end
|
data/lib/mail/message.rb
CHANGED
@@ -108,6 +108,9 @@ module Mail
|
|
108
108
|
@charset = 'UTF-8'
|
109
109
|
@defaulted_charset = true
|
110
110
|
|
111
|
+
@smtp_envelope_from = nil
|
112
|
+
@smtp_envelope_to = nil
|
113
|
+
|
111
114
|
@perform_deliveries = true
|
112
115
|
@raise_delivery_errors = true
|
113
116
|
|
@@ -122,7 +125,7 @@ module Mail
|
|
122
125
|
if args.flatten.first.respond_to?(:each_pair)
|
123
126
|
init_with_hash(args.flatten.first)
|
124
127
|
else
|
125
|
-
init_with_string(args.flatten[0].to_s
|
128
|
+
init_with_string(args.flatten[0].to_s)
|
126
129
|
end
|
127
130
|
|
128
131
|
if block_given?
|
@@ -169,7 +172,7 @@ module Mail
|
|
169
172
|
# obj.mail.deliver
|
170
173
|
#
|
171
174
|
# Would cause Mail to call obj.deliver_mail passing itself as a parameter,
|
172
|
-
# which then can just yield and let Mail do
|
175
|
+
# which then can just yield and let Mail do its own private do_delivery
|
173
176
|
# method.
|
174
177
|
attr_accessor :delivery_handler
|
175
178
|
|
@@ -938,8 +941,8 @@ module Mail
|
|
938
941
|
#
|
939
942
|
# Example:
|
940
943
|
#
|
941
|
-
# mail.
|
942
|
-
# mail.
|
944
|
+
# mail.resent_sender = 'Mikel <mikel@test.lindsaar.net>'
|
945
|
+
# mail.resent_sender #=> 'mikel@test.lindsaar.net'
|
943
946
|
def resent_sender=( val )
|
944
947
|
header[:resent_sender] = val
|
945
948
|
end
|
@@ -1023,6 +1026,82 @@ module Mail
|
|
1023
1026
|
header[:sender] = val
|
1024
1027
|
end
|
1025
1028
|
|
1029
|
+
# Returns the SMTP Envelope From value of the mail object, as a single
|
1030
|
+
# string of an address spec.
|
1031
|
+
#
|
1032
|
+
# Defaults to Return-Path, Sender, or the first From address.
|
1033
|
+
#
|
1034
|
+
# Example:
|
1035
|
+
#
|
1036
|
+
# mail.smtp_envelope_from = 'Mikel <mikel@test.lindsaar.net>'
|
1037
|
+
# mail.smtp_envelope_from #=> 'mikel@test.lindsaar.net'
|
1038
|
+
#
|
1039
|
+
# Also allows you to set the value by passing a value as a parameter
|
1040
|
+
#
|
1041
|
+
# Example:
|
1042
|
+
#
|
1043
|
+
# mail.smtp_envelope_from 'Mikel <mikel@test.lindsaar.net>'
|
1044
|
+
# mail.smtp_envelope_from #=> 'mikel@test.lindsaar.net'
|
1045
|
+
def smtp_envelope_from( val = nil )
|
1046
|
+
if val
|
1047
|
+
self.smtp_envelope_from = val
|
1048
|
+
else
|
1049
|
+
@smtp_envelope_from || return_path || sender || from_addrs.first
|
1050
|
+
end
|
1051
|
+
end
|
1052
|
+
|
1053
|
+
# Sets the From address on the SMTP Envelope.
|
1054
|
+
#
|
1055
|
+
# Example:
|
1056
|
+
#
|
1057
|
+
# mail.smtp_envelope_from = 'Mikel <mikel@test.lindsaar.net>'
|
1058
|
+
# mail.smtp_envelope_from #=> 'mikel@test.lindsaar.net'
|
1059
|
+
def smtp_envelope_from=( val )
|
1060
|
+
@smtp_envelope_from = val
|
1061
|
+
end
|
1062
|
+
|
1063
|
+
# Returns the SMTP Envelope To value of the mail object.
|
1064
|
+
#
|
1065
|
+
# Defaults to #destinations: To, Cc, and Bcc addresses.
|
1066
|
+
#
|
1067
|
+
# Example:
|
1068
|
+
#
|
1069
|
+
# mail.smtp_envelope_to = 'Mikel <mikel@test.lindsaar.net>'
|
1070
|
+
# mail.smtp_envelope_to #=> 'mikel@test.lindsaar.net'
|
1071
|
+
#
|
1072
|
+
# Also allows you to set the value by passing a value as a parameter
|
1073
|
+
#
|
1074
|
+
# Example:
|
1075
|
+
#
|
1076
|
+
# mail.smtp_envelope_to ['Mikel <mikel@test.lindsaar.net>', 'Lindsaar <lindsaar@test.lindsaar.net>']
|
1077
|
+
# mail.smtp_envelope_to #=> ['mikel@test.lindsaar.net', 'lindsaar@test.lindsaar.net']
|
1078
|
+
def smtp_envelope_to( val = nil )
|
1079
|
+
if val
|
1080
|
+
self.smtp_envelope_to = val
|
1081
|
+
else
|
1082
|
+
@smtp_envelope_to || destinations
|
1083
|
+
end
|
1084
|
+
end
|
1085
|
+
|
1086
|
+
# Sets the To addresses on the SMTP Envelope.
|
1087
|
+
#
|
1088
|
+
# Example:
|
1089
|
+
#
|
1090
|
+
# mail.smtp_envelope_to = 'Mikel <mikel@test.lindsaar.net>'
|
1091
|
+
# mail.smtp_envelope_to #=> 'mikel@test.lindsaar.net'
|
1092
|
+
#
|
1093
|
+
# mail.smtp_envelope_to = ['Mikel <mikel@test.lindsaar.net>', 'Lindsaar <lindsaar@test.lindsaar.net>']
|
1094
|
+
# mail.smtp_envelope_to #=> ['mikel@test.lindsaar.net', 'lindsaar@test.lindsaar.net']
|
1095
|
+
def smtp_envelope_to=( val )
|
1096
|
+
@smtp_envelope_to =
|
1097
|
+
case val
|
1098
|
+
when Array, NilClass
|
1099
|
+
val
|
1100
|
+
else
|
1101
|
+
[val]
|
1102
|
+
end
|
1103
|
+
end
|
1104
|
+
|
1026
1105
|
# Returns the decoded value of the subject field, as a single string.
|
1027
1106
|
#
|
1028
1107
|
# Example:
|
@@ -1411,7 +1490,7 @@ module Mail
|
|
1411
1490
|
|
1412
1491
|
# Returns the MIME media type of part we are on, this is taken from the content-type header
|
1413
1492
|
def mime_type
|
1414
|
-
|
1493
|
+
has_content_type? ? header[:content_type].string : nil rescue nil
|
1415
1494
|
end
|
1416
1495
|
|
1417
1496
|
def message_content_type
|
@@ -1422,7 +1501,7 @@ module Mail
|
|
1422
1501
|
# Returns the character set defined in the content type field
|
1423
1502
|
def charset
|
1424
1503
|
if @header
|
1425
|
-
|
1504
|
+
has_content_type? ? content_type_parameters['charset'] : @charset
|
1426
1505
|
else
|
1427
1506
|
@charset
|
1428
1507
|
end
|
@@ -1516,7 +1595,7 @@ module Mail
|
|
1516
1595
|
|
1517
1596
|
# Returns an AttachmentsList object, which holds all of the attachments in
|
1518
1597
|
# the receiver object (either the entier email or a part within) and all
|
1519
|
-
# of
|
1598
|
+
# of its descendants.
|
1520
1599
|
#
|
1521
1600
|
# It also allows you to add attachments to the mail object directly, like so:
|
1522
1601
|
#
|
@@ -1559,9 +1638,7 @@ module Mail
|
|
1559
1638
|
# Accessor for html_part
|
1560
1639
|
def html_part(&block)
|
1561
1640
|
if block_given?
|
1562
|
-
|
1563
|
-
add_multipart_alternate_header unless html_part.blank?
|
1564
|
-
add_part(@html_part)
|
1641
|
+
self.html_part = Mail::Part.new(:content_type => 'text/html', &block)
|
1565
1642
|
else
|
1566
1643
|
@html_part || find_first_mime_type('text/html')
|
1567
1644
|
end
|
@@ -1570,9 +1647,7 @@ module Mail
|
|
1570
1647
|
# Accessor for text_part
|
1571
1648
|
def text_part(&block)
|
1572
1649
|
if block_given?
|
1573
|
-
|
1574
|
-
add_multipart_alternate_header unless html_part.blank?
|
1575
|
-
add_part(@text_part)
|
1650
|
+
self.text_part = Mail::Part.new(:content_type => 'text/plain', &block)
|
1576
1651
|
else
|
1577
1652
|
@text_part || find_first_mime_type('text/plain')
|
1578
1653
|
end
|
@@ -1581,36 +1656,54 @@ module Mail
|
|
1581
1656
|
# Helper to add a html part to a multipart/alternative email. If this and
|
1582
1657
|
# text_part are both defined in a message, then it will be a multipart/alternative
|
1583
1658
|
# message and set itself that way.
|
1584
|
-
def html_part=(msg
|
1659
|
+
def html_part=(msg)
|
1660
|
+
# Assign the html part and set multipart/alternative if there's a text part.
|
1585
1661
|
if msg
|
1586
1662
|
@html_part = msg
|
1587
|
-
|
1588
|
-
|
1663
|
+
@html_part.content_type = 'text/html' unless @html_part.has_content_type?
|
1664
|
+
add_multipart_alternate_header if text_part
|
1665
|
+
add_part @html_part
|
1666
|
+
|
1667
|
+
# If nil, delete the html part and back out of multipart/alternative.
|
1668
|
+
elsif @html_part
|
1669
|
+
parts.delete_if { |p| p.object_id == @html_part.object_id }
|
1670
|
+
@html_part = nil
|
1671
|
+
if text_part
|
1672
|
+
self.content_type = nil
|
1673
|
+
body.boundary = nil
|
1674
|
+
end
|
1589
1675
|
end
|
1590
|
-
add_multipart_alternate_header unless text_part.blank?
|
1591
|
-
add_part(@html_part)
|
1592
1676
|
end
|
1593
1677
|
|
1594
1678
|
# Helper to add a text part to a multipart/alternative email. If this and
|
1595
1679
|
# html_part are both defined in a message, then it will be a multipart/alternative
|
1596
1680
|
# message and set itself that way.
|
1597
|
-
def text_part=(msg
|
1681
|
+
def text_part=(msg)
|
1682
|
+
# Assign the text part and set multipart/alternative if there's an html part.
|
1598
1683
|
if msg
|
1599
1684
|
@text_part = msg
|
1600
|
-
|
1601
|
-
|
1685
|
+
@text_part.content_type = 'text/plain' unless @text_part.has_content_type?
|
1686
|
+
add_multipart_alternate_header if html_part
|
1687
|
+
add_part @text_part
|
1688
|
+
|
1689
|
+
# If nil, delete the text part and back out of multipart/alternative.
|
1690
|
+
elsif @text_part
|
1691
|
+
parts.delete_if { |p| p.object_id == @text_part.object_id }
|
1692
|
+
@text_part = nil
|
1693
|
+
if html_part
|
1694
|
+
self.content_type = nil
|
1695
|
+
body.boundary = nil
|
1696
|
+
end
|
1602
1697
|
end
|
1603
|
-
add_multipart_alternate_header unless html_part.blank?
|
1604
|
-
add_part(@text_part)
|
1605
1698
|
end
|
1606
1699
|
|
1607
1700
|
# Adds a part to the parts list or creates the part list
|
1608
1701
|
def add_part(part)
|
1609
1702
|
if !body.multipart? && !self.body.decoded.blank?
|
1610
|
-
|
1611
|
-
|
1612
|
-
|
1613
|
-
|
1703
|
+
@text_part = Mail::Part.new('Content-Type: text/plain;')
|
1704
|
+
@text_part.body = body.decoded
|
1705
|
+
self.body << @text_part
|
1706
|
+
add_multipart_alternate_header
|
1614
1707
|
end
|
1615
1708
|
add_boundary
|
1616
1709
|
self.body << part
|
@@ -1646,7 +1739,7 @@ module Mail
|
|
1646
1739
|
# m.add_file(:filename => 'filename.png', :content => File.read('/path/to/file.jpg'))
|
1647
1740
|
#
|
1648
1741
|
# 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
|
1742
|
+
# to a MIME multipart email, moving whatever plain text body you had into its own text
|
1650
1743
|
# plain part.
|
1651
1744
|
#
|
1652
1745
|
# Example:
|
@@ -1683,7 +1776,7 @@ module Mail
|
|
1683
1776
|
self.body << text_part
|
1684
1777
|
end
|
1685
1778
|
|
1686
|
-
# Encodes the message, calls encode on all
|
1779
|
+
# Encodes the message, calls encode on all its parts, gets an email message
|
1687
1780
|
# ready to send
|
1688
1781
|
def ready_to_send!
|
1689
1782
|
identify_and_set_transfer_encoding
|
@@ -1875,15 +1968,13 @@ module Mail
|
|
1875
1968
|
# Additionally, I allow for the case where someone might have put whitespace
|
1876
1969
|
# on the "gap line"
|
1877
1970
|
def parse_message
|
1878
|
-
header_part, body_part = raw_source.split(/#{CRLF}#{WSP}*#{CRLF}/m, 2)
|
1879
|
-
# index = raw_source.index(/#{CRLF}#{WSP}*#{CRLF}/m, 2)
|
1880
|
-
# self.header = (index) ? header_part[0,index] : nil
|
1881
|
-
# lazy_body ( [raw_source, index+1])
|
1971
|
+
header_part, body_part = raw_source.lstrip.split(/#{CRLF}#{CRLF}|#{CRLF}#{WSP}*#{CRLF}(?!#{WSP})/m, 2)
|
1882
1972
|
self.header = header_part
|
1883
1973
|
self.body = body_part
|
1884
1974
|
end
|
1885
1975
|
|
1886
1976
|
def raw_source=(value)
|
1977
|
+
value.force_encoding("binary") if RUBY_VERSION >= "1.9.1"
|
1887
1978
|
@raw_source = value.to_crlf
|
1888
1979
|
end
|
1889
1980
|
|
@@ -1906,17 +1997,18 @@ module Mail
|
|
1906
1997
|
|
1907
1998
|
|
1908
1999
|
def process_body_raw
|
1909
|
-
|
1910
|
-
|
1911
|
-
|
2000
|
+
@body = Mail::Body.new(@body_raw)
|
2001
|
+
@body_raw = nil
|
2002
|
+
separate_parts if @separate_parts
|
1912
2003
|
|
1913
|
-
|
2004
|
+
add_encoding_to_body
|
1914
2005
|
end
|
1915
2006
|
|
1916
2007
|
def set_envelope_header
|
1917
|
-
|
2008
|
+
raw_string = raw_source.to_s
|
2009
|
+
if match_data = raw_source.to_s.match(/\AFrom\s(#{TEXT}+)#{CRLF}/m)
|
1918
2010
|
set_envelope(match_data[1])
|
1919
|
-
self.raw_source = match_data[
|
2011
|
+
self.raw_source = raw_string.sub(match_data[0], "")
|
1920
2012
|
end
|
1921
2013
|
end
|
1922
2014
|
|
@@ -1939,16 +2031,19 @@ module Mail
|
|
1939
2031
|
end
|
1940
2032
|
|
1941
2033
|
def add_required_fields
|
1942
|
-
|
1943
|
-
|
1944
|
-
add_message_id unless (has_message_id? || self.class == Mail::Part)
|
1945
|
-
add_date unless has_date?
|
1946
|
-
add_mime_version unless has_mime_version?
|
2034
|
+
add_required_message_fields
|
2035
|
+
add_multipart_mixed_header if body.multipart?
|
1947
2036
|
add_content_type unless has_content_type?
|
1948
2037
|
add_charset unless has_charset?
|
1949
2038
|
add_content_transfer_encoding unless has_content_transfer_encoding?
|
1950
2039
|
end
|
1951
2040
|
|
2041
|
+
def add_required_message_fields
|
2042
|
+
add_date unless has_date?
|
2043
|
+
add_mime_version unless has_mime_version?
|
2044
|
+
add_message_id unless has_message_id?
|
2045
|
+
end
|
2046
|
+
|
1952
2047
|
def add_multipart_alternate_header
|
1953
2048
|
header['content-type'] = ContentTypeField.with_boundary('multipart/alternative').value
|
1954
2049
|
header['content_type'].parameters[:charset] = @charset
|
@@ -2047,7 +2142,7 @@ module Mail
|
|
2047
2142
|
else
|
2048
2143
|
if encoding = Encoding.find(charset) rescue nil
|
2049
2144
|
body_text.force_encoding(encoding)
|
2050
|
-
return body_text.encode(Encoding::UTF_8)
|
2145
|
+
return body_text.encode(Encoding::UTF_8, :undef => :replace, :invalid => :replace, :replace => '')
|
2051
2146
|
end
|
2052
2147
|
end
|
2053
2148
|
end
|
data/lib/mail/multibyte/chars.rb
CHANGED
@@ -339,7 +339,7 @@ module Mail #:nodoc:
|
|
339
339
|
# Example:
|
340
340
|
# 'Laurent, où sont les tests ?'.mb_chars.upcase.to_s # => "LAURENT, OÙ SONT LES TESTS ?"
|
341
341
|
def upcase
|
342
|
-
chars(Unicode.apply_mapping(@wrapped_string
|
342
|
+
chars(Unicode.apply_mapping(@wrapped_string, :uppercase_mapping))
|
343
343
|
end
|
344
344
|
|
345
345
|
# Convert characters in the string to lowercase.
|
@@ -347,7 +347,7 @@ module Mail #:nodoc:
|
|
347
347
|
# Example:
|
348
348
|
# 'VĚDA A VÝZKUM'.mb_chars.downcase.to_s # => "věda a výzkum"
|
349
349
|
def downcase
|
350
|
-
chars(Unicode.apply_mapping(@wrapped_string
|
350
|
+
chars(Unicode.apply_mapping(@wrapped_string, :lowercase_mapping))
|
351
351
|
end
|
352
352
|
|
353
353
|
# Converts the first character to uppercase and the remainder to lowercase.
|
@@ -364,7 +364,7 @@ module Mail #:nodoc:
|
|
364
364
|
# "ÉL QUE SE ENTERÓ".mb_chars.titleize # => "Él Que Se Enteró"
|
365
365
|
# "日本語".mb_chars.titleize # => "日本語"
|
366
366
|
def titleize
|
367
|
-
chars(downcase.to_s.gsub(/\b('
|
367
|
+
chars(downcase.to_s.gsub(/\b('?\S)/u) { Unicode.apply_mapping $1, :uppercase_mapping })
|
368
368
|
end
|
369
369
|
alias_method :titlecase, :titleize
|
370
370
|
|
@@ -412,7 +412,7 @@ module Mail #:nodoc:
|
|
412
412
|
chars(Unicode.tidy_bytes(@wrapped_string, force))
|
413
413
|
end
|
414
414
|
|
415
|
-
|
415
|
+
%w(capitalize downcase lstrip reverse rstrip slice strip tidy_bytes upcase).each do |method|
|
416
416
|
# Only define a corresponding bang method for methods defined in the proxy; On 1.9 the proxy will
|
417
417
|
# exclude lstrip!, rstrip! and strip! because they are already work as expected on multibyte strings.
|
418
418
|
if public_method_defined?(method)
|
@@ -36,18 +36,13 @@ module Mail
|
|
36
36
|
#
|
37
37
|
# mail.deliver!
|
38
38
|
class Exim < Sendmail
|
39
|
+
DEFAULTS = {
|
40
|
+
:location => '/usr/sbin/exim',
|
41
|
+
:arguments => '-i -t'
|
42
|
+
}
|
39
43
|
|
40
|
-
def
|
41
|
-
|
42
|
-
:arguments => '-i -t' }.merge(values)
|
44
|
+
def self.call(path, arguments, destinations, encoded_message)
|
45
|
+
super path, arguments, nil, encoded_message
|
43
46
|
end
|
44
|
-
|
45
|
-
def self.call(path, arguments, mail)
|
46
|
-
IO.popen("#{path} #{arguments}", "w+") do |io|
|
47
|
-
io.puts mail.encoded.to_lf
|
48
|
-
io.flush
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
47
|
end
|
53
48
|
end
|
@@ -1,5 +1,6 @@
|
|
1
|
+
require 'mail/check_delivery_params'
|
2
|
+
|
1
3
|
module Mail
|
2
|
-
|
3
4
|
# FileDelivery class delivers emails into multiple files based on the destination
|
4
5
|
# address. Each file is appended to if it already exists.
|
5
6
|
#
|
@@ -11,20 +12,21 @@ module Mail
|
|
11
12
|
# Make sure the path you specify with :location is writable by the Ruby process
|
12
13
|
# running Mail.
|
13
14
|
class FileDelivery
|
14
|
-
|
15
15
|
if RUBY_VERSION >= '1.9.1'
|
16
16
|
require 'fileutils'
|
17
17
|
else
|
18
18
|
require 'ftools'
|
19
19
|
end
|
20
20
|
|
21
|
+
attr_accessor :settings
|
22
|
+
|
21
23
|
def initialize(values)
|
22
24
|
self.settings = { :location => './mails' }.merge!(values)
|
23
25
|
end
|
24
|
-
|
25
|
-
attr_accessor :settings
|
26
|
-
|
26
|
+
|
27
27
|
def deliver!(mail)
|
28
|
+
Mail::CheckDeliveryParams.check(mail)
|
29
|
+
|
28
30
|
if ::File.respond_to?(:makedirs)
|
29
31
|
::File.makedirs settings[:location]
|
30
32
|
else
|
@@ -35,6 +37,5 @@ module Mail
|
|
35
37
|
::File.open(::File.join(settings[:location], File.basename(to.to_s)), 'a') { |f| "#{f.write(mail.encoded)}\r\n\r\n" }
|
36
38
|
end
|
37
39
|
end
|
38
|
-
|
39
40
|
end
|
40
41
|
end
|