mail 2.7.1 → 2.9.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 +4 -4
- data/README.md +135 -59
- data/lib/mail/attachments_list.rb +5 -6
- data/lib/mail/body.rb +51 -74
- 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/unix_to_unix.rb +1 -1
- data/lib/mail/encodings.rb +32 -61
- data/lib/mail/envelope.rb +11 -14
- data/lib/mail/field.rb +100 -86
- data/lib/mail/field_list.rb +61 -8
- data/lib/mail/fields/bcc_field.rb +33 -52
- data/lib/mail/fields/cc_field.rb +27 -49
- data/lib/mail/fields/comments_field.rb +26 -37
- data/lib/mail/fields/common_address_field.rb +162 -0
- data/lib/mail/fields/common_date_field.rb +56 -0
- data/lib/mail/fields/common_field.rb +77 -0
- data/lib/mail/fields/common_message_id_field.rb +41 -0
- data/lib/mail/fields/content_description_field.rb +6 -14
- data/lib/mail/fields/content_disposition_field.rb +11 -38
- data/lib/mail/fields/content_id_field.rb +23 -51
- data/lib/mail/fields/content_location_field.rb +10 -25
- data/lib/mail/fields/content_transfer_encoding_field.rb +30 -31
- data/lib/mail/fields/content_type_field.rb +49 -75
- data/lib/mail/fields/date_field.rb +22 -51
- data/lib/mail/fields/from_field.rb +27 -49
- data/lib/mail/fields/in_reply_to_field.rb +37 -49
- data/lib/mail/fields/keywords_field.rb +17 -31
- data/lib/mail/fields/message_id_field.rb +24 -71
- data/lib/mail/fields/mime_version_field.rb +18 -30
- data/lib/mail/fields/named_structured_field.rb +10 -0
- data/lib/mail/fields/named_unstructured_field.rb +10 -0
- data/lib/mail/fields/optional_field.rb +5 -7
- data/lib/mail/fields/{common/parameter_hash.rb → parameter_hash.rb} +12 -10
- data/lib/mail/fields/received_field.rb +42 -57
- data/lib/mail/fields/references_field.rb +34 -49
- data/lib/mail/fields/reply_to_field.rb +27 -49
- data/lib/mail/fields/resent_bcc_field.rb +27 -49
- data/lib/mail/fields/resent_cc_field.rb +27 -49
- data/lib/mail/fields/resent_date_field.rb +4 -29
- data/lib/mail/fields/resent_from_field.rb +27 -49
- data/lib/mail/fields/resent_message_id_field.rb +4 -29
- data/lib/mail/fields/resent_sender_field.rb +26 -56
- data/lib/mail/fields/resent_to_field.rb +27 -49
- data/lib/mail/fields/return_path_field.rb +49 -54
- data/lib/mail/fields/sender_field.rb +33 -55
- data/lib/mail/fields/structured_field.rb +2 -30
- data/lib/mail/fields/subject_field.rb +8 -11
- data/lib/mail/fields/to_field.rb +27 -49
- data/lib/mail/fields/unstructured_field.rb +15 -48
- data/lib/mail/fields.rb +9 -0
- data/lib/mail/header.rb +69 -110
- data/lib/mail/mail.rb +32 -27
- data/lib/mail/matchers/attachment_matchers.rb +15 -0
- data/lib/mail/message.rb +67 -78
- data/lib/mail/multibyte/chars.rb +9 -167
- data/lib/mail/multibyte/unicode.rb +1 -1
- 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 +13 -12
- 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 +81 -30
- data/lib/mail/network/delivery_methods/smtp_connection.rb +10 -19
- data/lib/mail/network/delivery_methods/test_mailer.rb +8 -6
- data/lib/mail/network/retriever_methods/base.rb +13 -13
- data/lib/mail/network/retriever_methods/imap.rb +8 -5
- data/lib/mail/network/retriever_methods/pop3.rb +22 -22
- data/lib/mail/network/retriever_methods/test_retriever.rb +2 -1
- data/lib/mail/parsers/address_lists_parser.rb +33073 -33064
- data/lib/mail/parsers/address_lists_parser.rl +11 -0
- data/lib/mail/parsers/content_disposition_parser.rb +837 -828
- data/lib/mail/parsers/content_disposition_parser.rl +11 -0
- data/lib/mail/parsers/content_location_parser.rb +773 -764
- data/lib/mail/parsers/content_location_parser.rl +12 -1
- data/lib/mail/parsers/content_transfer_encoding_parser.rb +477 -468
- data/lib/mail/parsers/content_transfer_encoding_parser.rl +11 -0
- data/lib/mail/parsers/content_type_parser.rb +974 -965
- data/lib/mail/parsers/content_type_parser.rl +11 -0
- data/lib/mail/parsers/date_time_parser.rb +841 -832
- data/lib/mail/parsers/date_time_parser.rl +11 -0
- data/lib/mail/parsers/envelope_from_parser.rb +3627 -3530
- data/lib/mail/parsers/envelope_from_parser.rl +11 -0
- data/lib/mail/parsers/message_ids_parser.rb +5110 -2800
- data/lib/mail/parsers/message_ids_parser.rl +16 -1
- data/lib/mail/parsers/mime_version_parser.rb +466 -457
- data/lib/mail/parsers/mime_version_parser.rl +11 -0
- data/lib/mail/parsers/phrase_lists_parser.rb +839 -830
- data/lib/mail/parsers/phrase_lists_parser.rl +12 -1
- data/lib/mail/parsers/received_parser.rb +8692 -8683
- data/lib/mail/parsers/received_parser.rl +11 -0
- data/lib/mail/parsers/rfc5322.rl +28 -13
- data/lib/mail/parsers.rb +11 -17
- data/lib/mail/part.rb +24 -28
- data/lib/mail/parts_list.rb +57 -0
- data/lib/mail/smtp_envelope.rb +57 -0
- data/lib/mail/utilities.rb +321 -69
- data/lib/mail/version.rb +1 -1
- data/lib/mail/yaml.rb +30 -0
- data/lib/mail.rb +2 -22
- metadata +83 -19
- 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
|
@@ -1,27 +1,27 @@
|
|
|
1
1
|
# encoding: utf-8
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
require 'mail/parsers/address_lists_parser'
|
|
4
|
+
require 'mail/constants'
|
|
5
|
+
require 'mail/utilities'
|
|
4
6
|
|
|
5
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)'
|
|
6
24
|
class Address
|
|
7
|
-
include Mail::Utilities
|
|
8
|
-
|
|
9
|
-
# Mail::Address handles all email addresses in Mail. It takes an email address string
|
|
10
|
-
# and parses it, breaking it down into its component parts and allowing you to get the
|
|
11
|
-
# address, comments, display name, name, local part, domain part and fully formatted
|
|
12
|
-
# address.
|
|
13
|
-
#
|
|
14
|
-
# Mail::Address requires a correctly formatted email address per RFC2822 or RFC822. It
|
|
15
|
-
# handles all obsolete versions including obsolete domain routing on the local part.
|
|
16
|
-
#
|
|
17
|
-
# a = Address.new('Mikel Lindsaar (My email address) <mikel@test.lindsaar.net>')
|
|
18
|
-
# a.format #=> 'Mikel Lindsaar <mikel@test.lindsaar.net> (My email address)'
|
|
19
|
-
# a.address #=> 'mikel@test.lindsaar.net'
|
|
20
|
-
# a.display_name #=> 'Mikel Lindsaar'
|
|
21
|
-
# a.local #=> 'mikel'
|
|
22
|
-
# a.domain #=> 'test.lindsaar.net'
|
|
23
|
-
# a.comments #=> ['My email address']
|
|
24
|
-
# a.to_s #=> 'Mikel Lindsaar <mikel@test.lindsaar.net> (My email address)'
|
|
25
25
|
def initialize(value = nil)
|
|
26
26
|
if value.nil?
|
|
27
27
|
@parsed = false
|
|
@@ -47,11 +47,11 @@ module Mail
|
|
|
47
47
|
def format(output_type = :decode)
|
|
48
48
|
parse unless @parsed
|
|
49
49
|
if @data.nil?
|
|
50
|
-
EMPTY
|
|
50
|
+
Constants::EMPTY
|
|
51
51
|
elsif name = display_name(output_type)
|
|
52
|
-
[quote_phrase(name), "<#{address(output_type)}>", format_comments].compact.join(SPACE)
|
|
52
|
+
[Utilities.quote_phrase(name), "<#{address(output_type)}>", format_comments].compact.join(Constants::SPACE)
|
|
53
53
|
elsif a = address(output_type)
|
|
54
|
-
[a, format_comments].compact.join(SPACE)
|
|
54
|
+
[a, format_comments].compact.join(Constants::SPACE)
|
|
55
55
|
else
|
|
56
56
|
raw
|
|
57
57
|
end
|
|
@@ -135,7 +135,7 @@ module Mail
|
|
|
135
135
|
if comments.nil? || comments.none?
|
|
136
136
|
nil
|
|
137
137
|
else
|
|
138
|
-
comments.map { |c| c.squeeze(SPACE) }
|
|
138
|
+
comments.map { |c| c.squeeze(Constants::SPACE) }
|
|
139
139
|
end
|
|
140
140
|
end
|
|
141
141
|
|
|
@@ -198,7 +198,7 @@ module Mail
|
|
|
198
198
|
def strip_all_comments(string)
|
|
199
199
|
unless Utilities.blank?(comments)
|
|
200
200
|
comments.each do |comment|
|
|
201
|
-
string = string.gsub("(#{comment})", EMPTY)
|
|
201
|
+
string = string.gsub("(#{comment})", Constants::EMPTY)
|
|
202
202
|
end
|
|
203
203
|
end
|
|
204
204
|
string.strip
|
|
@@ -208,7 +208,7 @@ module Mail
|
|
|
208
208
|
unless Utilities.blank?(comments)
|
|
209
209
|
comments.each do |comment|
|
|
210
210
|
if @data.domain && @data.domain.include?("(#{comment})")
|
|
211
|
-
value = value.gsub("(#{comment})", EMPTY)
|
|
211
|
+
value = value.gsub("(#{comment})", Constants::EMPTY)
|
|
212
212
|
end
|
|
213
213
|
end
|
|
214
214
|
end
|
|
@@ -228,15 +228,15 @@ module Mail
|
|
|
228
228
|
if display_name
|
|
229
229
|
str = display_name
|
|
230
230
|
elsif comments
|
|
231
|
-
str = "(#{comments.join(SPACE).squeeze(SPACE)})"
|
|
231
|
+
str = "(#{comments.join(Constants::SPACE).squeeze(Constants::SPACE)})"
|
|
232
232
|
end
|
|
233
233
|
|
|
234
|
-
unparen(str) unless Utilities.blank?(str)
|
|
234
|
+
Utilities.unparen(str) unless Utilities.blank?(str)
|
|
235
235
|
end
|
|
236
236
|
|
|
237
237
|
def format_comments
|
|
238
238
|
if comments
|
|
239
|
-
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)
|
|
240
240
|
@format_comments ||= "(#{comment_text})"
|
|
241
241
|
else
|
|
242
242
|
nil
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
require 'mail/parsers/content_type_parser'
|
|
4
4
|
|
|
5
5
|
module Mail
|
|
6
|
-
class ContentTypeElement
|
|
6
|
+
class ContentTypeElement #:nodoc:
|
|
7
7
|
attr_reader :main_type, :sub_type, :parameters
|
|
8
8
|
|
|
9
9
|
def initialize(string)
|
|
@@ -14,8 +14,12 @@ module Mail
|
|
|
14
14
|
end
|
|
15
15
|
|
|
16
16
|
private
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
def cleaned(string)
|
|
18
|
+
if string =~ /;\s*$/
|
|
19
|
+
$`
|
|
20
|
+
else
|
|
21
|
+
string
|
|
22
|
+
end
|
|
23
|
+
end
|
|
20
24
|
end
|
|
21
25
|
end
|
|
@@ -4,13 +4,13 @@ require 'mail/parsers/envelope_from_parser'
|
|
|
4
4
|
require 'date'
|
|
5
5
|
|
|
6
6
|
module Mail
|
|
7
|
-
class EnvelopeFromElement
|
|
7
|
+
class EnvelopeFromElement #:nodoc:
|
|
8
8
|
attr_reader :date_time, :address
|
|
9
9
|
|
|
10
10
|
def initialize(string)
|
|
11
11
|
envelope_from = Mail::Parsers::EnvelopeFromParser.parse(string)
|
|
12
12
|
@address = envelope_from.address
|
|
13
|
-
@date_time = ::DateTime.parse(envelope_from.ctime_date)
|
|
13
|
+
@date_time = ::DateTime.parse(envelope_from.ctime_date) if envelope_from.ctime_date
|
|
14
14
|
end
|
|
15
15
|
|
|
16
16
|
# RFC 4155:
|
|
@@ -19,15 +19,21 @@ module Mail
|
|
|
19
19
|
# traditional UNIX 'ctime' output sans timezone (note that the
|
|
20
20
|
# use of UTC precludes the need for a timezone indicator);
|
|
21
21
|
def formatted_date_time
|
|
22
|
-
if date_time
|
|
23
|
-
date_time.ctime
|
|
24
|
-
|
|
25
|
-
|
|
22
|
+
if date_time
|
|
23
|
+
if date_time.respond_to?(:ctime)
|
|
24
|
+
date_time.ctime
|
|
25
|
+
else
|
|
26
|
+
date_time.strftime '%a %b %e %T %Y'
|
|
27
|
+
end
|
|
26
28
|
end
|
|
27
29
|
end
|
|
28
30
|
|
|
29
31
|
def to_s
|
|
30
|
-
|
|
32
|
+
if date_time
|
|
33
|
+
"#{address} #{formatted_date_time}"
|
|
34
|
+
else
|
|
35
|
+
address
|
|
36
|
+
end
|
|
31
37
|
end
|
|
32
38
|
end
|
|
33
39
|
end
|
|
@@ -1,13 +1,18 @@
|
|
|
1
1
|
# encoding: utf-8
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
require 'mail/parsers/message_ids_parser'
|
|
4
|
+
require 'mail/utilities'
|
|
4
5
|
|
|
5
6
|
module Mail
|
|
6
|
-
class MessageIdsElement
|
|
7
|
+
class MessageIdsElement #:nodoc:
|
|
8
|
+
def self.parse(string)
|
|
9
|
+
new(string).tap(&:message_ids)
|
|
10
|
+
end
|
|
11
|
+
|
|
7
12
|
attr_reader :message_ids
|
|
8
13
|
|
|
9
14
|
def initialize(string)
|
|
10
|
-
@message_ids =
|
|
15
|
+
@message_ids = parse(string)
|
|
11
16
|
end
|
|
12
17
|
|
|
13
18
|
def message_id
|
|
@@ -15,8 +20,12 @@ module Mail
|
|
|
15
20
|
end
|
|
16
21
|
|
|
17
22
|
private
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
23
|
+
def parse(string)
|
|
24
|
+
if Utilities.blank? string
|
|
25
|
+
[]
|
|
26
|
+
else
|
|
27
|
+
Mail::Parsers::MessageIdsParser.parse(string).message_ids
|
|
28
|
+
end
|
|
29
|
+
end
|
|
21
30
|
end
|
|
22
31
|
end
|
|
@@ -4,11 +4,16 @@ require 'mail/parsers/phrase_lists_parser'
|
|
|
4
4
|
require 'mail/utilities'
|
|
5
5
|
|
|
6
6
|
module Mail
|
|
7
|
-
class PhraseList
|
|
7
|
+
class PhraseList #:nodoc:
|
|
8
8
|
attr_reader :phrases
|
|
9
9
|
|
|
10
10
|
def initialize(string)
|
|
11
|
-
@phrases =
|
|
11
|
+
@phrases =
|
|
12
|
+
if Utilities.blank? string
|
|
13
|
+
[]
|
|
14
|
+
else
|
|
15
|
+
Mail::Parsers::PhraseListsParser.parse(string).phrases.map { |p| Mail::Utilities.unquote(p) }
|
|
16
|
+
end
|
|
12
17
|
end
|
|
13
18
|
end
|
|
14
19
|
end
|
|
@@ -1,21 +1,35 @@
|
|
|
1
1
|
# encoding: utf-8
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
require 'mail/parsers/received_parser'
|
|
4
|
+
require 'mail/utilities'
|
|
4
5
|
require 'date'
|
|
5
6
|
|
|
6
7
|
module Mail
|
|
7
|
-
class ReceivedElement
|
|
8
|
-
|
|
9
|
-
attr_reader :date_time, :info
|
|
8
|
+
class ReceivedElement #:nodoc:
|
|
9
|
+
attr_reader :info, :date_time
|
|
10
10
|
|
|
11
11
|
def initialize(string)
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
if Utilities.blank? string
|
|
13
|
+
@date_time = nil
|
|
14
|
+
@info = nil
|
|
15
|
+
else
|
|
16
|
+
received = Mail::Parsers::ReceivedParser.parse(string)
|
|
17
|
+
@date_time = datetime_for(received)
|
|
18
|
+
@info = received.info
|
|
19
|
+
end
|
|
15
20
|
end
|
|
16
21
|
|
|
17
22
|
def to_s(*args)
|
|
18
23
|
"#{info}; #{date_time.to_s(*args)}"
|
|
19
24
|
end
|
|
25
|
+
|
|
26
|
+
private
|
|
27
|
+
def datetime_for(received)
|
|
28
|
+
::DateTime.parse("#{received.date} #{received.time}")
|
|
29
|
+
rescue ArgumentError => e
|
|
30
|
+
raise e unless e.message == 'invalid date'
|
|
31
|
+
warn "WARNING: Invalid date field for received element (#{received.date} #{received.time}): #{e.class}: #{e.message}"
|
|
32
|
+
nil
|
|
33
|
+
end
|
|
20
34
|
end
|
|
21
35
|
end
|
data/lib/mail/encodings/7bit.rb
CHANGED
|
@@ -17,6 +17,11 @@ module Mail
|
|
|
17
17
|
def self.encode(str)
|
|
18
18
|
::Mail::Utilities.binary_unsafe_to_crlf str
|
|
19
19
|
end
|
|
20
|
+
|
|
21
|
+
# Per RFC 2045 2.7. 7bit Data, No octets with decimal values greater than 127 are allowed.
|
|
22
|
+
def self.compatible_input?(str)
|
|
23
|
+
str.ascii_only? && super
|
|
24
|
+
end
|
|
20
25
|
end
|
|
21
26
|
end
|
|
22
27
|
end
|
|
@@ -16,11 +16,11 @@ module Mail
|
|
|
16
16
|
end
|
|
17
17
|
|
|
18
18
|
def self.decode(str)
|
|
19
|
-
|
|
19
|
+
Utilities.decode_base64(str)
|
|
20
20
|
end
|
|
21
21
|
|
|
22
22
|
def self.encode(str)
|
|
23
|
-
::Mail::Utilities.binary_unsafe_to_crlf(
|
|
23
|
+
::Mail::Utilities.binary_unsafe_to_crlf(Utilities.encode_base64(str))
|
|
24
24
|
end
|
|
25
25
|
|
|
26
26
|
# 3 bytes in -> 4 bytes out
|
|
@@ -16,11 +16,11 @@ module Mail
|
|
|
16
16
|
# Decode the string from Quoted-Printable. Cope with hard line breaks
|
|
17
17
|
# that were incorrectly encoded as hex instead of literal CRLF.
|
|
18
18
|
def self.decode(str)
|
|
19
|
-
str.gsub(/(?:=0D=0A|=0D|=0A)\r\n/, "\r\n").
|
|
19
|
+
::Mail::Utilities.to_lf ::Mail::Utilities.to_crlf(str).gsub(/(?:=0D=0A|=0D|=0A)\r\n/, "\r\n").unpack1("M*")
|
|
20
20
|
end
|
|
21
21
|
|
|
22
22
|
def self.encode(str)
|
|
23
|
-
[str].pack("M")
|
|
23
|
+
::Mail::Utilities.to_crlf [::Mail::Utilities.to_lf(str)].pack("M")
|
|
24
24
|
end
|
|
25
25
|
|
|
26
26
|
def self.cost(str)
|
data/lib/mail/encodings.rb
CHANGED
|
@@ -52,7 +52,7 @@ module Mail
|
|
|
52
52
|
|
|
53
53
|
def Encodings.transcode_charset(str, from_charset, to_charset = 'UTF-8')
|
|
54
54
|
if from_charset
|
|
55
|
-
|
|
55
|
+
Utilities.transcode_charset str, from_charset, to_charset
|
|
56
56
|
else
|
|
57
57
|
str
|
|
58
58
|
end
|
|
@@ -65,20 +65,19 @@ module Mail
|
|
|
65
65
|
# param_encode_language 'jp'
|
|
66
66
|
# end
|
|
67
67
|
#
|
|
68
|
-
# The character set used for encoding will
|
|
69
|
-
# Ruby < 1.9 or the encoding on the string passed in.
|
|
68
|
+
# The character set used for encoding will be the encoding on the string passed in.
|
|
70
69
|
#
|
|
71
70
|
# Example:
|
|
72
71
|
#
|
|
73
72
|
# Mail::Encodings.param_encode("This is fun") #=> "us-ascii'en'This%20is%20fun"
|
|
74
73
|
def Encodings.param_encode(str)
|
|
75
74
|
case
|
|
76
|
-
when str.ascii_only? && str
|
|
75
|
+
when str.ascii_only? && TOKEN_UNSAFE.match?(str)
|
|
77
76
|
%Q{"#{str}"}
|
|
78
77
|
when str.ascii_only?
|
|
79
78
|
str
|
|
80
79
|
else
|
|
81
|
-
|
|
80
|
+
Utilities.param_encode(str)
|
|
82
81
|
end
|
|
83
82
|
end
|
|
84
83
|
|
|
@@ -92,15 +91,15 @@ module Mail
|
|
|
92
91
|
# str.encoding #=> 'ISO-8859-1' ## Only on Ruby 1.9
|
|
93
92
|
# str #=> "This is fun"
|
|
94
93
|
def Encodings.param_decode(str, encoding)
|
|
95
|
-
|
|
94
|
+
Utilities.param_decode(str, encoding)
|
|
96
95
|
end
|
|
97
96
|
|
|
98
97
|
# Decodes or encodes a string as needed for either Base64 or QP encoding types in
|
|
99
98
|
# the =?<encoding>?[QB]?<string>?=" format.
|
|
100
99
|
#
|
|
101
100
|
# The output type needs to be :decode to decode the input string or :encode to
|
|
102
|
-
# encode the input string. The character set used for encoding will
|
|
103
|
-
#
|
|
101
|
+
# encode the input string. The character set used for encoding will be the
|
|
102
|
+
# encoding on the string passed in.
|
|
104
103
|
#
|
|
105
104
|
# On encoding, will only send out Base64 encoded strings.
|
|
106
105
|
def Encodings.decode_encode(str, output_type)
|
|
@@ -111,7 +110,7 @@ module Mail
|
|
|
111
110
|
if str.ascii_only?
|
|
112
111
|
str
|
|
113
112
|
else
|
|
114
|
-
Encodings.b_value_encode(str,
|
|
113
|
+
Encodings.b_value_encode(str, str.encoding)
|
|
115
114
|
end
|
|
116
115
|
end
|
|
117
116
|
end
|
|
@@ -122,7 +121,7 @@ module Mail
|
|
|
122
121
|
# String has to be of the format =?<encoding>?[QB]?<string>?=
|
|
123
122
|
def Encodings.value_decode(str)
|
|
124
123
|
# Optimization: If there's no encoded-words in the string, just return it
|
|
125
|
-
return str unless str
|
|
124
|
+
return str unless ENCODED_VALUE.match?(str)
|
|
126
125
|
|
|
127
126
|
lines = collapse_adjacent_encodings(str)
|
|
128
127
|
|
|
@@ -145,13 +144,8 @@ module Mail
|
|
|
145
144
|
output
|
|
146
145
|
elsif to_encoding
|
|
147
146
|
begin
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
else
|
|
151
|
-
require 'iconv'
|
|
152
|
-
Iconv.iconv(to_encoding, 'UTF-8', output).first
|
|
153
|
-
end
|
|
154
|
-
rescue Iconv::IllegalSequence, Iconv::InvalidEncoding, Errno::EINVAL
|
|
147
|
+
output.encode(to_encoding)
|
|
148
|
+
rescue Errno::EINVAL
|
|
155
149
|
# the 'from' parameter specifies a charset other than what the text
|
|
156
150
|
# actually is...not much we can do in this case but just return the
|
|
157
151
|
# unconverted text.
|
|
@@ -176,42 +170,23 @@ module Mail
|
|
|
176
170
|
def Encodings.encode_non_usascii(address, charset)
|
|
177
171
|
return address if address.ascii_only? or charset.nil?
|
|
178
172
|
|
|
179
|
-
#
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
# Then loop through all remaining items and encode as needed
|
|
185
|
-
tokens = address.split(/\s/)
|
|
186
|
-
|
|
187
|
-
map_with_index(tokens) do |word, i|
|
|
188
|
-
if word.ascii_only?
|
|
189
|
-
word
|
|
190
|
-
else
|
|
191
|
-
previous_non_ascii = i>0 && tokens[i-1] && !tokens[i-1].ascii_only?
|
|
192
|
-
if previous_non_ascii #why are we adding an extra space here?
|
|
193
|
-
word = " #{word}"
|
|
194
|
-
end
|
|
195
|
-
Encodings.b_value_encode(word, charset)
|
|
196
|
-
end
|
|
197
|
-
end.join(' ')
|
|
198
|
-
end
|
|
199
|
-
end
|
|
173
|
+
# Encode all strings embedded inside of quotes
|
|
174
|
+
address = address.gsub(/("[^"]*[^\/]")/) { |s| Encodings.b_value_encode(unquote(s), charset) }
|
|
175
|
+
|
|
176
|
+
# Then loop through all remaining items and encode as needed
|
|
177
|
+
tokens = address.split(/\s/)
|
|
200
178
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
179
|
+
map_with_index(tokens) do |word, i|
|
|
180
|
+
if word.ascii_only?
|
|
181
|
+
word
|
|
182
|
+
else
|
|
183
|
+
previous_non_ascii = i>0 && tokens[i-1] && !tokens[i-1].ascii_only?
|
|
184
|
+
if previous_non_ascii #why are we adding an extra space here?
|
|
185
|
+
word = " #{word}"
|
|
186
|
+
end
|
|
187
|
+
Encodings.b_value_encode(word, charset)
|
|
206
188
|
end
|
|
207
|
-
|
|
208
|
-
ensure
|
|
209
|
-
$KCODE = original_kcode if original_kcode
|
|
210
|
-
end
|
|
211
|
-
else
|
|
212
|
-
def Encodings.with_ascii_kcode #:nodoc:
|
|
213
|
-
yield
|
|
214
|
-
end
|
|
189
|
+
end.join(' ')
|
|
215
190
|
end
|
|
216
191
|
|
|
217
192
|
# Encode a string with Base64 Encoding and returns it ready to be inserted
|
|
@@ -226,7 +201,7 @@ module Mail
|
|
|
226
201
|
string
|
|
227
202
|
else
|
|
228
203
|
Encodings.each_base64_chunk_byterange(string, 60).map do |chunk|
|
|
229
|
-
str, encoding =
|
|
204
|
+
str, encoding = Utilities.b_value_encode(chunk, encoding)
|
|
230
205
|
"=?#{encoding}?B?#{str.chomp}?="
|
|
231
206
|
end.join(" ")
|
|
232
207
|
end
|
|
@@ -241,7 +216,7 @@ module Mail
|
|
|
241
216
|
# #=> "=?UTF-8?Q?This_is_=E3=81=82_string?="
|
|
242
217
|
def Encodings.q_value_encode(encoded_str, encoding = nil)
|
|
243
218
|
return encoded_str if encoded_str.to_s.ascii_only?
|
|
244
|
-
string, encoding =
|
|
219
|
+
string, encoding = Utilities.q_value_encode(encoded_str, encoding)
|
|
245
220
|
string.gsub!("=\r\n", '') # We already have limited the string to the length we want
|
|
246
221
|
map_lines(string) do |str|
|
|
247
222
|
"=?#{encoding}?Q?#{str.chomp.gsub(/ /, '_')}?="
|
|
@@ -257,7 +232,7 @@ module Mail
|
|
|
257
232
|
# Encodings.b_value_decode("=?UTF-8?B?VGhpcyBpcyDjgYIgc3RyaW5n?=")
|
|
258
233
|
# #=> 'This is あ string'
|
|
259
234
|
def Encodings.b_value_decode(str)
|
|
260
|
-
|
|
235
|
+
Utilities.b_value_decode(str)
|
|
261
236
|
end
|
|
262
237
|
|
|
263
238
|
# Decodes a Quoted-Printable string from the "=?UTF-8?Q?This_is_=E3=81=82_string?=" format
|
|
@@ -267,11 +242,7 @@ module Mail
|
|
|
267
242
|
# Encodings.q_value_decode("=?UTF-8?Q?This_is_=E3=81=82_string?=")
|
|
268
243
|
# #=> 'This is あ string'
|
|
269
244
|
def Encodings.q_value_decode(str)
|
|
270
|
-
|
|
271
|
-
end
|
|
272
|
-
|
|
273
|
-
def Encodings.find_encoding(str)
|
|
274
|
-
RUBY_VERSION >= '1.9' ? str.encoding : $KCODE
|
|
245
|
+
Utilities.q_value_decode(str)
|
|
275
246
|
end
|
|
276
247
|
|
|
277
248
|
# Gets the encoding type (Q or B) from the string.
|
|
@@ -329,7 +300,7 @@ module Mail
|
|
|
329
300
|
charsize = chr.bytesize
|
|
330
301
|
|
|
331
302
|
if chunksize + charsize > max_bytesize_per_chunk
|
|
332
|
-
yield
|
|
303
|
+
yield Utilities.string_byteslice(str, offset, chunksize)
|
|
333
304
|
offset += chunksize
|
|
334
305
|
chunksize = charsize
|
|
335
306
|
else
|
|
@@ -337,7 +308,7 @@ module Mail
|
|
|
337
308
|
end
|
|
338
309
|
end
|
|
339
310
|
|
|
340
|
-
yield
|
|
311
|
+
yield Utilities.string_byteslice(str, offset, chunksize)
|
|
341
312
|
end
|
|
342
313
|
end
|
|
343
314
|
end
|
data/lib/mail/envelope.rb
CHANGED
|
@@ -1,31 +1,28 @@
|
|
|
1
1
|
# encoding: utf-8
|
|
2
2
|
# frozen_string_literal: true
|
|
3
|
-
#
|
|
3
|
+
#
|
|
4
4
|
# = Mail Envelope
|
|
5
|
-
#
|
|
5
|
+
#
|
|
6
6
|
# The Envelope class provides a field for the first line in an
|
|
7
7
|
# mbox file, that looks like "From mikel@test.lindsaar.net DATETIME"
|
|
8
|
-
#
|
|
8
|
+
#
|
|
9
9
|
# This envelope class reads that line, and turns it into an
|
|
10
10
|
# Envelope.from and Envelope.date for your use.
|
|
11
|
+
|
|
11
12
|
module Mail
|
|
12
|
-
class Envelope <
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
super(FIELD_NAME, args.last.to_s)
|
|
16
|
-
end
|
|
17
|
-
|
|
13
|
+
class Envelope < NamedStructuredField
|
|
14
|
+
NAME = 'Envelope-From'
|
|
15
|
+
|
|
18
16
|
def element
|
|
19
17
|
@element ||= Mail::EnvelopeFromElement.new(value)
|
|
20
18
|
end
|
|
21
|
-
|
|
22
|
-
def date
|
|
23
|
-
::DateTime.parse("#{element.date_time}")
|
|
24
|
-
end
|
|
25
19
|
|
|
26
20
|
def from
|
|
27
21
|
element.address
|
|
28
22
|
end
|
|
29
|
-
|
|
23
|
+
|
|
24
|
+
def date
|
|
25
|
+
element.date_time
|
|
26
|
+
end
|
|
30
27
|
end
|
|
31
28
|
end
|