mail 2.6.1 → 2.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/MIT-LICENSE +1 -1
- data/README.md +92 -80
- data/lib/mail/attachments_list.rb +11 -5
- data/lib/mail/body.rb +81 -44
- data/lib/mail/check_delivery_params.rb +50 -10
- data/lib/mail/configuration.rb +3 -0
- data/lib/mail/{patterns.rb → constants.rb} +26 -6
- data/lib/mail/core_extensions/smtp.rb +20 -16
- data/lib/mail/core_extensions/string.rb +1 -27
- data/lib/mail/elements/address.rb +81 -93
- data/lib/mail/elements/address_list.rb +12 -29
- data/lib/mail/elements/content_disposition_element.rb +9 -15
- data/lib/mail/elements/content_location_element.rb +8 -12
- data/lib/mail/elements/content_transfer_encoding_element.rb +6 -10
- data/lib/mail/elements/content_type_element.rb +9 -19
- data/lib/mail/elements/date_time_element.rb +7 -14
- data/lib/mail/elements/envelope_from_element.rb +15 -21
- data/lib/mail/elements/message_ids_element.rb +12 -14
- data/lib/mail/elements/mime_version_element.rb +7 -14
- data/lib/mail/elements/phrase_list.rb +7 -9
- data/lib/mail/elements/received_element.rb +10 -15
- data/lib/mail/elements.rb +1 -0
- data/lib/mail/encodings/7bit.rb +6 -15
- data/lib/mail/encodings/8bit.rb +5 -18
- data/lib/mail/encodings/base64.rb +15 -10
- data/lib/mail/encodings/binary.rb +4 -22
- data/lib/mail/encodings/identity.rb +24 -0
- data/lib/mail/encodings/quoted_printable.rb +13 -7
- data/lib/mail/encodings/transfer_encoding.rb +47 -28
- data/lib/mail/encodings/unix_to_unix.rb +20 -0
- data/lib/mail/encodings.rb +121 -82
- data/lib/mail/envelope.rb +2 -1
- data/lib/mail/field.rb +114 -62
- data/lib/mail/field_list.rb +2 -1
- data/lib/mail/fields/bcc_field.rb +17 -5
- data/lib/mail/fields/cc_field.rb +2 -2
- data/lib/mail/fields/comments_field.rb +2 -1
- data/lib/mail/fields/common/address_container.rb +3 -2
- data/lib/mail/fields/common/common_address.rb +40 -14
- data/lib/mail/fields/common/common_date.rb +2 -1
- data/lib/mail/fields/common/common_field.rb +6 -11
- data/lib/mail/fields/common/common_message_id.rb +3 -2
- data/lib/mail/fields/common/parameter_hash.rb +5 -4
- data/lib/mail/fields/content_description_field.rb +2 -1
- data/lib/mail/fields/content_disposition_field.rb +14 -13
- data/lib/mail/fields/content_id_field.rb +5 -4
- data/lib/mail/fields/content_location_field.rb +3 -2
- data/lib/mail/fields/content_transfer_encoding_field.rb +3 -2
- data/lib/mail/fields/content_type_field.rb +7 -11
- data/lib/mail/fields/date_field.rb +4 -4
- data/lib/mail/fields/from_field.rb +2 -2
- data/lib/mail/fields/in_reply_to_field.rb +2 -1
- data/lib/mail/fields/keywords_field.rb +3 -3
- data/lib/mail/fields/message_id_field.rb +3 -2
- data/lib/mail/fields/mime_version_field.rb +4 -3
- data/lib/mail/fields/optional_field.rb +5 -1
- data/lib/mail/fields/received_field.rb +5 -4
- data/lib/mail/fields/references_field.rb +2 -1
- data/lib/mail/fields/reply_to_field.rb +2 -2
- data/lib/mail/fields/resent_bcc_field.rb +2 -2
- data/lib/mail/fields/resent_cc_field.rb +2 -2
- data/lib/mail/fields/resent_date_field.rb +2 -2
- data/lib/mail/fields/resent_from_field.rb +2 -2
- data/lib/mail/fields/resent_message_id_field.rb +2 -1
- data/lib/mail/fields/resent_sender_field.rb +2 -2
- data/lib/mail/fields/resent_to_field.rb +2 -2
- data/lib/mail/fields/return_path_field.rb +2 -2
- data/lib/mail/fields/sender_field.rb +2 -2
- data/lib/mail/fields/structured_field.rb +1 -0
- data/lib/mail/fields/subject_field.rb +2 -1
- data/lib/mail/fields/to_field.rb +2 -2
- data/lib/mail/fields/unstructured_field.rb +28 -10
- data/lib/mail/fields.rb +1 -0
- data/lib/mail/header.rb +18 -14
- data/lib/mail/indifferent_hash.rb +1 -0
- data/lib/mail/mail.rb +6 -11
- data/lib/mail/matchers/attachment_matchers.rb +29 -0
- data/lib/mail/matchers/has_sent_mail.rb +53 -9
- data/lib/mail/message.rb +99 -89
- data/lib/mail/multibyte/chars.rb +32 -30
- data/lib/mail/multibyte/unicode.rb +31 -26
- data/lib/mail/multibyte/utils.rb +1 -0
- data/lib/mail/multibyte.rb +65 -15
- data/lib/mail/network/delivery_methods/exim.rb +7 -10
- data/lib/mail/network/delivery_methods/file_delivery.rb +5 -8
- data/lib/mail/network/delivery_methods/logger_delivery.rb +37 -0
- data/lib/mail/network/delivery_methods/sendmail.rb +17 -11
- data/lib/mail/network/delivery_methods/smtp.rb +60 -53
- data/lib/mail/network/delivery_methods/smtp_connection.rb +11 -6
- data/lib/mail/network/delivery_methods/test_mailer.rb +6 -8
- data/lib/mail/network/retriever_methods/base.rb +1 -0
- data/lib/mail/network/retriever_methods/imap.rb +19 -5
- data/lib/mail/network/retriever_methods/pop3.rb +4 -1
- data/lib/mail/network/retriever_methods/test_retriever.rb +2 -1
- data/lib/mail/network.rb +2 -0
- data/lib/mail/parser_tools.rb +15 -0
- data/lib/mail/parsers/address_lists_parser.rb +33208 -104
- data/lib/mail/parsers/address_lists_parser.rl +172 -0
- data/lib/mail/parsers/content_disposition_parser.rb +877 -49
- data/lib/mail/parsers/content_disposition_parser.rl +82 -0
- data/lib/mail/parsers/content_location_parser.rb +804 -23
- data/lib/mail/parsers/content_location_parser.rl +71 -0
- data/lib/mail/parsers/content_transfer_encoding_parser.rb +502 -19
- data/lib/mail/parsers/content_transfer_encoding_parser.rl +64 -0
- data/lib/mail/parsers/content_type_parser.rb +1024 -46
- data/lib/mail/parsers/content_type_parser.rl +83 -0
- data/lib/mail/parsers/date_time_parser.rb +872 -23
- data/lib/mail/parsers/date_time_parser.rl +62 -0
- data/lib/mail/parsers/envelope_from_parser.rb +3570 -34
- data/lib/mail/parsers/envelope_from_parser.rl +82 -0
- data/lib/mail/parsers/message_ids_parser.rb +2840 -25
- data/lib/mail/parsers/message_ids_parser.rl +82 -0
- data/lib/mail/parsers/mime_version_parser.rb +492 -26
- data/lib/mail/parsers/mime_version_parser.rl +61 -0
- data/lib/mail/parsers/phrase_lists_parser.rb +862 -17
- data/lib/mail/parsers/phrase_lists_parser.rl +83 -0
- data/lib/mail/parsers/received_parser.rb +8765 -36
- data/lib/mail/parsers/received_parser.rl +84 -0
- data/lib/mail/parsers/rfc2045_content_transfer_encoding.rl +13 -0
- data/lib/mail/parsers/rfc2045_content_type.rl +25 -0
- data/lib/mail/parsers/rfc2045_mime.rl +16 -0
- data/lib/mail/parsers/rfc2183_content_disposition.rl +15 -0
- data/lib/mail/parsers/rfc3629_utf8.rl +19 -0
- data/lib/mail/parsers/rfc5234_abnf_core_rules.rl +22 -0
- data/lib/mail/parsers/rfc5322.rl +59 -0
- data/lib/mail/parsers/rfc5322_address.rl +72 -0
- data/lib/mail/parsers/{ragel/date_time.rl → rfc5322_date_time.rl} +8 -1
- data/lib/mail/parsers/rfc5322_lexical_tokens.rl +60 -0
- data/lib/mail/parsers.rb +17 -24
- data/lib/mail/part.rb +8 -5
- data/lib/mail/parts_list.rb +31 -14
- data/lib/mail/utilities.rb +112 -13
- data/lib/mail/values/unicode_tables.dat +0 -0
- data/lib/mail/version.rb +8 -15
- data/lib/mail/version_specific/ruby_1_8.rb +52 -8
- data/lib/mail/version_specific/ruby_1_9.rb +143 -24
- data/lib/mail.rb +8 -14
- metadata +71 -81
- data/CHANGELOG.rdoc +0 -752
- data/CONTRIBUTING.md +0 -60
- data/Dependencies.txt +0 -2
- data/Gemfile +0 -15
- data/Rakefile +0 -29
- data/TODO.rdoc +0 -9
- data/VERSION +0 -4
- data/lib/mail/core_extensions/nil.rb +0 -19
- data/lib/mail/core_extensions/object.rb +0 -13
- data/lib/mail/core_extensions/string/access.rb +0 -145
- data/lib/mail/core_extensions/string/multibyte.rb +0 -78
- data/lib/mail/multibyte/exceptions.rb +0 -8
- data/lib/mail/parsers/ragel/common.rl +0 -184
- data/lib/mail/parsers/ragel/parser_info.rb +0 -61
- data/lib/mail/parsers/ragel/ruby/machines/address_lists_machine.rb +0 -14864
- data/lib/mail/parsers/ragel/ruby/machines/address_lists_machine.rb.rl +0 -37
- data/lib/mail/parsers/ragel/ruby/machines/content_disposition_machine.rb +0 -751
- data/lib/mail/parsers/ragel/ruby/machines/content_disposition_machine.rb.rl +0 -37
- data/lib/mail/parsers/ragel/ruby/machines/content_location_machine.rb +0 -614
- data/lib/mail/parsers/ragel/ruby/machines/content_location_machine.rb.rl +0 -37
- data/lib/mail/parsers/ragel/ruby/machines/content_transfer_encoding_machine.rb +0 -447
- data/lib/mail/parsers/ragel/ruby/machines/content_transfer_encoding_machine.rb.rl +0 -37
- data/lib/mail/parsers/ragel/ruby/machines/content_type_machine.rb +0 -825
- data/lib/mail/parsers/ragel/ruby/machines/content_type_machine.rb.rl +0 -37
- data/lib/mail/parsers/ragel/ruby/machines/date_time_machine.rb +0 -817
- data/lib/mail/parsers/ragel/ruby/machines/date_time_machine.rb.rl +0 -37
- data/lib/mail/parsers/ragel/ruby/machines/envelope_from_machine.rb +0 -2129
- data/lib/mail/parsers/ragel/ruby/machines/envelope_from_machine.rb.rl +0 -37
- data/lib/mail/parsers/ragel/ruby/machines/message_ids_machine.rb +0 -1570
- data/lib/mail/parsers/ragel/ruby/machines/message_ids_machine.rb.rl +0 -37
- data/lib/mail/parsers/ragel/ruby/machines/mime_version_machine.rb +0 -440
- data/lib/mail/parsers/ragel/ruby/machines/mime_version_machine.rb.rl +0 -37
- data/lib/mail/parsers/ragel/ruby/machines/phrase_lists_machine.rb +0 -564
- data/lib/mail/parsers/ragel/ruby/machines/phrase_lists_machine.rb.rl +0 -37
- data/lib/mail/parsers/ragel/ruby/machines/rb_actions.rl +0 -51
- data/lib/mail/parsers/ragel/ruby/machines/received_machine.rb +0 -5144
- data/lib/mail/parsers/ragel/ruby/machines/received_machine.rb.rl +0 -37
- data/lib/mail/parsers/ragel/ruby/parser.rb.rl.erb +0 -37
- data/lib/mail/parsers/ragel/ruby.rb +0 -39
- data/lib/mail/parsers/ragel.rb +0 -17
@@ -1,20 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module Mail
|
2
|
-
module CheckDeliveryParams
|
3
|
-
|
4
|
-
|
5
|
-
|
3
|
+
module CheckDeliveryParams #:nodoc:
|
4
|
+
class << self
|
5
|
+
def check(mail)
|
6
|
+
[ check_from(mail.smtp_envelope_from),
|
7
|
+
check_to(mail.smtp_envelope_to),
|
8
|
+
check_message(mail) ]
|
6
9
|
end
|
7
10
|
|
8
|
-
|
9
|
-
|
11
|
+
def check_from(addr)
|
12
|
+
if Utilities.blank?(addr)
|
13
|
+
raise ArgumentError, "SMTP From address may not be blank: #{addr.inspect}"
|
14
|
+
end
|
15
|
+
|
16
|
+
check_addr 'From', addr
|
17
|
+
end
|
18
|
+
|
19
|
+
def check_to(addrs)
|
20
|
+
if Utilities.blank?(addrs)
|
21
|
+
raise ArgumentError, "SMTP To address may not be blank: #{addrs.inspect}"
|
22
|
+
end
|
23
|
+
|
24
|
+
Array(addrs).map do |addr|
|
25
|
+
check_addr 'To', addr
|
26
|
+
end
|
10
27
|
end
|
11
28
|
|
12
|
-
|
13
|
-
|
14
|
-
|
29
|
+
def check_addr(addr_name, addr)
|
30
|
+
validate_smtp_addr addr do |error_message|
|
31
|
+
raise ArgumentError, "SMTP #{addr_name} address #{error_message}: #{addr.inspect}"
|
32
|
+
end
|
15
33
|
end
|
16
34
|
|
17
|
-
|
35
|
+
def validate_smtp_addr(addr)
|
36
|
+
if addr
|
37
|
+
if addr.bytesize > 2048
|
38
|
+
yield 'may not exceed 2kB'
|
39
|
+
end
|
40
|
+
|
41
|
+
if /[\r\n]/ =~ addr
|
42
|
+
yield 'may not contain CR or LF line breaks'
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
addr
|
47
|
+
end
|
48
|
+
|
49
|
+
def check_message(message)
|
50
|
+
message = message.encoded if message.respond_to?(:encoded)
|
51
|
+
|
52
|
+
if Utilities.blank?(message)
|
53
|
+
raise ArgumentError, 'An encoded message is required to send an email'
|
54
|
+
end
|
55
|
+
|
56
|
+
message
|
57
|
+
end
|
18
58
|
end
|
19
59
|
end
|
20
60
|
end
|
data/lib/mail/configuration.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
+
# frozen_string_literal: true
|
2
3
|
#
|
3
4
|
# Thanks to Nicolas Fouché for this wrapper
|
4
5
|
#
|
@@ -41,6 +42,8 @@ module Mail
|
|
41
42
|
Mail::SMTPConnection
|
42
43
|
when :test
|
43
44
|
Mail::TestMailer
|
45
|
+
when :logger
|
46
|
+
Mail::LoggerDelivery
|
44
47
|
else
|
45
48
|
method
|
46
49
|
end
|
@@ -1,21 +1,22 @@
|
|
1
1
|
# encoding: us-ascii
|
2
|
+
# frozen_string_literal: true
|
2
3
|
module Mail
|
3
|
-
module
|
4
|
+
module Constants
|
4
5
|
white_space = %Q|\x9\x20|
|
5
6
|
text = %Q|\x1-\x8\xB\xC\xE-\x7f|
|
6
7
|
field_name = %Q|\x21-\x39\x3b-\x7e|
|
7
8
|
qp_safe = %Q|\x20-\x3c\x3e-\x7e|
|
8
|
-
|
9
|
+
|
9
10
|
aspecial = %Q|()<>[]:;@\\,."| # RFC5322
|
10
11
|
tspecial = %Q|()<>@,;:\\"/[]?=| # RFC2045
|
11
12
|
sp = %Q| |
|
12
13
|
control = %Q|\x00-\x1f\x7f-\xff|
|
13
|
-
|
14
|
+
|
14
15
|
if control.respond_to?(:force_encoding)
|
15
|
-
control = control.force_encoding(Encoding::BINARY)
|
16
|
+
control = control.dup.force_encoding(Encoding::BINARY)
|
16
17
|
end
|
17
|
-
|
18
|
-
CRLF = /\r
|
18
|
+
|
19
|
+
CRLF = /\r?\n/
|
19
20
|
WSP = /[#{white_space}]/
|
20
21
|
FWS = /#{CRLF}#{WSP}*/
|
21
22
|
TEXT = /[#{text}]/ # + obs-text
|
@@ -33,5 +34,24 @@ module Mail
|
|
33
34
|
ATOM_UNSAFE = /[#{Regexp.quote aspecial}#{control}#{sp}]/n
|
34
35
|
PHRASE_UNSAFE = /[#{Regexp.quote aspecial}#{control}]/n
|
35
36
|
TOKEN_UNSAFE = /[#{Regexp.quote tspecial}#{control}#{sp}]/n
|
37
|
+
ENCODED_VALUE = /\=\?([^?]+)\?([QB])\?[^?]*?\?\=/mi
|
38
|
+
FULL_ENCODED_VALUE = /(\=\?[^?]+\?[QB]\?[^?]*?\?\=)/mi
|
39
|
+
|
40
|
+
EMPTY = ''
|
41
|
+
SPACE = ' '
|
42
|
+
UNDERSCORE = '_'
|
43
|
+
HYPHEN = '-'
|
44
|
+
COLON = ':'
|
45
|
+
ASTERISK = '*'
|
46
|
+
CR = "\r"
|
47
|
+
LF = "\n"
|
48
|
+
CR_ENCODED = "=0D"
|
49
|
+
LF_ENCODED = "=0A"
|
50
|
+
CAPITAL_M = 'M'
|
51
|
+
EQUAL_LF = "=\n"
|
52
|
+
NULL_SENDER = '<>'
|
53
|
+
|
54
|
+
Q_VALUES = ['Q','q']
|
55
|
+
B_VALUES = ['B','b']
|
36
56
|
end
|
37
57
|
end
|
@@ -1,24 +1,28 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
-
|
3
|
-
class SMTP
|
4
|
-
# This is a backport of r30294 from ruby trunk because of a bug in net/smtp.
|
5
|
-
# http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=30294
|
6
|
-
#
|
7
|
-
# Fixed in what will be Ruby 1.9.3 - tlsconnect also does not exist in some early versions of ruby
|
8
|
-
begin
|
9
|
-
alias_method :original_tlsconnect, :tlsconnect
|
2
|
+
# frozen_string_literal: true
|
10
3
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
4
|
+
# This is a backport of r30294 from ruby trunk because of a bug in net/smtp.
|
5
|
+
# http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=30294
|
6
|
+
#
|
7
|
+
# Fixed in Ruby 1.9.3 - tlsconnect also does not exist in some early versions of ruby
|
8
|
+
if RUBY_VERSION < '1.9.3'
|
9
|
+
module Net
|
10
|
+
class SMTP
|
11
|
+
begin
|
12
|
+
alias_method :original_tlsconnect, :tlsconnect
|
13
|
+
|
14
|
+
def tlsconnect(s)
|
15
|
+
verified = false
|
16
|
+
begin
|
17
|
+
original_tlsconnect(s).tap { verified = true }
|
18
|
+
ensure
|
19
|
+
unless verified
|
20
|
+
s.close rescue nil
|
21
|
+
end
|
18
22
|
end
|
19
23
|
end
|
24
|
+
rescue NameError
|
20
25
|
end
|
21
|
-
rescue NameError
|
22
26
|
end
|
23
27
|
end
|
24
28
|
end
|
@@ -1,29 +1,7 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
+
# frozen_string_literal: true
|
2
3
|
class String #:nodoc:
|
3
4
|
|
4
|
-
if RUBY_VERSION >= '1.9'
|
5
|
-
# This 1.9 only regex can save a reasonable amount of time (~20%)
|
6
|
-
# by not matching "\r\n" so the string is returned unchanged in
|
7
|
-
# the common case.
|
8
|
-
CRLF_REGEX = Regexp.new("(?<!\r)\n|\r(?!\n)")
|
9
|
-
else
|
10
|
-
CRLF_REGEX = /\n|\r\n|\r/
|
11
|
-
end
|
12
|
-
|
13
|
-
def to_crlf
|
14
|
-
to_str.gsub(CRLF_REGEX, "\r\n")
|
15
|
-
end
|
16
|
-
|
17
|
-
def to_lf
|
18
|
-
to_str.gsub(/\r\n|\r/, "\n")
|
19
|
-
end
|
20
|
-
|
21
|
-
unless String.instance_methods(false).map {|m| m.to_sym}.include?(:blank?)
|
22
|
-
def blank?
|
23
|
-
self !~ /\S/
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
5
|
unless method_defined?(:ascii_only?)
|
28
6
|
# Backport from Ruby 1.9 checks for non-us-ascii characters.
|
29
7
|
def ascii_only?
|
@@ -33,10 +11,6 @@ class String #:nodoc:
|
|
33
11
|
MATCH_NON_US_ASCII = /[^\x00-\x7f]/
|
34
12
|
end
|
35
13
|
|
36
|
-
def not_ascii_only?
|
37
|
-
!ascii_only?
|
38
|
-
end
|
39
|
-
|
40
14
|
unless method_defined?(:bytesize)
|
41
15
|
alias :bytesize :length
|
42
16
|
end
|
@@ -1,17 +1,19 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
require 'mail/parsers/address_lists_parser'
|
4
|
+
|
2
5
|
module Mail
|
3
6
|
class Address
|
4
|
-
|
5
7
|
include Mail::Utilities
|
6
|
-
|
8
|
+
|
7
9
|
# Mail::Address handles all email addresses in Mail. It takes an email address string
|
8
10
|
# and parses it, breaking it down into its component parts and allowing you to get the
|
9
11
|
# address, comments, display name, name, local part, domain part and fully formatted
|
10
12
|
# address.
|
11
|
-
#
|
13
|
+
#
|
12
14
|
# Mail::Address requires a correctly formatted email address per RFC2822 or RFC822. It
|
13
15
|
# handles all obsolete versions including obsolete domain routing on the local part.
|
14
|
-
#
|
16
|
+
#
|
15
17
|
# a = Address.new('Mikel Lindsaar (My email address) <mikel@test.lindsaar.net>')
|
16
18
|
# a.format #=> 'Mikel Lindsaar <mikel@test.lindsaar.net> (My email address)'
|
17
19
|
# a.address #=> 'mikel@test.lindsaar.net'
|
@@ -21,16 +23,14 @@ module Mail
|
|
21
23
|
# a.comments #=> ['My email address']
|
22
24
|
# a.to_s #=> 'Mikel Lindsaar <mikel@test.lindsaar.net> (My email address)'
|
23
25
|
def initialize(value = nil)
|
24
|
-
@output_type = :decode
|
25
26
|
if value.nil?
|
26
27
|
@parsed = false
|
27
28
|
@data = nil
|
28
|
-
return
|
29
29
|
else
|
30
30
|
parse(value)
|
31
31
|
end
|
32
32
|
end
|
33
|
-
|
33
|
+
|
34
34
|
# Returns the raw input of the passed in string, this is before it is passed
|
35
35
|
# by the parser.
|
36
36
|
def raw
|
@@ -44,111 +44,120 @@ 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
|
-
|
51
|
-
elsif display_name
|
52
|
-
[quote_phrase(
|
53
|
-
elsif address
|
54
|
-
[
|
50
|
+
EMPTY
|
51
|
+
elsif name = display_name(output_type)
|
52
|
+
[quote_phrase(name), "<#{address(output_type)}>", format_comments].compact.join(SPACE)
|
53
|
+
elsif a = address(output_type)
|
54
|
+
[a, format_comments].compact.join(SPACE)
|
55
55
|
else
|
56
56
|
raw
|
57
57
|
end
|
58
58
|
end
|
59
59
|
|
60
|
-
# Returns the address that is in the address itself. That is, the
|
60
|
+
# Returns the address that is in the address itself. That is, the
|
61
61
|
# local@domain string, without any angle brackets or the like.
|
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.
|
71
|
-
#
|
75
|
+
#
|
72
76
|
# a = Address.new
|
73
77
|
# a.address = 'Mikel Lindsaar (My email address) <mikel@test.lindsaar.net>'
|
74
78
|
# a.address #=> 'mikel@test.lindsaar.net'
|
75
79
|
def address=(value)
|
76
80
|
parse(value)
|
77
81
|
end
|
78
|
-
|
82
|
+
|
79
83
|
# Returns the display name of the email address passed in.
|
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.
|
90
|
-
#
|
94
|
+
#
|
91
95
|
# a = Address.new
|
92
96
|
# a.address = 'mikel@test.lindsaar.net'
|
93
97
|
# a.display_name = 'Mikel Lindsaar'
|
94
98
|
# a.format #=> 'Mikel Lindsaar <mikel@test.lindsaar.net>'
|
95
99
|
def display_name=( str )
|
96
|
-
@display_name = str
|
100
|
+
@display_name = str.nil? ? nil : str.dup # in case frozen
|
97
101
|
end
|
98
102
|
|
99
103
|
# Returns the local part (the left hand side of the @ sign in the email address) of
|
100
104
|
# the address
|
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
|
-
"#{@data.obs_domain_list}#{get_local.strip}" if get_local
|
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
|
110
114
|
# the address
|
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
|
-
strip_all_comments(get_domain) if get_domain
|
120
|
+
Encodings.decode_encode(strip_all_comments(get_domain), output_type) if get_domain
|
117
121
|
end
|
118
|
-
|
119
|
-
# Returns an array of comments that are in the email, or
|
122
|
+
|
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
|
135
|
+
if comments.nil? || comments.none?
|
127
136
|
nil
|
128
137
|
else
|
129
|
-
|
138
|
+
comments.map { |c| c.squeeze(SPACE) }
|
130
139
|
end
|
131
140
|
end
|
132
|
-
|
141
|
+
|
133
142
|
# Sometimes an address will not have a display name, but might have the name
|
134
143
|
# as a comment field after the address. This returns that name if it exists.
|
135
|
-
#
|
144
|
+
#
|
136
145
|
# a = Address.new('mikel@test.lindsaar.net (Mikel Lindsaar)')
|
137
146
|
# a.name #=> 'Mikel Lindsaar'
|
138
147
|
def name
|
139
148
|
parse unless @parsed
|
140
149
|
get_name
|
141
150
|
end
|
142
|
-
|
151
|
+
|
143
152
|
# Returns the format of the address, or returns nothing
|
144
|
-
#
|
153
|
+
#
|
145
154
|
# a = Address.new('Mikel Lindsaar (My email address) <mikel@test.lindsaar.net>')
|
146
155
|
# a.format #=> 'Mikel Lindsaar <mikel@test.lindsaar.net> (My email address)'
|
147
156
|
def to_s
|
148
157
|
parse unless @parsed
|
149
158
|
format
|
150
159
|
end
|
151
|
-
|
160
|
+
|
152
161
|
# Shows the Address object basic details, including the Address
|
153
162
|
# a = Address.new('Mikel (My email) <mikel@test.lindsaar.net>')
|
154
163
|
# a.inspect #=> "#<Mail::Address:14184910 Address: |Mikel <mikel@test.lindsaar.net> (My email)| >"
|
@@ -156,99 +165,78 @@ module Mail
|
|
156
165
|
parse unless @parsed
|
157
166
|
"#<#{self.class}:#{self.object_id} Address: |#{to_s}| >"
|
158
167
|
end
|
159
|
-
|
168
|
+
|
160
169
|
def encoded
|
161
|
-
|
162
|
-
format
|
170
|
+
format :encode
|
163
171
|
end
|
164
|
-
|
172
|
+
|
165
173
|
def decoded
|
166
|
-
|
167
|
-
|
174
|
+
format :decode
|
175
|
+
end
|
176
|
+
|
177
|
+
def group
|
178
|
+
@data && @data.group
|
168
179
|
end
|
169
180
|
|
170
181
|
private
|
171
|
-
|
182
|
+
|
172
183
|
def parse(value = nil)
|
173
184
|
@parsed = true
|
185
|
+
@data = nil
|
174
186
|
|
175
187
|
case value
|
176
|
-
when
|
177
|
-
@data = nil
|
178
|
-
nil
|
179
|
-
when Mail::Parsers::AddressStruct
|
188
|
+
when Mail::Parsers::AddressListsParser::AddressStruct
|
180
189
|
@data = value
|
181
190
|
when String
|
182
|
-
|
183
|
-
|
184
|
-
@data = nil
|
185
|
-
else
|
186
|
-
address_list = Mail::Parsers::AddressListsParser.new.parse(value)
|
191
|
+
unless Utilities.blank?(value)
|
192
|
+
address_list = Mail::Parsers::AddressListsParser.parse(value)
|
187
193
|
@data = address_list.addresses.first
|
188
194
|
end
|
189
195
|
end
|
190
196
|
end
|
191
|
-
|
197
|
+
|
192
198
|
def strip_all_comments(string)
|
193
|
-
unless
|
199
|
+
unless Utilities.blank?(comments)
|
194
200
|
comments.each do |comment|
|
195
|
-
string = string.gsub("(#{comment})",
|
201
|
+
string = string.gsub("(#{comment})", EMPTY)
|
196
202
|
end
|
197
203
|
end
|
198
204
|
string.strip
|
199
205
|
end
|
200
206
|
|
201
207
|
def strip_domain_comments(value)
|
202
|
-
unless
|
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})",
|
211
|
+
value = value.gsub("(#{comment})", EMPTY)
|
206
212
|
end
|
207
213
|
end
|
208
214
|
end
|
209
215
|
value.to_s.strip
|
210
216
|
end
|
211
|
-
|
217
|
+
|
212
218
|
def get_display_name
|
213
|
-
if @data.display_name
|
219
|
+
if @data && @data.display_name
|
214
220
|
str = strip_all_comments(@data.display_name.to_s)
|
215
|
-
elsif @data.comments
|
216
|
-
|
217
|
-
str = strip_domain_comments(format_comments)
|
218
|
-
else
|
219
|
-
str = nil
|
220
|
-
end
|
221
|
-
else
|
222
|
-
nil
|
223
|
-
end
|
224
|
-
|
225
|
-
if str.blank?
|
226
|
-
nil
|
227
|
-
else
|
228
|
-
str
|
221
|
+
elsif @data && @data.comments && @data.domain
|
222
|
+
str = strip_domain_comments(format_comments)
|
229
223
|
end
|
224
|
+
str unless Utilities.blank?(str)
|
230
225
|
end
|
231
|
-
|
226
|
+
|
232
227
|
def get_name
|
233
228
|
if display_name
|
234
229
|
str = display_name
|
235
|
-
|
236
|
-
|
237
|
-
comment_text = comments.join(' ').squeeze(" ")
|
238
|
-
str = "(#{comment_text})"
|
239
|
-
end
|
230
|
+
elsif comments
|
231
|
+
str = "(#{comments.join(SPACE).squeeze(SPACE)})"
|
240
232
|
end
|
241
233
|
|
242
|
-
|
243
|
-
nil
|
244
|
-
else
|
245
|
-
unparen(str)
|
246
|
-
end
|
234
|
+
unparen(str) unless Utilities.blank?(str)
|
247
235
|
end
|
248
|
-
|
236
|
+
|
249
237
|
def format_comments
|
250
238
|
if comments
|
251
|
-
comment_text = comments.map {|c| escape_paren(c) }.join(
|
239
|
+
comment_text = comments.map {|c| escape_paren(c) }.join(SPACE).squeeze(SPACE)
|
252
240
|
@format_comments ||= "(#{comment_text})"
|
253
241
|
else
|
254
242
|
nil
|
@@ -262,7 +250,7 @@ module Mail
|
|
262
250
|
def get_domain
|
263
251
|
@data && @data.domain
|
264
252
|
end
|
265
|
-
|
253
|
+
|
266
254
|
def get_comments
|
267
255
|
@data && @data.comments
|
268
256
|
end
|
@@ -1,51 +1,34 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
require 'mail/parsers/address_lists_parser'
|
4
|
+
|
2
5
|
module Mail
|
3
6
|
class AddressList # :nodoc:
|
7
|
+
attr_reader :addresses, :group_names
|
4
8
|
|
5
9
|
# Mail::AddressList is the class that parses To, From and other address fields from
|
6
10
|
# emails passed into Mail.
|
7
|
-
#
|
11
|
+
#
|
8
12
|
# AddressList provides a way to query the groups and mailbox lists of the passed in
|
9
13
|
# string.
|
10
|
-
#
|
14
|
+
#
|
11
15
|
# It can supply all addresses in an array, or return each address as an address object.
|
12
|
-
#
|
16
|
+
#
|
13
17
|
# Mail::AddressList requires a correctly formatted group or mailbox list per RFC2822 or
|
14
18
|
# RFC822. It also handles all obsolete versions in those RFCs.
|
15
|
-
#
|
19
|
+
#
|
16
20
|
# list = 'ada@test.lindsaar.net, My Group: mikel@test.lindsaar.net, Bob <bob@test.lindsaar.net>;'
|
17
21
|
# a = AddressList.new(list)
|
18
22
|
# a.addresses #=> [#<Mail::Address:14943130 Address: |ada@test.lindsaar.net...
|
19
23
|
# a.group_names #=> ["My Group"]
|
20
24
|
def initialize(string)
|
21
|
-
|
22
|
-
@
|
23
|
-
|
24
|
-
|
25
|
-
# Returns a list of address objects from the parsed line
|
26
|
-
def addresses
|
27
|
-
@addresses ||= @address_list.addresses.map do |address_data|
|
28
|
-
Mail::Address.new(address_data)
|
29
|
-
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
|
30
28
|
end
|
31
29
|
|
32
30
|
def addresses_grouped_by_group
|
33
|
-
|
34
|
-
|
35
|
-
@addresses_grouped_by_group = {}
|
36
|
-
|
37
|
-
@address_list.addresses.each do |address_data|
|
38
|
-
if group = address_data.group
|
39
|
-
@addresses_grouped_by_group[group] ||= []
|
40
|
-
@addresses_grouped_by_group[group] << Mail::Address.new(address_data)
|
41
|
-
end
|
42
|
-
end
|
43
|
-
@addresses_grouped_by_group
|
44
|
-
end
|
45
|
-
|
46
|
-
# Returns the names as an array of strings of all groups
|
47
|
-
def group_names # :nodoc:
|
48
|
-
@address_list.group_names
|
31
|
+
addresses.select(&:group).group_by(&:group)
|
49
32
|
end
|
50
33
|
end
|
51
34
|
end
|
@@ -1,26 +1,20 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
require 'mail/parsers/content_disposition_parser'
|
4
|
+
|
2
5
|
module Mail
|
3
6
|
class ContentDispositionElement # :nodoc:
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
content_disposition = Mail::Parsers::ContentDispositionParser.new.parse(cleaned(string))
|
7
|
+
attr_reader :disposition_type, :parameters
|
8
|
+
|
9
|
+
def initialize(string)
|
10
|
+
content_disposition = Mail::Parsers::ContentDispositionParser.parse(cleaned(string))
|
9
11
|
@disposition_type = content_disposition.disposition_type
|
10
12
|
@parameters = content_disposition.parameters
|
11
13
|
end
|
12
|
-
|
13
|
-
|
14
|
-
@disposition_type
|
15
|
-
end
|
16
|
-
|
17
|
-
def parameters
|
18
|
-
@parameters
|
19
|
-
end
|
20
|
-
|
14
|
+
|
15
|
+
private
|
21
16
|
def cleaned(string)
|
22
17
|
string =~ /(.+);\s*$/ ? $1 : string
|
23
18
|
end
|
24
|
-
|
25
19
|
end
|
26
20
|
end
|