mail 2.6.6 → 2.8.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 +134 -119
- data/lib/mail/attachments_list.rb +10 -9
- data/lib/mail/body.rb +73 -84
- data/lib/mail/check_delivery_params.rb +28 -21
- data/lib/mail/configuration.rb +2 -0
- data/lib/mail/constants.rb +27 -5
- data/lib/mail/elements/address.rb +53 -47
- data/lib/mail/elements/address_list.rb +11 -19
- data/lib/mail/elements/content_disposition_element.rb +9 -16
- data/lib/mail/elements/content_location_element.rb +6 -11
- data/lib/mail/elements/content_transfer_encoding_element.rb +6 -11
- data/lib/mail/elements/content_type_element.rb +16 -23
- data/lib/mail/elements/date_time_element.rb +7 -15
- data/lib/mail/elements/envelope_from_element.rb +22 -23
- data/lib/mail/elements/message_ids_element.rb +18 -13
- data/lib/mail/elements/mime_version_element.rb +7 -15
- data/lib/mail/elements/phrase_list.rb +12 -10
- data/lib/mail/elements/received_element.rb +27 -19
- data/lib/mail/encodings/7bit.rb +9 -14
- data/lib/mail/encodings/8bit.rb +2 -21
- data/lib/mail/encodings/base64.rb +11 -12
- data/lib/mail/encodings/binary.rb +3 -22
- data/lib/mail/encodings/identity.rb +24 -0
- data/lib/mail/encodings/quoted_printable.rb +6 -6
- data/lib/mail/encodings/transfer_encoding.rb +38 -29
- data/lib/mail/encodings/unix_to_unix.rb +3 -1
- data/lib/mail/encodings.rb +81 -54
- data/lib/mail/envelope.rb +11 -14
- data/lib/mail/field.rb +119 -98
- 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 +50 -80
- data/lib/mail/fields/date_field.rb +23 -52
- 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 +9 -7
- data/lib/mail/fields/{common/parameter_hash.rb → parameter_hash.rb} +13 -11
- 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 -30
- 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 +32 -47
- data/lib/mail/header.rb +71 -110
- data/lib/mail/mail.rb +2 -10
- data/lib/mail/matchers/attachment_matchers.rb +15 -0
- data/lib/mail/matchers/has_sent_mail.rb +21 -1
- data/lib/mail/message.rb +113 -117
- data/lib/mail/multibyte/chars.rb +21 -178
- data/lib/mail/multibyte/unicode.rb +10 -10
- data/lib/mail/multibyte/utils.rb +26 -43
- data/lib/mail/multibyte.rb +55 -16
- 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 +34 -0
- data/lib/mail/network/delivery_methods/sendmail.rb +62 -21
- data/lib/mail/network/delivery_methods/smtp.rb +75 -50
- data/lib/mail/network/delivery_methods/smtp_connection.rb +3 -4
- 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 +20 -7
- data/lib/mail/network/retriever_methods/pop3.rb +5 -3
- data/lib/mail/network/retriever_methods/test_retriever.rb +2 -1
- data/lib/mail/network.rb +1 -0
- data/lib/mail/parser_tools.rb +15 -0
- data/lib/mail/parsers/address_lists_parser.rb +33225 -116
- data/lib/mail/parsers/address_lists_parser.rl +179 -0
- data/lib/mail/parsers/content_disposition_parser.rb +882 -49
- data/lib/mail/parsers/content_disposition_parser.rl +89 -0
- data/lib/mail/parsers/content_location_parser.rb +809 -23
- data/lib/mail/parsers/content_location_parser.rl +78 -0
- data/lib/mail/parsers/content_transfer_encoding_parser.rb +509 -21
- data/lib/mail/parsers/content_transfer_encoding_parser.rl +71 -0
- data/lib/mail/parsers/content_type_parser.rb +1037 -56
- data/lib/mail/parsers/content_type_parser.rl +90 -0
- data/lib/mail/parsers/date_time_parser.rb +877 -25
- data/lib/mail/parsers/date_time_parser.rl +69 -0
- data/lib/mail/parsers/envelope_from_parser.rb +3669 -40
- data/lib/mail/parsers/envelope_from_parser.rl +89 -0
- data/lib/mail/parsers/message_ids_parser.rb +5146 -25
- data/lib/mail/parsers/message_ids_parser.rl +93 -0
- data/lib/mail/parsers/mime_version_parser.rb +497 -26
- data/lib/mail/parsers/mime_version_parser.rl +68 -0
- data/lib/mail/parsers/phrase_lists_parser.rb +870 -22
- data/lib/mail/parsers/phrase_lists_parser.rl +90 -0
- data/lib/mail/parsers/received_parser.rb +8776 -43
- data/lib/mail/parsers/received_parser.rl +91 -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 +74 -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 +11 -25
- data/lib/mail/part.rb +6 -10
- data/lib/mail/parts_list.rb +62 -6
- data/lib/mail/smtp_envelope.rb +57 -0
- data/lib/mail/utilities.rb +343 -74
- data/lib/mail/version.rb +2 -2
- data/lib/mail/yaml.rb +30 -0
- data/lib/mail.rb +5 -35
- metadata +111 -66
- data/CHANGELOG.rdoc +0 -803
- data/CONTRIBUTING.md +0 -60
- data/Dependencies.txt +0 -2
- data/Gemfile +0 -14
- data/Rakefile +0 -29
- data/TODO.rdoc +0 -9
- data/lib/mail/core_extensions/smtp.rb +0 -25
- data/lib/mail/core_extensions/string/access.rb +0 -146
- data/lib/mail/core_extensions/string/multibyte.rb +0 -79
- data/lib/mail/core_extensions/string.rb +0 -21
- data/lib/mail/fields/common/address_container.rb +0 -17
- data/lib/mail/fields/common/common_address.rb +0 -136
- data/lib/mail/fields/common/common_date.rb +0 -36
- data/lib/mail/fields/common/common_field.rb +0 -61
- data/lib/mail/fields/common/common_message_id.rb +0 -49
- data/lib/mail/multibyte/exceptions.rb +0 -9
- data/lib/mail/parsers/ragel/common.rl +0 -185
- 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 -2149
- 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 -40
- data/lib/mail/parsers/ragel.rb +0 -18
- data/lib/mail/version_specific/ruby_1_8.rb +0 -126
- data/lib/mail/version_specific/ruby_1_9.rb +0 -226
data/lib/mail/body.rb
CHANGED
@@ -32,24 +32,29 @@ module Mail
|
|
32
32
|
@preamble = nil
|
33
33
|
@epilogue = nil
|
34
34
|
@charset = nil
|
35
|
-
@part_sort_order = [ "text/plain", "text/enriched", "text/html" ]
|
35
|
+
@part_sort_order = [ "text/plain", "text/enriched", "text/html", "multipart/alternative" ]
|
36
36
|
@parts = Mail::PartsList.new
|
37
37
|
if Utilities.blank?(string)
|
38
38
|
@raw_source = ''
|
39
39
|
else
|
40
40
|
# Do join first incase we have been given an Array in Ruby 1.9
|
41
41
|
if string.respond_to?(:join)
|
42
|
-
@raw_source = string.join('')
|
42
|
+
@raw_source = ::Mail::Utilities.to_crlf(string.join(''))
|
43
43
|
elsif string.respond_to?(:to_s)
|
44
|
-
@raw_source = string.to_s
|
44
|
+
@raw_source = ::Mail::Utilities.to_crlf(string.to_s)
|
45
45
|
else
|
46
46
|
raise "You can only assign a string or an object that responds_to? :join or :to_s to a body."
|
47
47
|
end
|
48
48
|
end
|
49
|
-
@encoding =
|
49
|
+
@encoding = default_encoding
|
50
50
|
set_charset
|
51
51
|
end
|
52
|
-
|
52
|
+
|
53
|
+
def init_with(coder)
|
54
|
+
coder.map.each { |k, v| instance_variable_set(:"@#{k}", v) }
|
55
|
+
@parts = Mail::PartsList.new(coder['parts'])
|
56
|
+
end
|
57
|
+
|
53
58
|
# Matches this body with another body. Also matches the decoded value of this
|
54
59
|
# body with a string.
|
55
60
|
#
|
@@ -115,8 +120,8 @@ module Mail
|
|
115
120
|
end
|
116
121
|
|
117
122
|
# Allows you to set the sort order of the parts, overriding the default sort order.
|
118
|
-
# Defaults to 'text/plain', then 'text/enriched', then 'text/html'
|
119
|
-
# type coming after.
|
123
|
+
# Defaults to 'text/plain', then 'text/enriched', then 'text/html', then 'multipart/alternative'
|
124
|
+
# with any other content type coming after.
|
120
125
|
def set_sort_order(order)
|
121
126
|
@part_sort_order = order
|
122
127
|
end
|
@@ -133,46 +138,44 @@ module Mail
|
|
133
138
|
@parts.sort!(@part_sort_order)
|
134
139
|
end
|
135
140
|
|
136
|
-
|
137
|
-
|
138
|
-
def raw_source
|
139
|
-
@raw_source
|
140
|
-
end
|
141
|
-
|
142
|
-
def get_best_encoding(target)
|
143
|
-
target_encoding = Mail::Encodings.get_encoding(target)
|
144
|
-
target_encoding.get_best_compatible(encoding, raw_source)
|
141
|
+
def negotiate_best_encoding(message_encoding, allowed_encodings = nil)
|
142
|
+
Mail::Encodings::TransferEncoding.negotiate(message_encoding, encoding, raw_source, allowed_encodings)
|
145
143
|
end
|
146
|
-
|
144
|
+
|
147
145
|
# Returns a body encoded using transfer_encoding. Multipart always uses an
|
148
146
|
# identiy encoding (i.e. no encoding).
|
149
147
|
# Calling this directly is not a good idea, but supported for compatibility
|
150
148
|
# TODO: Validate that preamble and epilogue are valid for requested encoding
|
151
|
-
def encoded(transfer_encoding =
|
149
|
+
def encoded(transfer_encoding = nil)
|
152
150
|
if multipart?
|
153
151
|
self.sort_parts!
|
154
152
|
encoded_parts = parts.map { |p| p.encoded }
|
155
153
|
([preamble] + encoded_parts).join(crlf_boundary) + end_boundary + epilogue.to_s
|
156
154
|
else
|
157
|
-
|
158
|
-
|
159
|
-
|
155
|
+
dec = Mail::Encodings.get_encoding(encoding)
|
156
|
+
enc =
|
157
|
+
if Utilities.blank?(transfer_encoding)
|
158
|
+
dec
|
159
|
+
else
|
160
|
+
negotiate_best_encoding(transfer_encoding)
|
161
|
+
end
|
162
|
+
|
160
163
|
if dec.nil?
|
161
|
-
|
162
|
-
|
164
|
+
# Cannot decode, so skip normalization
|
165
|
+
raw_source
|
163
166
|
else
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
167
|
+
# Decode then encode to normalize and allow transforming
|
168
|
+
# from base64 to Q-P and vice versa
|
169
|
+
decoded = dec.decode(raw_source)
|
170
|
+
if defined?(Encoding) && charset && charset != "US-ASCII"
|
171
|
+
decoded = decoded.encode(charset)
|
172
|
+
decoded.force_encoding('BINARY') unless Encoding.find(charset).ascii_compatible?
|
173
|
+
end
|
174
|
+
enc.encode(decoded)
|
172
175
|
end
|
173
176
|
end
|
174
177
|
end
|
175
|
-
|
178
|
+
|
176
179
|
def decoded
|
177
180
|
if !Encodings.defined?(encoding)
|
178
181
|
raise UnknownEncodingType, "Don't know how to decode #{encoding}, please call #encoded and decode it yourself."
|
@@ -184,14 +187,6 @@ module Mail
|
|
184
187
|
def to_s
|
185
188
|
decoded
|
186
189
|
end
|
187
|
-
|
188
|
-
def charset
|
189
|
-
@charset
|
190
|
-
end
|
191
|
-
|
192
|
-
def charset=( val )
|
193
|
-
@charset = val
|
194
|
-
end
|
195
190
|
|
196
191
|
def encoding(val = nil)
|
197
192
|
if val
|
@@ -200,54 +195,41 @@ module Mail
|
|
200
195
|
@encoding
|
201
196
|
end
|
202
197
|
end
|
203
|
-
|
198
|
+
|
204
199
|
def encoding=( val )
|
205
|
-
@encoding =
|
206
|
-
|
207
|
-
|
200
|
+
@encoding =
|
201
|
+
if val == "text" || Utilities.blank?(val)
|
202
|
+
default_encoding
|
203
|
+
else
|
208
204
|
val
|
209
|
-
|
205
|
+
end
|
210
206
|
end
|
211
207
|
|
212
|
-
# Returns the
|
213
|
-
|
214
|
-
|
215
|
-
|
208
|
+
# Returns the raw source that the body was initialized with, without
|
209
|
+
# any tampering
|
210
|
+
attr_reader :raw_source
|
211
|
+
|
212
|
+
# Returns parts of the body
|
213
|
+
attr_reader :parts
|
214
|
+
|
215
|
+
# Returns and sets the original character encoding
|
216
|
+
attr_accessor :charset
|
217
|
+
|
218
|
+
# Returns and sets the preamble as a string (any text that is before the first MIME boundary)
|
219
|
+
attr_accessor :preamble
|
220
|
+
|
221
|
+
# Returns and sets the epilogue as a string (any text that is after the last MIME boundary)
|
222
|
+
attr_accessor :epilogue
|
223
|
+
|
224
|
+
# Returns and sets the boundary used by the body
|
225
|
+
# Allows you to change the boundary of this Body object
|
226
|
+
attr_accessor :boundary
|
216
227
|
|
217
|
-
# Sets the preamble to a string (adds text before the first MIME boundary)
|
218
|
-
def preamble=( val )
|
219
|
-
@preamble = val
|
220
|
-
end
|
221
|
-
|
222
|
-
# Returns the epilogue (any text that is after the last MIME boundary)
|
223
|
-
def epilogue
|
224
|
-
@epilogue
|
225
|
-
end
|
226
|
-
|
227
|
-
# Sets the epilogue to a string (adds text after the last MIME boundary)
|
228
|
-
def epilogue=( val )
|
229
|
-
@epilogue = val
|
230
|
-
end
|
231
|
-
|
232
228
|
# Returns true if there are parts defined in the body
|
233
229
|
def multipart?
|
234
230
|
true unless parts.empty?
|
235
231
|
end
|
236
|
-
|
237
|
-
# Returns the boundary used by the body
|
238
|
-
def boundary
|
239
|
-
@boundary
|
240
|
-
end
|
241
|
-
|
242
|
-
# Allows you to change the boundary of this Body object
|
243
|
-
def boundary=( val )
|
244
|
-
@boundary = val
|
245
|
-
end
|
246
232
|
|
247
|
-
def parts
|
248
|
-
@parts
|
249
|
-
end
|
250
|
-
|
251
233
|
def <<( val )
|
252
234
|
if @parts
|
253
235
|
@parts << val
|
@@ -268,14 +250,21 @@ module Mail
|
|
268
250
|
self
|
269
251
|
end
|
270
252
|
|
271
|
-
def
|
272
|
-
|
253
|
+
def ascii_only?
|
254
|
+
unless defined? @ascii_only
|
255
|
+
@ascii_only = raw_source.ascii_only?
|
256
|
+
end
|
257
|
+
@ascii_only
|
273
258
|
end
|
274
|
-
|
259
|
+
|
275
260
|
def empty?
|
276
261
|
!!raw_source.to_s.empty?
|
277
262
|
end
|
278
|
-
|
263
|
+
|
264
|
+
def default_encoding
|
265
|
+
ascii_only? ? '7bit' : '8bit'
|
266
|
+
end
|
267
|
+
|
279
268
|
private
|
280
269
|
|
281
270
|
# split parts by boundary, ignore first part if empty, append final part when closing boundary was missing
|
@@ -308,9 +297,9 @@ module Mail
|
|
308
297
|
def end_boundary
|
309
298
|
"\r\n--#{boundary}--\r\n"
|
310
299
|
end
|
311
|
-
|
300
|
+
|
312
301
|
def set_charset
|
313
|
-
|
302
|
+
@charset = ascii_only? ? 'US-ASCII' : nil
|
314
303
|
end
|
315
304
|
end
|
316
305
|
end
|
@@ -1,48 +1,54 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
#
|
3
|
+
# This whole class and associated specs is deprecated and will go away in the version 3 release of mail.
|
2
4
|
module Mail
|
3
5
|
module CheckDeliveryParams #:nodoc:
|
4
6
|
class << self
|
7
|
+
|
8
|
+
extend Gem::Deprecate
|
9
|
+
|
5
10
|
def check(mail)
|
6
|
-
|
7
|
-
|
8
|
-
|
11
|
+
envelope = Mail::SmtpEnvelope.new(mail)
|
12
|
+
[ envelope.from,
|
13
|
+
envelope.to,
|
14
|
+
envelope.message ]
|
9
15
|
end
|
16
|
+
deprecate :check, 'Mail::SmtpEnvelope.new created in commit c106bebea066782a72e4f24dd37b532d95773df7', 2023, 6
|
10
17
|
|
11
18
|
def check_from(addr)
|
12
|
-
|
13
|
-
|
14
|
-
end
|
15
|
-
|
16
|
-
check_addr 'From', addr
|
19
|
+
mail = Mail.new(from: 'deprecated@example.com', to: 'deprecated@example.com')
|
20
|
+
Mail::SmtpEnvelope.new(mail).send(:validate_addr, 'From', addr)
|
17
21
|
end
|
22
|
+
deprecate :check_from, :none, 2023, 6
|
18
23
|
|
19
24
|
def check_to(addrs)
|
20
|
-
|
21
|
-
raise ArgumentError, "SMTP To address may not be blank: #{addrs.inspect}"
|
22
|
-
end
|
23
|
-
|
25
|
+
mail = Mail.new(from: 'deprecated@example.com', to: 'deprecated@example.com')
|
24
26
|
Array(addrs).map do |addr|
|
25
|
-
|
27
|
+
Mail::SmtpEnvelope.new(mail).send(:validate_addr, 'To', addr)
|
26
28
|
end
|
27
29
|
end
|
30
|
+
deprecate :check_to, :none, 2023, 6
|
28
31
|
|
29
32
|
def check_addr(addr_name, addr)
|
30
|
-
|
31
|
-
|
32
|
-
end
|
33
|
+
mail = Mail.new(from: 'deprecated@example.com', to: 'deprecated@example.com')
|
34
|
+
Mail::SmtpEnvelope.new(mail).send(:validate_addr, addr_name, addr)
|
33
35
|
end
|
36
|
+
deprecate :check_addr, :none, 2023, 6
|
34
37
|
|
35
38
|
def validate_smtp_addr(addr)
|
36
|
-
if addr
|
37
|
-
|
38
|
-
|
39
|
+
if addr
|
40
|
+
if addr.bytesize > 2048
|
41
|
+
yield 'may not exceed 2kB'
|
42
|
+
end
|
39
43
|
|
40
|
-
|
41
|
-
|
44
|
+
if /[\r\n]/ =~ addr
|
45
|
+
yield 'may not contain CR or LF line breaks'
|
46
|
+
end
|
42
47
|
end
|
43
48
|
|
44
49
|
addr
|
45
50
|
end
|
51
|
+
deprecate :validate_smtp_addr, :none, 2023, 6
|
46
52
|
|
47
53
|
def check_message(message)
|
48
54
|
message = message.encoded if message.respond_to?(:encoded)
|
@@ -53,6 +59,7 @@ module Mail
|
|
53
59
|
|
54
60
|
message
|
55
61
|
end
|
62
|
+
deprecate :check_message, :none, 2023, 6
|
56
63
|
end
|
57
64
|
end
|
58
65
|
end
|
data/lib/mail/configuration.rb
CHANGED
data/lib/mail/constants.rb
CHANGED
@@ -16,9 +16,10 @@ module Mail
|
|
16
16
|
control = control.dup.force_encoding(Encoding::BINARY)
|
17
17
|
end
|
18
18
|
|
19
|
-
|
19
|
+
LAX_CRLF = /\r?\n/
|
20
20
|
WSP = /[#{white_space}]/
|
21
|
-
FWS = /#{
|
21
|
+
FWS = /#{LAX_CRLF}#{WSP}*/
|
22
|
+
UNFOLD_WS = /#{LAX_CRLF}(#{WSP})/m
|
22
23
|
TEXT = /[#{text}]/ # + obs-text
|
23
24
|
FIELD_NAME = /[#{field_name}]+/
|
24
25
|
FIELD_PREFIX = /\A(#{FIELD_NAME})/
|
@@ -26,7 +27,7 @@ module Mail
|
|
26
27
|
FIELD_LINE = /^[#{field_name}]+:\s*.+$/
|
27
28
|
FIELD_SPLIT = /^(#{FIELD_NAME})\s*:\s*(#{FIELD_BODY})?$/
|
28
29
|
HEADER_LINE = /^([#{field_name}]+:\s*.+)$/
|
29
|
-
HEADER_SPLIT = /#{
|
30
|
+
HEADER_SPLIT = /#{LAX_CRLF}(?!#{WSP})/
|
30
31
|
|
31
32
|
QP_UNSAFE = /[^#{qp_safe}]/
|
32
33
|
QP_SAFE = /[#{qp_safe}]/
|
@@ -34,8 +35,28 @@ module Mail
|
|
34
35
|
ATOM_UNSAFE = /[#{Regexp.quote aspecial}#{control}#{sp}]/n
|
35
36
|
PHRASE_UNSAFE = /[#{Regexp.quote aspecial}#{control}]/n
|
36
37
|
TOKEN_UNSAFE = /[#{Regexp.quote tspecial}#{control}#{sp}]/n
|
37
|
-
|
38
|
-
|
38
|
+
|
39
|
+
ENCODED_VALUE = %r{
|
40
|
+
\=\? # literal =?
|
41
|
+
([^?]+) #
|
42
|
+
\? # literal ?
|
43
|
+
([QB]) # either a "Q" or a "B"
|
44
|
+
\? # literal ?
|
45
|
+
.*? # lazily match all characters
|
46
|
+
\?\= # literal ?=
|
47
|
+
}mix # m is multi-line, i is case-insensitive, x is free-spacing
|
48
|
+
|
49
|
+
FULL_ENCODED_VALUE = %r{ # Identical to ENCODED_VALUE but captures the whole rather than components of
|
50
|
+
(
|
51
|
+
\=\? # literal =?
|
52
|
+
[^?]+ #
|
53
|
+
\? # literal ?
|
54
|
+
[QB] # either a "Q" or a "B"
|
55
|
+
\? # literal ?
|
56
|
+
.*? # lazily match all characters
|
57
|
+
\?\= # literal ?=
|
58
|
+
)
|
59
|
+
}mix # m is multi-line, i is case-insensitive, x is free-spacing
|
39
60
|
|
40
61
|
EMPTY = ''
|
41
62
|
SPACE = ' '
|
@@ -43,6 +64,7 @@ module Mail
|
|
43
64
|
HYPHEN = '-'
|
44
65
|
COLON = ':'
|
45
66
|
ASTERISK = '*'
|
67
|
+
CRLF = "\r\n"
|
46
68
|
CR = "\r"
|
47
69
|
LF = "\n"
|
48
70
|
CR_ENCODED = "=0D"
|
@@ -1,28 +1,28 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
# frozen_string_literal: true
|
3
|
+
require 'mail/parsers/address_lists_parser'
|
4
|
+
require 'mail/constants'
|
5
|
+
require 'mail/utilities'
|
6
|
+
|
3
7
|
module Mail
|
8
|
+
# Mail::Address handles all email addresses in Mail. It takes an email address string
|
9
|
+
# and parses it, breaking it down into its component parts and allowing you to get the
|
10
|
+
# address, comments, display name, name, local part, domain part and fully formatted
|
11
|
+
# address.
|
12
|
+
#
|
13
|
+
# Mail::Address requires a correctly formatted email address per RFC2822 or RFC822. It
|
14
|
+
# handles all obsolete versions including obsolete domain routing on the local part.
|
15
|
+
#
|
16
|
+
# a = Address.new('Mikel Lindsaar (My email address) <mikel@test.lindsaar.net>')
|
17
|
+
# a.format #=> 'Mikel Lindsaar <mikel@test.lindsaar.net> (My email address)'
|
18
|
+
# a.address #=> 'mikel@test.lindsaar.net'
|
19
|
+
# a.display_name #=> 'Mikel Lindsaar'
|
20
|
+
# a.local #=> 'mikel'
|
21
|
+
# a.domain #=> 'test.lindsaar.net'
|
22
|
+
# a.comments #=> ['My email address']
|
23
|
+
# a.to_s #=> 'Mikel Lindsaar <mikel@test.lindsaar.net> (My email address)'
|
4
24
|
class Address
|
5
|
-
|
6
|
-
include Mail::Utilities
|
7
|
-
|
8
|
-
# Mail::Address handles all email addresses in Mail. It takes an email address string
|
9
|
-
# and parses it, breaking it down into its component parts and allowing you to get the
|
10
|
-
# address, comments, display name, name, local part, domain part and fully formatted
|
11
|
-
# address.
|
12
|
-
#
|
13
|
-
# Mail::Address requires a correctly formatted email address per RFC2822 or RFC822. It
|
14
|
-
# handles all obsolete versions including obsolete domain routing on the local part.
|
15
|
-
#
|
16
|
-
# a = Address.new('Mikel Lindsaar (My email address) <mikel@test.lindsaar.net>')
|
17
|
-
# a.format #=> 'Mikel Lindsaar <mikel@test.lindsaar.net> (My email address)'
|
18
|
-
# a.address #=> 'mikel@test.lindsaar.net'
|
19
|
-
# a.display_name #=> 'Mikel Lindsaar'
|
20
|
-
# a.local #=> 'mikel'
|
21
|
-
# a.domain #=> 'test.lindsaar.net'
|
22
|
-
# a.comments #=> ['My email address']
|
23
|
-
# a.to_s #=> 'Mikel Lindsaar <mikel@test.lindsaar.net> (My email address)'
|
24
25
|
def initialize(value = nil)
|
25
|
-
@output_type = :decode
|
26
26
|
if value.nil?
|
27
27
|
@parsed = false
|
28
28
|
@data = nil
|
@@ -44,14 +44,14 @@ module Mail
|
|
44
44
|
#
|
45
45
|
# a = Address.new('Mikel Lindsaar (My email address) <mikel@test.lindsaar.net>')
|
46
46
|
# a.format #=> 'Mikel Lindsaar <mikel@test.lindsaar.net> (My email address)'
|
47
|
-
def format
|
47
|
+
def format(output_type = :decode)
|
48
48
|
parse unless @parsed
|
49
49
|
if @data.nil?
|
50
|
-
EMPTY
|
51
|
-
elsif display_name
|
52
|
-
[quote_phrase(
|
53
|
-
elsif address
|
54
|
-
[
|
50
|
+
Constants::EMPTY
|
51
|
+
elsif name = display_name(output_type)
|
52
|
+
[Utilities.quote_phrase(name), "<#{address(output_type)}>", format_comments].compact.join(Constants::SPACE)
|
53
|
+
elsif a = address(output_type)
|
54
|
+
[a, format_comments].compact.join(Constants::SPACE)
|
55
55
|
else
|
56
56
|
raw
|
57
57
|
end
|
@@ -62,9 +62,13 @@ module Mail
|
|
62
62
|
#
|
63
63
|
# a = Address.new('Mikel Lindsaar (My email address) <mikel@test.lindsaar.net>')
|
64
64
|
# a.address #=> 'mikel@test.lindsaar.net'
|
65
|
-
def address
|
65
|
+
def address(output_type = :decode)
|
66
66
|
parse unless @parsed
|
67
|
-
|
67
|
+
if d = domain(output_type)
|
68
|
+
"#{local(output_type)}@#{d}"
|
69
|
+
else
|
70
|
+
local(output_type)
|
71
|
+
end
|
68
72
|
end
|
69
73
|
|
70
74
|
# Provides a way to assign an address to an already made Mail::Address object.
|
@@ -80,10 +84,10 @@ module Mail
|
|
80
84
|
#
|
81
85
|
# a = Address.new('Mikel Lindsaar (My email address) <mikel@test.lindsaar.net>')
|
82
86
|
# a.display_name #=> 'Mikel Lindsaar'
|
83
|
-
def display_name
|
87
|
+
def display_name(output_type = :decode)
|
84
88
|
parse unless @parsed
|
85
89
|
@display_name ||= get_display_name
|
86
|
-
Encodings.decode_encode(@display_name.to_s,
|
90
|
+
Encodings.decode_encode(@display_name.to_s, output_type) if @display_name
|
87
91
|
end
|
88
92
|
|
89
93
|
# Provides a way to assign a display name to an already made Mail::Address object.
|
@@ -101,9 +105,9 @@ module Mail
|
|
101
105
|
#
|
102
106
|
# a = Address.new('Mikel Lindsaar (My email address) <mikel@test.lindsaar.net>')
|
103
107
|
# a.local #=> 'mikel'
|
104
|
-
def local
|
108
|
+
def local(output_type = :decode)
|
105
109
|
parse unless @parsed
|
106
|
-
Encodings.decode_encode("#{@data.obs_domain_list}#{get_local.strip}",
|
110
|
+
Encodings.decode_encode("#{@data.obs_domain_list}#{get_local.strip}", output_type) if get_local
|
107
111
|
end
|
108
112
|
|
109
113
|
# Returns the domain part (the right hand side of the @ sign in the email address) of
|
@@ -111,23 +115,27 @@ module Mail
|
|
111
115
|
#
|
112
116
|
# a = Address.new('Mikel Lindsaar (My email address) <mikel@test.lindsaar.net>')
|
113
117
|
# a.domain #=> 'test.lindsaar.net'
|
114
|
-
def domain
|
118
|
+
def domain(output_type = :decode)
|
115
119
|
parse unless @parsed
|
116
|
-
Encodings.decode_encode(strip_all_comments(get_domain),
|
120
|
+
Encodings.decode_encode(strip_all_comments(get_domain), output_type) if get_domain
|
117
121
|
end
|
118
122
|
|
119
|
-
# Returns an array of comments that are in the email, or
|
123
|
+
# Returns an array of comments that are in the email, or nil if there
|
120
124
|
# are no comments
|
121
125
|
#
|
122
126
|
# a = Address.new('Mikel Lindsaar (My email address) <mikel@test.lindsaar.net>')
|
123
127
|
# a.comments #=> ['My email address']
|
128
|
+
#
|
129
|
+
# b = Address.new('Mikel Lindsaar <mikel@test.lindsaar.net>')
|
130
|
+
# b.comments #=> nil
|
131
|
+
|
124
132
|
def comments
|
125
133
|
parse unless @parsed
|
126
134
|
comments = get_comments
|
127
135
|
if comments.nil? || comments.none?
|
128
136
|
nil
|
129
137
|
else
|
130
|
-
comments.map { |c| c.squeeze(SPACE) }
|
138
|
+
comments.map { |c| c.squeeze(Constants::SPACE) }
|
131
139
|
end
|
132
140
|
end
|
133
141
|
|
@@ -159,13 +167,11 @@ module Mail
|
|
159
167
|
end
|
160
168
|
|
161
169
|
def encoded
|
162
|
-
|
163
|
-
format
|
170
|
+
format :encode
|
164
171
|
end
|
165
172
|
|
166
173
|
def decoded
|
167
|
-
|
168
|
-
format
|
174
|
+
format :decode
|
169
175
|
end
|
170
176
|
|
171
177
|
def group
|
@@ -179,11 +185,11 @@ module Mail
|
|
179
185
|
@data = nil
|
180
186
|
|
181
187
|
case value
|
182
|
-
when Mail::Parsers::AddressStruct
|
188
|
+
when Mail::Parsers::AddressListsParser::AddressStruct
|
183
189
|
@data = value
|
184
190
|
when String
|
185
191
|
unless Utilities.blank?(value)
|
186
|
-
address_list = Mail::Parsers::AddressListsParser.
|
192
|
+
address_list = Mail::Parsers::AddressListsParser.parse(value)
|
187
193
|
@data = address_list.addresses.first
|
188
194
|
end
|
189
195
|
end
|
@@ -192,7 +198,7 @@ module Mail
|
|
192
198
|
def strip_all_comments(string)
|
193
199
|
unless Utilities.blank?(comments)
|
194
200
|
comments.each do |comment|
|
195
|
-
string = string.gsub("(#{comment})", EMPTY)
|
201
|
+
string = string.gsub("(#{comment})", Constants::EMPTY)
|
196
202
|
end
|
197
203
|
end
|
198
204
|
string.strip
|
@@ -202,7 +208,7 @@ module Mail
|
|
202
208
|
unless Utilities.blank?(comments)
|
203
209
|
comments.each do |comment|
|
204
210
|
if @data.domain && @data.domain.include?("(#{comment})")
|
205
|
-
value = value.gsub("(#{comment})", EMPTY)
|
211
|
+
value = value.gsub("(#{comment})", Constants::EMPTY)
|
206
212
|
end
|
207
213
|
end
|
208
214
|
end
|
@@ -222,15 +228,15 @@ module Mail
|
|
222
228
|
if display_name
|
223
229
|
str = display_name
|
224
230
|
elsif comments
|
225
|
-
str = "(#{comments.join(SPACE).squeeze(SPACE)})"
|
231
|
+
str = "(#{comments.join(Constants::SPACE).squeeze(Constants::SPACE)})"
|
226
232
|
end
|
227
233
|
|
228
|
-
unparen(str) unless Utilities.blank?(str)
|
234
|
+
Utilities.unparen(str) unless Utilities.blank?(str)
|
229
235
|
end
|
230
236
|
|
231
237
|
def format_comments
|
232
238
|
if comments
|
233
|
-
comment_text = comments.map {|c| escape_paren(c) }.join(SPACE).squeeze(SPACE)
|
239
|
+
comment_text = comments.map {|c| Utilities.escape_paren(c) }.join(Constants::SPACE).squeeze(Constants::SPACE)
|
234
240
|
@format_comments ||= "(#{comment_text})"
|
235
241
|
else
|
236
242
|
nil
|
@@ -1,42 +1,34 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
# frozen_string_literal: true
|
3
|
+
require 'mail/parsers/address_lists_parser'
|
4
|
+
|
3
5
|
module Mail
|
4
|
-
class AddressList
|
6
|
+
class AddressList #:nodoc:
|
7
|
+
attr_reader :addresses, :group_names
|
5
8
|
|
6
9
|
# Mail::AddressList is the class that parses To, From and other address fields from
|
7
10
|
# emails passed into Mail.
|
8
|
-
#
|
11
|
+
#
|
9
12
|
# AddressList provides a way to query the groups and mailbox lists of the passed in
|
10
13
|
# string.
|
11
|
-
#
|
14
|
+
#
|
12
15
|
# It can supply all addresses in an array, or return each address as an address object.
|
13
|
-
#
|
16
|
+
#
|
14
17
|
# Mail::AddressList requires a correctly formatted group or mailbox list per RFC2822 or
|
15
18
|
# RFC822. It also handles all obsolete versions in those RFCs.
|
16
|
-
#
|
19
|
+
#
|
17
20
|
# list = 'ada@test.lindsaar.net, My Group: mikel@test.lindsaar.net, Bob <bob@test.lindsaar.net>;'
|
18
21
|
# a = AddressList.new(list)
|
19
22
|
# a.addresses #=> [#<Mail::Address:14943130 Address: |ada@test.lindsaar.net...
|
20
23
|
# a.group_names #=> ["My Group"]
|
21
24
|
def initialize(string)
|
22
|
-
|
23
|
-
@
|
24
|
-
|
25
|
-
|
26
|
-
# Returns a list of address objects from the parsed line
|
27
|
-
def addresses
|
28
|
-
@addresses ||= @address_list.addresses.map do |address_data|
|
29
|
-
Mail::Address.new(address_data)
|
30
|
-
end
|
25
|
+
address_list = Parsers::AddressListsParser.parse(string)
|
26
|
+
@addresses = address_list.addresses.map { |a| Address.new(a) }
|
27
|
+
@group_names = address_list.group_names
|
31
28
|
end
|
32
29
|
|
33
30
|
def addresses_grouped_by_group
|
34
31
|
addresses.select(&:group).group_by(&:group)
|
35
32
|
end
|
36
|
-
|
37
|
-
# Returns the names as an array of strings of all groups
|
38
|
-
def group_names # :nodoc:
|
39
|
-
@address_list.group_names
|
40
|
-
end
|
41
33
|
end
|
42
34
|
end
|