mail 2.5.2 → 2.6.4
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 +124 -0
- data/CONTRIBUTING.md +21 -6
- data/Dependencies.txt +0 -1
- data/Gemfile +7 -22
- data/MIT-LICENSE +20 -0
- data/README.md +86 -31
- data/Rakefile +11 -22
- data/lib/mail/attachments_list.rb +4 -2
- data/lib/mail/body.rb +36 -11
- data/lib/mail/check_delivery_params.rb +13 -22
- data/lib/mail/configuration.rb +1 -0
- data/lib/mail/{patterns.rb → constants.rb} +29 -6
- data/lib/mail/core_extensions/smtp.rb +13 -13
- data/lib/mail/core_extensions/string/access.rb +1 -0
- data/lib/mail/core_extensions/string/multibyte.rb +1 -0
- data/lib/mail/core_extensions/string.rb +5 -17
- data/lib/mail/elements/address.rb +86 -145
- data/lib/mail/elements/address_list.rb +10 -42
- data/lib/mail/elements/content_disposition_element.rb +4 -7
- data/lib/mail/elements/content_location_element.rb +8 -11
- data/lib/mail/elements/content_transfer_encoding_element.rb +4 -10
- data/lib/mail/elements/content_type_element.rb +5 -8
- data/lib/mail/elements/date_time_element.rb +4 -7
- data/lib/mail/elements/envelope_from_element.rb +19 -13
- data/lib/mail/elements/message_ids_element.rb +8 -11
- data/lib/mail/elements/mime_version_element.rb +4 -7
- data/lib/mail/elements/phrase_list.rb +3 -7
- data/lib/mail/elements/received_element.rb +4 -7
- data/lib/mail/elements.rb +1 -0
- data/lib/mail/encodings/7bit.rb +1 -0
- data/lib/mail/encodings/8bit.rb +8 -2
- data/lib/mail/encodings/base64.rb +7 -1
- data/lib/mail/encodings/binary.rb +1 -0
- data/lib/mail/encodings/quoted_printable.rb +11 -4
- data/lib/mail/encodings/transfer_encoding.rb +27 -17
- data/lib/mail/encodings/unix_to_unix.rb +18 -0
- data/lib/mail/encodings.rb +54 -39
- data/lib/mail/envelope.rb +1 -5
- data/lib/mail/field.rb +81 -31
- data/lib/mail/field_list.rb +19 -18
- data/lib/mail/fields/bcc_field.rb +17 -5
- data/lib/mail/fields/cc_field.rb +3 -3
- data/lib/mail/fields/comments_field.rb +2 -1
- data/lib/mail/fields/common/address_container.rb +1 -0
- data/lib/mail/fields/common/common_address.rb +34 -28
- data/lib/mail/fields/common/common_date.rb +2 -8
- data/lib/mail/fields/common/common_field.rb +9 -5
- data/lib/mail/fields/common/common_message_id.rb +3 -2
- data/lib/mail/fields/common/parameter_hash.rb +4 -3
- data/lib/mail/fields/content_description_field.rb +1 -0
- data/lib/mail/fields/content_disposition_field.rb +13 -12
- data/lib/mail/fields/content_id_field.rb +4 -4
- data/lib/mail/fields/content_location_field.rb +2 -1
- data/lib/mail/fields/content_transfer_encoding_field.rb +4 -9
- data/lib/mail/fields/content_type_field.rb +4 -3
- data/lib/mail/fields/date_field.rb +16 -15
- data/lib/mail/fields/from_field.rb +3 -3
- data/lib/mail/fields/in_reply_to_field.rb +3 -1
- data/lib/mail/fields/keywords_field.rb +2 -2
- data/lib/mail/fields/message_id_field.rb +4 -4
- data/lib/mail/fields/mime_version_field.rb +3 -2
- data/lib/mail/fields/optional_field.rb +1 -0
- data/lib/mail/fields/received_field.rb +4 -3
- data/lib/mail/fields/references_field.rb +3 -1
- data/lib/mail/fields/reply_to_field.rb +3 -3
- data/lib/mail/fields/resent_bcc_field.rb +3 -3
- data/lib/mail/fields/resent_cc_field.rb +3 -3
- data/lib/mail/fields/resent_date_field.rb +2 -1
- data/lib/mail/fields/resent_from_field.rb +3 -3
- data/lib/mail/fields/resent_message_id_field.rb +1 -0
- data/lib/mail/fields/resent_sender_field.rb +4 -4
- data/lib/mail/fields/resent_to_field.rb +3 -3
- data/lib/mail/fields/return_path_field.rb +1 -1
- data/lib/mail/fields/sender_field.rb +9 -9
- data/lib/mail/fields/structured_field.rb +1 -0
- data/lib/mail/fields/subject_field.rb +1 -0
- data/lib/mail/fields/to_field.rb +3 -3
- data/lib/mail/fields/unstructured_field.rb +15 -8
- data/lib/mail/fields.rb +1 -0
- data/lib/mail/header.rb +21 -29
- data/lib/mail/indifferent_hash.rb +1 -0
- data/lib/mail/mail.rb +16 -1
- data/lib/mail/matchers/attachment_matchers.rb +29 -0
- data/lib/mail/matchers/has_sent_mail.rb +61 -4
- data/lib/mail/message.rb +175 -72
- data/lib/mail/multibyte/chars.rb +3 -2
- data/lib/mail/multibyte/exceptions.rb +1 -0
- data/lib/mail/multibyte/unicode.rb +22 -15
- data/lib/mail/multibyte/utils.rb +1 -0
- data/lib/mail/multibyte.rb +1 -0
- data/lib/mail/network/delivery_methods/exim.rb +3 -7
- data/lib/mail/network/delivery_methods/file_delivery.rb +2 -1
- data/lib/mail/network/delivery_methods/sendmail.rb +33 -10
- data/lib/mail/network/delivery_methods/smtp.rb +32 -34
- data/lib/mail/network/delivery_methods/smtp_connection.rb +7 -6
- data/lib/mail/network/delivery_methods/test_mailer.rb +3 -2
- data/lib/mail/network/retriever_methods/base.rb +1 -0
- data/lib/mail/network/retriever_methods/imap.rb +19 -13
- data/lib/mail/network/retriever_methods/pop3.rb +1 -0
- data/lib/mail/network/retriever_methods/test_retriever.rb +1 -0
- data/lib/mail/network.rb +1 -0
- data/lib/mail/parsers/address_lists_parser.rb +133 -0
- data/lib/mail/parsers/content_disposition_parser.rb +68 -0
- data/lib/mail/parsers/content_location_parser.rb +36 -0
- data/lib/mail/parsers/content_transfer_encoding_parser.rb +34 -0
- data/lib/mail/parsers/content_type_parser.rb +67 -0
- data/lib/mail/parsers/date_time_parser.rb +39 -0
- data/lib/mail/parsers/envelope_from_parser.rb +46 -0
- data/lib/mail/parsers/message_ids_parser.rb +40 -0
- data/lib/mail/parsers/mime_version_parser.rb +42 -0
- data/lib/mail/parsers/phrase_lists_parser.rb +36 -0
- data/lib/mail/parsers/ragel/common.rl +185 -0
- data/lib/mail/parsers/ragel/date_time.rl +30 -0
- data/lib/mail/parsers/ragel/parser_info.rb +61 -0
- data/lib/mail/parsers/ragel/ruby/machines/address_lists_machine.rb +14864 -0
- data/lib/mail/parsers/ragel/ruby/machines/address_lists_machine.rb.rl +37 -0
- data/lib/mail/parsers/ragel/ruby/machines/content_disposition_machine.rb +751 -0
- data/lib/mail/parsers/ragel/ruby/machines/content_disposition_machine.rb.rl +37 -0
- data/lib/mail/parsers/ragel/ruby/machines/content_location_machine.rb +614 -0
- data/lib/mail/parsers/ragel/ruby/machines/content_location_machine.rb.rl +37 -0
- data/lib/mail/parsers/ragel/ruby/machines/content_transfer_encoding_machine.rb +447 -0
- data/lib/mail/parsers/ragel/ruby/machines/content_transfer_encoding_machine.rb.rl +37 -0
- data/lib/mail/parsers/ragel/ruby/machines/content_type_machine.rb +825 -0
- data/lib/mail/parsers/ragel/ruby/machines/content_type_machine.rb.rl +37 -0
- data/lib/mail/parsers/ragel/ruby/machines/date_time_machine.rb +817 -0
- data/lib/mail/parsers/ragel/ruby/machines/date_time_machine.rb.rl +37 -0
- data/lib/mail/parsers/ragel/ruby/machines/envelope_from_machine.rb +2149 -0
- data/lib/mail/parsers/ragel/ruby/machines/envelope_from_machine.rb.rl +37 -0
- data/lib/mail/parsers/ragel/ruby/machines/message_ids_machine.rb +1570 -0
- data/lib/mail/parsers/ragel/ruby/machines/message_ids_machine.rb.rl +37 -0
- data/lib/mail/parsers/ragel/ruby/machines/mime_version_machine.rb +440 -0
- data/lib/mail/parsers/ragel/ruby/machines/mime_version_machine.rb.rl +37 -0
- data/lib/mail/parsers/ragel/ruby/machines/phrase_lists_machine.rb +564 -0
- data/lib/mail/parsers/ragel/ruby/machines/phrase_lists_machine.rb.rl +37 -0
- data/lib/mail/parsers/ragel/ruby/machines/rb_actions.rl +51 -0
- data/lib/mail/parsers/ragel/ruby/machines/received_machine.rb +5144 -0
- data/lib/mail/parsers/ragel/ruby/machines/received_machine.rb.rl +37 -0
- data/lib/mail/parsers/ragel/ruby/parser.rb.rl.erb +37 -0
- data/lib/mail/parsers/ragel/ruby.rb +40 -0
- data/lib/mail/parsers/ragel.rb +18 -0
- data/lib/mail/parsers/received_parser.rb +49 -0
- data/lib/mail/parsers.rb +27 -0
- data/lib/mail/part.rb +11 -4
- data/lib/mail/parts_list.rb +30 -10
- data/lib/mail/utilities.rb +127 -63
- 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 +18 -7
- data/lib/mail/version_specific/ruby_1_9.rb +136 -32
- data/lib/mail.rb +12 -6
- metadata +115 -77
- data/lib/VERSION +0 -4
- data/lib/load_parsers.rb +0 -41
- data/lib/mail/core_extensions/nil.rb +0 -19
- data/lib/mail/core_extensions/object.rb +0 -13
- data/lib/mail/core_extensions/shell_escape.rb +0 -56
- data/lib/mail/parsers/address_lists.rb +0 -64
- data/lib/mail/parsers/address_lists.treetop +0 -19
- data/lib/mail/parsers/content_disposition.rb +0 -535
- data/lib/mail/parsers/content_disposition.treetop +0 -46
- data/lib/mail/parsers/content_location.rb +0 -139
- data/lib/mail/parsers/content_location.treetop +0 -20
- data/lib/mail/parsers/content_transfer_encoding.rb +0 -162
- data/lib/mail/parsers/content_transfer_encoding.treetop +0 -20
- data/lib/mail/parsers/content_type.rb +0 -967
- data/lib/mail/parsers/content_type.treetop +0 -68
- data/lib/mail/parsers/date_time.rb +0 -114
- data/lib/mail/parsers/date_time.treetop +0 -11
- data/lib/mail/parsers/envelope_from.rb +0 -194
- data/lib/mail/parsers/envelope_from.treetop +0 -32
- data/lib/mail/parsers/message_ids.rb +0 -45
- data/lib/mail/parsers/message_ids.treetop +0 -15
- data/lib/mail/parsers/mime_version.rb +0 -144
- data/lib/mail/parsers/mime_version.treetop +0 -19
- data/lib/mail/parsers/phrase_lists.rb +0 -45
- data/lib/mail/parsers/phrase_lists.treetop +0 -15
- data/lib/mail/parsers/received.rb +0 -71
- data/lib/mail/parsers/received.treetop +0 -11
- data/lib/mail/parsers/rfc2045.rb +0 -464
- data/lib/mail/parsers/rfc2045.treetop +0 -36
- data/lib/mail/parsers/rfc2822.rb +0 -5397
- data/lib/mail/parsers/rfc2822.treetop +0 -410
- data/lib/mail/parsers/rfc2822_obsolete.rb +0 -3768
- data/lib/mail/parsers/rfc2822_obsolete.treetop +0 -241
- data/lib/tasks/corpus.rake +0 -125
- data/lib/tasks/treetop.rake +0 -10
|
@@ -1,30 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
1
2
|
module Mail
|
|
2
|
-
|
|
3
3
|
module CheckDeliveryParams
|
|
4
|
+
def check_delivery_params(mail)
|
|
5
|
+
if Utilities.blank?(mail.smtp_envelope_from)
|
|
6
|
+
raise ArgumentError.new('An SMTP From address is required to send a message. Set the message smtp_envelope_from, return_path, sender, or from address.')
|
|
7
|
+
end
|
|
4
8
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
def check_params(mail)
|
|
9
|
-
envelope_from = mail.return_path || mail.sender || mail.from_addrs.first
|
|
10
|
-
if envelope_from.blank?
|
|
11
|
-
raise ArgumentError.new('A sender (Return-Path, Sender or From) required to send a message')
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
destinations ||= mail.destinations if mail.respond_to?(:destinations) && mail.destinations
|
|
15
|
-
if destinations.blank?
|
|
16
|
-
raise ArgumentError.new('At least one recipient (To, Cc or Bcc) is required to send a message')
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
message ||= mail.encoded if mail.respond_to?(:encoded)
|
|
20
|
-
if message.blank?
|
|
21
|
-
raise ArgumentError.new('A encoded content is required to send a message')
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
[envelope_from, destinations, message]
|
|
25
|
-
end
|
|
9
|
+
if Utilities.blank?(mail.smtp_envelope_to)
|
|
10
|
+
raise ArgumentError.new('An SMTP To address is required to send a message. Set the message smtp_envelope_to, to, cc, or bcc address.')
|
|
11
|
+
end
|
|
26
12
|
|
|
13
|
+
message = mail.encoded if mail.respond_to?(:encoded)
|
|
14
|
+
if Utilities.blank?(message)
|
|
15
|
+
raise ArgumentError.new('An encoded message is required to send an email')
|
|
27
16
|
end
|
|
17
|
+
|
|
18
|
+
[mail.smtp_envelope_from, mail.smtp_envelope_to, message]
|
|
28
19
|
end
|
|
29
20
|
end
|
|
30
21
|
end
|
data/lib/mail/configuration.rb
CHANGED
|
@@ -1,28 +1,32 @@
|
|
|
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
|
+
|
|
18
19
|
CRLF = /\r\n/
|
|
19
20
|
WSP = /[#{white_space}]/
|
|
20
21
|
FWS = /#{CRLF}#{WSP}*/
|
|
21
22
|
TEXT = /[#{text}]/ # + obs-text
|
|
22
23
|
FIELD_NAME = /[#{field_name}]+/
|
|
23
|
-
|
|
24
|
+
FIELD_PREFIX = /\A(#{FIELD_NAME})/
|
|
25
|
+
FIELD_BODY = /.+/m
|
|
24
26
|
FIELD_LINE = /^[#{field_name}]+:\s*.+$/
|
|
27
|
+
FIELD_SPLIT = /^(#{FIELD_NAME})\s*:\s*(#{FIELD_BODY})?$/
|
|
25
28
|
HEADER_LINE = /^([#{field_name}]+:\s*.+)$/
|
|
29
|
+
HEADER_SPLIT = /#{CRLF}(?!#{WSP})/
|
|
26
30
|
|
|
27
31
|
QP_UNSAFE = /[^#{qp_safe}]/
|
|
28
32
|
QP_SAFE = /[#{qp_safe}]/
|
|
@@ -30,5 +34,24 @@ module Mail
|
|
|
30
34
|
ATOM_UNSAFE = /[#{Regexp.quote aspecial}#{control}#{sp}]/n
|
|
31
35
|
PHRASE_UNSAFE = /[#{Regexp.quote aspecial}#{control}]/n
|
|
32
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']
|
|
33
56
|
end
|
|
34
57
|
end
|
|
@@ -1,25 +1,25 @@
|
|
|
1
1
|
# encoding: utf-8
|
|
2
|
+
# frozen_string_literal: true
|
|
2
3
|
module Net
|
|
3
4
|
class SMTP
|
|
4
5
|
# This is a backport of r30294 from ruby trunk because of a bug in net/smtp.
|
|
5
6
|
# http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=30294
|
|
6
7
|
#
|
|
7
8
|
# Fixed in what will be Ruby 1.9.3 - tlsconnect also does not exist in some early versions of ruby
|
|
8
|
-
|
|
9
|
+
begin
|
|
10
|
+
alias_method :original_tlsconnect, :tlsconnect
|
|
9
11
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
12
|
+
def tlsconnect(s)
|
|
13
|
+
verified = false
|
|
14
|
+
begin
|
|
15
|
+
original_tlsconnect(s).tap { verified = true }
|
|
16
|
+
ensure
|
|
17
|
+
unless verified
|
|
18
|
+
s.close rescue nil
|
|
19
|
+
end
|
|
20
|
+
end
|
|
18
21
|
end
|
|
19
|
-
|
|
20
|
-
s
|
|
21
|
-
ensure
|
|
22
|
-
s.close unless verified
|
|
22
|
+
rescue NameError
|
|
23
23
|
end
|
|
24
24
|
end
|
|
25
25
|
end
|
|
@@ -1,26 +1,14 @@
|
|
|
1
1
|
# encoding: utf-8
|
|
2
|
+
# frozen_string_literal: true
|
|
2
3
|
class String #:nodoc:
|
|
3
|
-
def to_crlf
|
|
4
|
-
to_str.gsub(/\n|\r\n|\r/) { "\r\n" }
|
|
5
|
-
end
|
|
6
|
-
|
|
7
|
-
def to_lf
|
|
8
|
-
to_str.gsub(/\n|\r\n|\r/) { "\n" }
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
unless String.instance_methods(false).map {|m| m.to_sym}.include?(:blank?)
|
|
12
|
-
def blank?
|
|
13
|
-
self !~ /\S/
|
|
14
|
-
end
|
|
15
|
-
end
|
|
16
4
|
|
|
17
5
|
unless method_defined?(:ascii_only?)
|
|
18
|
-
#
|
|
19
|
-
# returns true or false
|
|
20
|
-
US_ASCII_REGEXP = %Q{\x00-\x7f}
|
|
6
|
+
# Backport from Ruby 1.9 checks for non-us-ascii characters.
|
|
21
7
|
def ascii_only?
|
|
22
|
-
|
|
8
|
+
self !~ MATCH_NON_US_ASCII
|
|
23
9
|
end
|
|
10
|
+
|
|
11
|
+
MATCH_NON_US_ASCII = /[^\x00-\x7f]/
|
|
24
12
|
end
|
|
25
13
|
|
|
26
14
|
def not_ascii_only?
|
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
# encoding: utf-8
|
|
2
|
+
# frozen_string_literal: true
|
|
2
3
|
module Mail
|
|
3
4
|
class Address
|
|
4
|
-
|
|
5
|
+
|
|
5
6
|
include Mail::Utilities
|
|
6
|
-
|
|
7
|
+
|
|
7
8
|
# Mail::Address handles all email addresses in Mail. It takes an email address string
|
|
8
|
-
# and parses it, breaking it down into
|
|
9
|
+
# and parses it, breaking it down into its component parts and allowing you to get the
|
|
9
10
|
# address, comments, display name, name, local part, domain part and fully formatted
|
|
10
11
|
# address.
|
|
11
|
-
#
|
|
12
|
+
#
|
|
12
13
|
# Mail::Address requires a correctly formatted email address per RFC2822 or RFC822. It
|
|
13
14
|
# handles all obsolete versions including obsolete domain routing on the local part.
|
|
14
|
-
#
|
|
15
|
+
#
|
|
15
16
|
# a = Address.new('Mikel Lindsaar (My email address) <mikel@test.lindsaar.net>')
|
|
16
17
|
# a.format #=> 'Mikel Lindsaar <mikel@test.lindsaar.net> (My email address)'
|
|
17
18
|
# a.address #=> 'mikel@test.lindsaar.net'
|
|
@@ -21,26 +22,23 @@ module Mail
|
|
|
21
22
|
# a.comments #=> ['My email address']
|
|
22
23
|
# a.to_s #=> 'Mikel Lindsaar <mikel@test.lindsaar.net> (My email address)'
|
|
23
24
|
def initialize(value = nil)
|
|
24
|
-
@output_type =
|
|
25
|
-
|
|
26
|
-
@raw_text = value
|
|
27
|
-
case
|
|
28
|
-
when value.nil?
|
|
25
|
+
@output_type = :decode
|
|
26
|
+
if value.nil?
|
|
29
27
|
@parsed = false
|
|
30
|
-
|
|
28
|
+
@data = nil
|
|
31
29
|
else
|
|
32
30
|
parse(value)
|
|
33
31
|
end
|
|
34
32
|
end
|
|
35
|
-
|
|
36
|
-
# Returns the raw
|
|
33
|
+
|
|
34
|
+
# Returns the raw input of the passed in string, this is before it is passed
|
|
37
35
|
# by the parser.
|
|
38
36
|
def raw
|
|
39
|
-
@
|
|
37
|
+
@data.raw
|
|
40
38
|
end
|
|
41
39
|
|
|
42
40
|
# Returns a correctly formatted address for the email going out. If given
|
|
43
|
-
# an incorrectly formatted address as input, Mail::Address will do
|
|
41
|
+
# an incorrectly formatted address as input, Mail::Address will do its best
|
|
44
42
|
# to format it correctly. This includes quoting display names as needed and
|
|
45
43
|
# putting the address in angle brackets etc.
|
|
46
44
|
#
|
|
@@ -48,37 +46,38 @@ module Mail
|
|
|
48
46
|
# a.format #=> 'Mikel Lindsaar <mikel@test.lindsaar.net> (My email address)'
|
|
49
47
|
def format
|
|
50
48
|
parse unless @parsed
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
49
|
+
if @data.nil?
|
|
50
|
+
EMPTY
|
|
51
|
+
elsif display_name
|
|
52
|
+
[quote_phrase(display_name), "<#{address}>", format_comments].compact.join(SPACE)
|
|
53
|
+
elsif address
|
|
54
|
+
[address, format_comments].compact.join(SPACE)
|
|
56
55
|
else
|
|
57
|
-
|
|
56
|
+
raw
|
|
58
57
|
end
|
|
59
58
|
end
|
|
60
59
|
|
|
61
|
-
# 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
|
|
62
61
|
# local@domain string, without any angle brackets or the like.
|
|
63
|
-
#
|
|
62
|
+
#
|
|
64
63
|
# a = Address.new('Mikel Lindsaar (My email address) <mikel@test.lindsaar.net>')
|
|
65
64
|
# a.address #=> 'mikel@test.lindsaar.net'
|
|
66
65
|
def address
|
|
67
66
|
parse unless @parsed
|
|
68
67
|
domain ? "#{local}@#{domain}" : local
|
|
69
68
|
end
|
|
70
|
-
|
|
69
|
+
|
|
71
70
|
# Provides a way to assign an address to an already made Mail::Address object.
|
|
72
|
-
#
|
|
71
|
+
#
|
|
73
72
|
# a = Address.new
|
|
74
73
|
# a.address = 'Mikel Lindsaar (My email address) <mikel@test.lindsaar.net>'
|
|
75
74
|
# a.address #=> 'mikel@test.lindsaar.net'
|
|
76
75
|
def address=(value)
|
|
77
76
|
parse(value)
|
|
78
77
|
end
|
|
79
|
-
|
|
78
|
+
|
|
80
79
|
# Returns the display name of the email address passed in.
|
|
81
|
-
#
|
|
80
|
+
#
|
|
82
81
|
# a = Address.new('Mikel Lindsaar (My email address) <mikel@test.lindsaar.net>')
|
|
83
82
|
# a.display_name #=> 'Mikel Lindsaar'
|
|
84
83
|
def display_name
|
|
@@ -86,70 +85,66 @@ module Mail
|
|
|
86
85
|
@display_name ||= get_display_name
|
|
87
86
|
Encodings.decode_encode(@display_name.to_s, @output_type) if @display_name
|
|
88
87
|
end
|
|
89
|
-
|
|
88
|
+
|
|
90
89
|
# Provides a way to assign a display name to an already made Mail::Address object.
|
|
91
|
-
#
|
|
90
|
+
#
|
|
92
91
|
# a = Address.new
|
|
93
92
|
# a.address = 'mikel@test.lindsaar.net'
|
|
94
93
|
# a.display_name = 'Mikel Lindsaar'
|
|
95
94
|
# a.format #=> 'Mikel Lindsaar <mikel@test.lindsaar.net>'
|
|
96
95
|
def display_name=( str )
|
|
97
|
-
@display_name = str
|
|
96
|
+
@display_name = str.dup # in case frozen
|
|
98
97
|
end
|
|
99
98
|
|
|
100
99
|
# Returns the local part (the left hand side of the @ sign in the email address) of
|
|
101
100
|
# the address
|
|
102
|
-
#
|
|
101
|
+
#
|
|
103
102
|
# a = Address.new('Mikel Lindsaar (My email address) <mikel@test.lindsaar.net>')
|
|
104
103
|
# a.local #=> 'mikel'
|
|
105
104
|
def local
|
|
106
105
|
parse unless @parsed
|
|
107
|
-
"#{obs_domain_list}#{get_local.strip}" if get_local
|
|
106
|
+
Encodings.decode_encode("#{@data.obs_domain_list}#{get_local.strip}", @output_type) if get_local
|
|
108
107
|
end
|
|
109
108
|
|
|
110
109
|
# Returns the domain part (the right hand side of the @ sign in the email address) of
|
|
111
110
|
# the address
|
|
112
|
-
#
|
|
111
|
+
#
|
|
113
112
|
# a = Address.new('Mikel Lindsaar (My email address) <mikel@test.lindsaar.net>')
|
|
114
113
|
# a.domain #=> 'test.lindsaar.net'
|
|
115
114
|
def domain
|
|
116
115
|
parse unless @parsed
|
|
117
|
-
strip_all_comments(get_domain) if get_domain
|
|
116
|
+
Encodings.decode_encode(strip_all_comments(get_domain), @output_type) if get_domain
|
|
118
117
|
end
|
|
119
|
-
|
|
118
|
+
|
|
120
119
|
# Returns an array of comments that are in the email, or an empty array if there
|
|
121
120
|
# are no comments
|
|
122
|
-
#
|
|
121
|
+
#
|
|
123
122
|
# a = Address.new('Mikel Lindsaar (My email address) <mikel@test.lindsaar.net>')
|
|
124
123
|
# a.comments #=> ['My email address']
|
|
125
124
|
def comments
|
|
126
125
|
parse unless @parsed
|
|
127
|
-
|
|
128
|
-
nil
|
|
129
|
-
else
|
|
130
|
-
get_comments.map { |c| c.squeeze(" ") }
|
|
131
|
-
end
|
|
126
|
+
get_comments.map { |c| c.squeeze(SPACE) } unless get_comments.empty?
|
|
132
127
|
end
|
|
133
|
-
|
|
128
|
+
|
|
134
129
|
# Sometimes an address will not have a display name, but might have the name
|
|
135
130
|
# as a comment field after the address. This returns that name if it exists.
|
|
136
|
-
#
|
|
131
|
+
#
|
|
137
132
|
# a = Address.new('mikel@test.lindsaar.net (Mikel Lindsaar)')
|
|
138
133
|
# a.name #=> 'Mikel Lindsaar'
|
|
139
134
|
def name
|
|
140
135
|
parse unless @parsed
|
|
141
136
|
get_name
|
|
142
137
|
end
|
|
143
|
-
|
|
138
|
+
|
|
144
139
|
# Returns the format of the address, or returns nothing
|
|
145
|
-
#
|
|
140
|
+
#
|
|
146
141
|
# a = Address.new('Mikel Lindsaar (My email address) <mikel@test.lindsaar.net>')
|
|
147
142
|
# a.format #=> 'Mikel Lindsaar <mikel@test.lindsaar.net> (My email address)'
|
|
148
143
|
def to_s
|
|
149
144
|
parse unless @parsed
|
|
150
145
|
format
|
|
151
146
|
end
|
|
152
|
-
|
|
147
|
+
|
|
153
148
|
# Shows the Address object basic details, including the Address
|
|
154
149
|
# a = Address.new('Mikel (My email) <mikel@test.lindsaar.net>')
|
|
155
150
|
# a.inspect #=> "#<Mail::Address:14184910 Address: |Mikel <mikel@test.lindsaar.net> (My email)| >"
|
|
@@ -157,150 +152,96 @@ module Mail
|
|
|
157
152
|
parse unless @parsed
|
|
158
153
|
"#<#{self.class}:#{self.object_id} Address: |#{to_s}| >"
|
|
159
154
|
end
|
|
160
|
-
|
|
155
|
+
|
|
161
156
|
def encoded
|
|
162
157
|
@output_type = :encode
|
|
163
158
|
format
|
|
164
159
|
end
|
|
165
|
-
|
|
160
|
+
|
|
166
161
|
def decoded
|
|
167
162
|
@output_type = :decode
|
|
168
163
|
format
|
|
169
164
|
end
|
|
170
165
|
|
|
166
|
+
def group
|
|
167
|
+
@data && @data.group
|
|
168
|
+
end
|
|
169
|
+
|
|
171
170
|
private
|
|
172
|
-
|
|
171
|
+
|
|
173
172
|
def parse(value = nil)
|
|
174
173
|
@parsed = true
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
when
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
def get_domain
|
|
187
|
-
if tree.respond_to?(:angle_addr) && tree.angle_addr.respond_to?(:addr_spec) && tree.angle_addr.addr_spec.respond_to?(:domain)
|
|
188
|
-
@domain_text ||= tree.angle_addr.addr_spec.domain.text_value.strip
|
|
189
|
-
elsif tree.respond_to?(:domain)
|
|
190
|
-
@domain_text ||= tree.domain.text_value.strip
|
|
191
|
-
elsif tree.respond_to?(:addr_spec) && tree.addr_spec.respond_to?(:domain)
|
|
192
|
-
tree.addr_spec.domain.text_value.strip
|
|
193
|
-
else
|
|
194
|
-
nil
|
|
174
|
+
@data = nil
|
|
175
|
+
|
|
176
|
+
case value
|
|
177
|
+
when Mail::Parsers::AddressStruct
|
|
178
|
+
@data = value
|
|
179
|
+
when String
|
|
180
|
+
unless Utilities.blank?(value)
|
|
181
|
+
address_list = Mail::Parsers::AddressListsParser.new.parse(value)
|
|
182
|
+
@data = address_list.addresses.first
|
|
183
|
+
end
|
|
195
184
|
end
|
|
196
185
|
end
|
|
197
186
|
|
|
198
187
|
def strip_all_comments(string)
|
|
199
|
-
unless
|
|
188
|
+
unless Utilities.blank?(comments)
|
|
200
189
|
comments.each do |comment|
|
|
201
|
-
string = string.gsub("(#{comment})",
|
|
190
|
+
string = string.gsub("(#{comment})", EMPTY)
|
|
202
191
|
end
|
|
203
192
|
end
|
|
204
193
|
string.strip
|
|
205
194
|
end
|
|
206
195
|
|
|
207
196
|
def strip_domain_comments(value)
|
|
208
|
-
unless
|
|
197
|
+
unless Utilities.blank?(comments)
|
|
209
198
|
comments.each do |comment|
|
|
210
|
-
if
|
|
211
|
-
value = value.gsub("(#{comment})",
|
|
199
|
+
if @data.domain && @data.domain.include?("(#{comment})")
|
|
200
|
+
value = value.gsub("(#{comment})", EMPTY)
|
|
212
201
|
end
|
|
213
202
|
end
|
|
214
203
|
end
|
|
215
204
|
value.to_s.strip
|
|
216
205
|
end
|
|
217
|
-
|
|
218
|
-
def get_comments
|
|
219
|
-
if tree.respond_to?(:comments)
|
|
220
|
-
@comments = tree.comments.map { |c| unparen(c.text_value.to_str) }
|
|
221
|
-
else
|
|
222
|
-
@comments = []
|
|
223
|
-
end
|
|
224
|
-
end
|
|
225
|
-
|
|
206
|
+
|
|
226
207
|
def get_display_name
|
|
227
|
-
if
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
if domain
|
|
232
|
-
str = strip_domain_comments(format_comments)
|
|
233
|
-
else
|
|
234
|
-
str = nil
|
|
235
|
-
end
|
|
236
|
-
else
|
|
237
|
-
nil
|
|
238
|
-
end
|
|
239
|
-
|
|
240
|
-
if str.blank?
|
|
241
|
-
nil
|
|
242
|
-
else
|
|
243
|
-
str
|
|
208
|
+
if @data.display_name
|
|
209
|
+
str = strip_all_comments(@data.display_name.to_s)
|
|
210
|
+
elsif @data.comments && @data.domain
|
|
211
|
+
str = strip_domain_comments(format_comments)
|
|
244
212
|
end
|
|
213
|
+
str unless Utilities.blank?(str)
|
|
245
214
|
end
|
|
246
|
-
|
|
215
|
+
|
|
247
216
|
def get_name
|
|
248
217
|
if display_name
|
|
249
218
|
str = display_name
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
comment_text = comments.join(' ').squeeze(" ")
|
|
253
|
-
str = "(#{comment_text})"
|
|
254
|
-
end
|
|
219
|
+
elsif comments
|
|
220
|
+
str = "(#{comments.join(SPACE).squeeze(SPACE)})"
|
|
255
221
|
end
|
|
256
222
|
|
|
257
|
-
|
|
258
|
-
nil
|
|
259
|
-
else
|
|
260
|
-
unparen(str)
|
|
261
|
-
end
|
|
262
|
-
end
|
|
263
|
-
|
|
264
|
-
# Provides access to the Treetop parse tree for this address
|
|
265
|
-
def tree
|
|
266
|
-
@tree
|
|
223
|
+
unparen(str) unless Utilities.blank?(str)
|
|
267
224
|
end
|
|
268
|
-
|
|
269
|
-
def tree=(value)
|
|
270
|
-
@tree = value
|
|
271
|
-
end
|
|
272
|
-
|
|
225
|
+
|
|
273
226
|
def format_comments
|
|
274
227
|
if comments
|
|
275
|
-
comment_text = comments.map {|c| escape_paren(c) }.join(
|
|
228
|
+
comment_text = comments.map {|c| escape_paren(c) }.join(SPACE).squeeze(SPACE)
|
|
276
229
|
@format_comments ||= "(#{comment_text})"
|
|
277
230
|
else
|
|
278
231
|
nil
|
|
279
232
|
end
|
|
280
233
|
end
|
|
281
|
-
|
|
282
|
-
def obs_domain_list
|
|
283
|
-
if tree.respond_to?(:angle_addr)
|
|
284
|
-
obs = tree.angle_addr.elements.select { |e| e.respond_to?(:obs_domain_list) }
|
|
285
|
-
!obs.empty? ? obs.first.text_value : nil
|
|
286
|
-
else
|
|
287
|
-
nil
|
|
288
|
-
end
|
|
289
|
-
end
|
|
290
|
-
|
|
234
|
+
|
|
291
235
|
def get_local
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
end
|
|
236
|
+
@data && @data.local
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
def get_domain
|
|
240
|
+
@data && @data.domain
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
def get_comments
|
|
244
|
+
@data && @data.comments
|
|
302
245
|
end
|
|
303
|
-
|
|
304
|
-
|
|
305
246
|
end
|
|
306
|
-
end
|
|
247
|
+
end
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
# encoding: utf-8
|
|
2
|
+
# frozen_string_literal: true
|
|
2
3
|
module Mail
|
|
3
4
|
class AddressList # :nodoc:
|
|
4
|
-
|
|
5
|
+
|
|
5
6
|
# Mail::AddressList is the class that parses To, From and other address fields from
|
|
6
7
|
# emails passed into Mail.
|
|
7
8
|
#
|
|
@@ -18,57 +19,24 @@ module Mail
|
|
|
18
19
|
# a.addresses #=> [#<Mail::Address:14943130 Address: |ada@test.lindsaar.net...
|
|
19
20
|
# a.group_names #=> ["My Group"]
|
|
20
21
|
def initialize(string)
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
return self
|
|
24
|
-
end
|
|
25
|
-
parser = Mail::AddressListsParser.new
|
|
26
|
-
if tree = parser.parse(string)
|
|
27
|
-
@address_nodes = tree.addresses
|
|
28
|
-
else
|
|
29
|
-
raise Mail::Field::ParseError.new(AddressListsParser, string, parser.failure_reason)
|
|
30
|
-
end
|
|
22
|
+
@addresses_grouped_by_group = nil
|
|
23
|
+
@address_list = Parsers::AddressListsParser.new.parse(string)
|
|
31
24
|
end
|
|
32
25
|
|
|
33
26
|
# Returns a list of address objects from the parsed line
|
|
34
27
|
def addresses
|
|
35
|
-
@addresses ||=
|
|
36
|
-
Mail::Address.new(
|
|
28
|
+
@addresses ||= @address_list.addresses.map do |address_data|
|
|
29
|
+
Mail::Address.new(address_data)
|
|
37
30
|
end
|
|
38
31
|
end
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
@individual_recipients ||= @address_nodes - group_recipients
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
# Returns a list of all recipient syntax trees that are part of a group
|
|
46
|
-
def group_recipients # :nodoc:
|
|
47
|
-
@group_recipients ||= @address_nodes.select { |an| an.respond_to?(:group_name) }
|
|
32
|
+
|
|
33
|
+
def addresses_grouped_by_group
|
|
34
|
+
addresses.select(&:group).group_by(&:group)
|
|
48
35
|
end
|
|
49
36
|
|
|
50
37
|
# Returns the names as an array of strings of all groups
|
|
51
38
|
def group_names # :nodoc:
|
|
52
|
-
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
# Returns a list of address syntax trees
|
|
56
|
-
def address_nodes # :nodoc:
|
|
57
|
-
@address_nodes
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
private
|
|
61
|
-
|
|
62
|
-
def get_addresses
|
|
63
|
-
(individual_recipients + group_recipients.map { |g| get_group_addresses(g) }).flatten
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
def get_group_addresses(g)
|
|
67
|
-
if g.group_list.respond_to?(:addresses)
|
|
68
|
-
g.group_list.addresses
|
|
69
|
-
else
|
|
70
|
-
[]
|
|
71
|
-
end
|
|
39
|
+
@address_list.group_names
|
|
72
40
|
end
|
|
73
41
|
end
|
|
74
42
|
end
|