mail-portertech 2.6.2.edge
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 +753 -0
- data/CONTRIBUTING.md +60 -0
- data/Dependencies.txt +2 -0
- data/Gemfile +15 -0
- data/MIT-LICENSE +20 -0
- data/README.md +683 -0
- data/Rakefile +29 -0
- data/TODO.rdoc +9 -0
- data/lib/mail.rb +91 -0
- data/lib/mail/attachments_list.rb +104 -0
- data/lib/mail/body.rb +291 -0
- data/lib/mail/check_delivery_params.rb +20 -0
- data/lib/mail/configuration.rb +75 -0
- data/lib/mail/core_extensions/nil.rb +19 -0
- data/lib/mail/core_extensions/object.rb +13 -0
- data/lib/mail/core_extensions/smtp.rb +24 -0
- data/lib/mail/core_extensions/string.rb +43 -0
- data/lib/mail/core_extensions/string/access.rb +145 -0
- data/lib/mail/core_extensions/string/multibyte.rb +78 -0
- data/lib/mail/elements.rb +14 -0
- data/lib/mail/elements/address.rb +270 -0
- data/lib/mail/elements/address_list.rb +51 -0
- data/lib/mail/elements/content_disposition_element.rb +26 -0
- data/lib/mail/elements/content_location_element.rb +21 -0
- data/lib/mail/elements/content_transfer_encoding_element.rb +17 -0
- data/lib/mail/elements/content_type_element.rb +31 -0
- data/lib/mail/elements/date_time_element.rb +22 -0
- data/lib/mail/elements/envelope_from_element.rb +39 -0
- data/lib/mail/elements/message_ids_element.rb +24 -0
- data/lib/mail/elements/mime_version_element.rb +22 -0
- data/lib/mail/elements/phrase_list.rb +16 -0
- data/lib/mail/elements/received_element.rb +26 -0
- data/lib/mail/encodings.rb +304 -0
- data/lib/mail/encodings/7bit.rb +31 -0
- data/lib/mail/encodings/8bit.rb +31 -0
- data/lib/mail/encodings/base64.rb +33 -0
- data/lib/mail/encodings/binary.rb +31 -0
- data/lib/mail/encodings/quoted_printable.rb +39 -0
- data/lib/mail/encodings/transfer_encoding.rb +58 -0
- data/lib/mail/envelope.rb +30 -0
- data/lib/mail/field.rb +247 -0
- data/lib/mail/field_list.rb +33 -0
- data/lib/mail/fields.rb +35 -0
- data/lib/mail/fields/bcc_field.rb +56 -0
- data/lib/mail/fields/cc_field.rb +55 -0
- data/lib/mail/fields/comments_field.rb +41 -0
- data/lib/mail/fields/common/address_container.rb +16 -0
- data/lib/mail/fields/common/common_address.rb +135 -0
- data/lib/mail/fields/common/common_date.rb +35 -0
- data/lib/mail/fields/common/common_field.rb +57 -0
- data/lib/mail/fields/common/common_message_id.rb +48 -0
- data/lib/mail/fields/common/parameter_hash.rb +58 -0
- data/lib/mail/fields/content_description_field.rb +19 -0
- data/lib/mail/fields/content_disposition_field.rb +70 -0
- data/lib/mail/fields/content_id_field.rb +62 -0
- data/lib/mail/fields/content_location_field.rb +42 -0
- data/lib/mail/fields/content_transfer_encoding_field.rb +44 -0
- data/lib/mail/fields/content_type_field.rb +201 -0
- data/lib/mail/fields/date_field.rb +57 -0
- data/lib/mail/fields/from_field.rb +55 -0
- data/lib/mail/fields/in_reply_to_field.rb +56 -0
- data/lib/mail/fields/keywords_field.rb +44 -0
- data/lib/mail/fields/message_id_field.rb +82 -0
- data/lib/mail/fields/mime_version_field.rb +53 -0
- data/lib/mail/fields/optional_field.rb +13 -0
- data/lib/mail/fields/received_field.rb +75 -0
- data/lib/mail/fields/references_field.rb +56 -0
- data/lib/mail/fields/reply_to_field.rb +55 -0
- data/lib/mail/fields/resent_bcc_field.rb +55 -0
- data/lib/mail/fields/resent_cc_field.rb +55 -0
- data/lib/mail/fields/resent_date_field.rb +35 -0
- data/lib/mail/fields/resent_from_field.rb +55 -0
- data/lib/mail/fields/resent_message_id_field.rb +34 -0
- data/lib/mail/fields/resent_sender_field.rb +62 -0
- data/lib/mail/fields/resent_to_field.rb +55 -0
- data/lib/mail/fields/return_path_field.rb +65 -0
- data/lib/mail/fields/sender_field.rb +67 -0
- data/lib/mail/fields/structured_field.rb +51 -0
- data/lib/mail/fields/subject_field.rb +16 -0
- data/lib/mail/fields/to_field.rb +55 -0
- data/lib/mail/fields/unstructured_field.rb +204 -0
- data/lib/mail/header.rb +274 -0
- data/lib/mail/indifferent_hash.rb +146 -0
- data/lib/mail/mail.rb +267 -0
- data/lib/mail/matchers/has_sent_mail.rb +157 -0
- data/lib/mail/message.rb +2160 -0
- data/lib/mail/multibyte.rb +42 -0
- data/lib/mail/multibyte/chars.rb +474 -0
- data/lib/mail/multibyte/exceptions.rb +8 -0
- data/lib/mail/multibyte/unicode.rb +400 -0
- data/lib/mail/multibyte/utils.rb +60 -0
- data/lib/mail/network.rb +14 -0
- data/lib/mail/network/delivery_methods/exim.rb +52 -0
- data/lib/mail/network/delivery_methods/file_delivery.rb +45 -0
- data/lib/mail/network/delivery_methods/sendmail.rb +89 -0
- data/lib/mail/network/delivery_methods/smtp.rb +142 -0
- data/lib/mail/network/delivery_methods/smtp_connection.rb +61 -0
- data/lib/mail/network/delivery_methods/test_mailer.rb +44 -0
- data/lib/mail/network/retriever_methods/base.rb +63 -0
- data/lib/mail/network/retriever_methods/imap.rb +173 -0
- data/lib/mail/network/retriever_methods/pop3.rb +140 -0
- data/lib/mail/network/retriever_methods/test_retriever.rb +43 -0
- data/lib/mail/parsers.rb +26 -0
- data/lib/mail/parsers/address_lists_parser.rb +132 -0
- data/lib/mail/parsers/content_disposition_parser.rb +67 -0
- data/lib/mail/parsers/content_location_parser.rb +35 -0
- data/lib/mail/parsers/content_transfer_encoding_parser.rb +33 -0
- data/lib/mail/parsers/content_type_parser.rb +64 -0
- data/lib/mail/parsers/date_time_parser.rb +36 -0
- data/lib/mail/parsers/envelope_from_parser.rb +45 -0
- data/lib/mail/parsers/message_ids_parser.rb +39 -0
- data/lib/mail/parsers/mime_version_parser.rb +41 -0
- data/lib/mail/parsers/phrase_lists_parser.rb +33 -0
- data/lib/mail/parsers/ragel.rb +17 -0
- data/lib/mail/parsers/ragel/common.rl +184 -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.rb +39 -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 +2129 -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/received_parser.rb +47 -0
- data/lib/mail/part.rb +120 -0
- data/lib/mail/parts_list.rb +57 -0
- data/lib/mail/patterns.rb +37 -0
- data/lib/mail/utilities.rb +225 -0
- data/lib/mail/values/unicode_tables.dat +0 -0
- data/lib/mail/version.rb +4 -0
- data/lib/mail/version_specific/ruby_1_8.rb +119 -0
- data/lib/mail/version_specific/ruby_1_9.rb +159 -0
- metadata +276 -0
@@ -0,0 +1,20 @@
|
|
1
|
+
module Mail
|
2
|
+
module CheckDeliveryParams
|
3
|
+
def check_delivery_params(mail)
|
4
|
+
if mail.smtp_envelope_from.blank?
|
5
|
+
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.')
|
6
|
+
end
|
7
|
+
|
8
|
+
if mail.smtp_envelope_to.blank?
|
9
|
+
raise ArgumentError.new('An SMTP To address is required to send a message. Set the message smtp_envelope_to, to, cc, or bcc address.')
|
10
|
+
end
|
11
|
+
|
12
|
+
message = mail.encoded if mail.respond_to?(:encoded)
|
13
|
+
if message.blank?
|
14
|
+
raise ArgumentError.new('An encoded message is required to send an email')
|
15
|
+
end
|
16
|
+
|
17
|
+
[mail.smtp_envelope_from, mail.smtp_envelope_to, message]
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
#
|
3
|
+
# Thanks to Nicolas Fouché for this wrapper
|
4
|
+
#
|
5
|
+
require 'singleton'
|
6
|
+
|
7
|
+
module Mail
|
8
|
+
|
9
|
+
# The Configuration class is a Singleton used to hold the default
|
10
|
+
# configuration for all Mail objects.
|
11
|
+
#
|
12
|
+
# Each new mail object gets a copy of these values at initialization
|
13
|
+
# which can be overwritten on a per mail object basis.
|
14
|
+
class Configuration
|
15
|
+
include Singleton
|
16
|
+
|
17
|
+
def initialize
|
18
|
+
@delivery_method = nil
|
19
|
+
@retriever_method = nil
|
20
|
+
super
|
21
|
+
end
|
22
|
+
|
23
|
+
def delivery_method(method = nil, settings = {})
|
24
|
+
return @delivery_method if @delivery_method && method.nil?
|
25
|
+
@delivery_method = lookup_delivery_method(method).new(settings)
|
26
|
+
end
|
27
|
+
|
28
|
+
def lookup_delivery_method(method)
|
29
|
+
case method.is_a?(String) ? method.to_sym : method
|
30
|
+
when nil
|
31
|
+
Mail::SMTP
|
32
|
+
when :smtp
|
33
|
+
Mail::SMTP
|
34
|
+
when :sendmail
|
35
|
+
Mail::Sendmail
|
36
|
+
when :exim
|
37
|
+
Mail::Exim
|
38
|
+
when :file
|
39
|
+
Mail::FileDelivery
|
40
|
+
when :smtp_connection
|
41
|
+
Mail::SMTPConnection
|
42
|
+
when :test
|
43
|
+
Mail::TestMailer
|
44
|
+
else
|
45
|
+
method
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def retriever_method(method = nil, settings = {})
|
50
|
+
return @retriever_method if @retriever_method && method.nil?
|
51
|
+
@retriever_method = lookup_retriever_method(method).new(settings)
|
52
|
+
end
|
53
|
+
|
54
|
+
def lookup_retriever_method(method)
|
55
|
+
case method
|
56
|
+
when nil
|
57
|
+
Mail::POP3
|
58
|
+
when :pop3
|
59
|
+
Mail::POP3
|
60
|
+
when :imap
|
61
|
+
Mail::IMAP
|
62
|
+
when :test
|
63
|
+
Mail::TestRetriever
|
64
|
+
else
|
65
|
+
method
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def param_encode_language(value = nil)
|
70
|
+
value ? @encode_language = value : @encode_language ||= 'en'
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Net
|
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
|
10
|
+
|
11
|
+
def tlsconnect(s)
|
12
|
+
verified = false
|
13
|
+
begin
|
14
|
+
original_tlsconnect(s).tap { verified = true }
|
15
|
+
ensure
|
16
|
+
unless verified
|
17
|
+
s.close rescue nil
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
rescue NameError
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
class String #:nodoc:
|
3
|
+
|
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
|
+
unless method_defined?(:ascii_only?)
|
28
|
+
# Backport from Ruby 1.9 checks for non-us-ascii characters.
|
29
|
+
def ascii_only?
|
30
|
+
self !~ MATCH_NON_US_ASCII
|
31
|
+
end
|
32
|
+
|
33
|
+
MATCH_NON_US_ASCII = /[^\x00-\x7f]/
|
34
|
+
end
|
35
|
+
|
36
|
+
def not_ascii_only?
|
37
|
+
!ascii_only?
|
38
|
+
end
|
39
|
+
|
40
|
+
unless method_defined?(:bytesize)
|
41
|
+
alias :bytesize :length
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,145 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
# This is not loaded if ActiveSupport is already loaded
|
4
|
+
|
5
|
+
# This is an almost cut and paste from ActiveSupport v3.0.6, copied in here so that Mail
|
6
|
+
# itself does not depend on ActiveSupport to avoid versioning conflicts
|
7
|
+
|
8
|
+
class String
|
9
|
+
unless '1.9'.respond_to?(:force_encoding)
|
10
|
+
# Returns the character at the +position+ treating the string as an array (where 0 is the first character).
|
11
|
+
#
|
12
|
+
# Examples:
|
13
|
+
# "hello".at(0) # => "h"
|
14
|
+
# "hello".at(4) # => "o"
|
15
|
+
# "hello".at(10) # => ERROR if < 1.9, nil in 1.9
|
16
|
+
def at(position)
|
17
|
+
mb_chars[position, 1].to_s
|
18
|
+
end
|
19
|
+
|
20
|
+
# Returns the remaining of the string from the +position+ treating the string as an array (where 0 is the first character).
|
21
|
+
#
|
22
|
+
# Examples:
|
23
|
+
# "hello".from(0) # => "hello"
|
24
|
+
# "hello".from(2) # => "llo"
|
25
|
+
# "hello".from(10) # => "" if < 1.9, nil in 1.9
|
26
|
+
def from(position)
|
27
|
+
mb_chars[position..-1].to_s
|
28
|
+
end
|
29
|
+
|
30
|
+
# Returns the beginning of the string up to the +position+ treating the string as an array (where 0 is the first character).
|
31
|
+
#
|
32
|
+
# Examples:
|
33
|
+
# "hello".to(0) # => "h"
|
34
|
+
# "hello".to(2) # => "hel"
|
35
|
+
# "hello".to(10) # => "hello"
|
36
|
+
def to(position)
|
37
|
+
mb_chars[0..position].to_s
|
38
|
+
end
|
39
|
+
|
40
|
+
# Returns the first character of the string or the first +limit+ characters.
|
41
|
+
#
|
42
|
+
# Examples:
|
43
|
+
# "hello".first # => "h"
|
44
|
+
# "hello".first(2) # => "he"
|
45
|
+
# "hello".first(10) # => "hello"
|
46
|
+
def first(limit = 1)
|
47
|
+
if limit == 0
|
48
|
+
''
|
49
|
+
elsif limit >= size
|
50
|
+
self
|
51
|
+
else
|
52
|
+
mb_chars[0...limit].to_s
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# Returns the last character of the string or the last +limit+ characters.
|
57
|
+
#
|
58
|
+
# Examples:
|
59
|
+
# "hello".last # => "o"
|
60
|
+
# "hello".last(2) # => "lo"
|
61
|
+
# "hello".last(10) # => "hello"
|
62
|
+
def last(limit = 1)
|
63
|
+
if limit == 0
|
64
|
+
''
|
65
|
+
elsif limit >= size
|
66
|
+
self
|
67
|
+
else
|
68
|
+
mb_chars[(-limit)..-1].to_s
|
69
|
+
end
|
70
|
+
end
|
71
|
+
else
|
72
|
+
def at(position)
|
73
|
+
self[position]
|
74
|
+
end
|
75
|
+
|
76
|
+
def from(position)
|
77
|
+
self[position..-1]
|
78
|
+
end
|
79
|
+
|
80
|
+
def to(position)
|
81
|
+
self[0..position]
|
82
|
+
end
|
83
|
+
|
84
|
+
def first(limit = 1)
|
85
|
+
if limit == 0
|
86
|
+
''
|
87
|
+
elsif limit >= size
|
88
|
+
self
|
89
|
+
else
|
90
|
+
to(limit - 1)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def last(limit = 1)
|
95
|
+
if limit == 0
|
96
|
+
''
|
97
|
+
elsif limit >= size
|
98
|
+
self
|
99
|
+
else
|
100
|
+
from(-limit)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
if Module.method(:const_get).arity == 1
|
106
|
+
# Tries to find a constant with the name specified in the argument string:
|
107
|
+
#
|
108
|
+
# "Module".constantize # => Module
|
109
|
+
# "Test::Unit".constantize # => Test::Unit
|
110
|
+
#
|
111
|
+
# The name is assumed to be the one of a top-level constant, no matter whether
|
112
|
+
# it starts with "::" or not. No lexical context is taken into account:
|
113
|
+
#
|
114
|
+
# C = 'outside'
|
115
|
+
# module M
|
116
|
+
# C = 'inside'
|
117
|
+
# C # => 'inside'
|
118
|
+
# "C".constantize # => 'outside', same as ::C
|
119
|
+
# end
|
120
|
+
#
|
121
|
+
# NameError is raised when the name is not in CamelCase or the constant is
|
122
|
+
# unknown.
|
123
|
+
def constantize
|
124
|
+
names = self.split('::')
|
125
|
+
names.shift if names.empty? || names.first.empty?
|
126
|
+
|
127
|
+
constant = Object
|
128
|
+
names.each do |name|
|
129
|
+
constant = constant.const_defined?(name) ? constant.const_get(name) : constant.const_missing(name)
|
130
|
+
end
|
131
|
+
constant
|
132
|
+
end
|
133
|
+
else
|
134
|
+
def constantize #:nodoc:
|
135
|
+
names = self.split('::')
|
136
|
+
names.shift if names.empty? || names.first.empty?
|
137
|
+
|
138
|
+
constant = Object
|
139
|
+
names.each do |name|
|
140
|
+
constant = constant.const_defined?(name, false) ? constant.const_get(name) : constant.const_missing(name)
|
141
|
+
end
|
142
|
+
constant
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
# This is not loaded if ActiveSupport is already loaded
|
4
|
+
|
5
|
+
# This is an almost cut and paste from ActiveSupport v3.0.6, copied in here so that Mail
|
6
|
+
# itself does not depend on ActiveSupport to avoid versioning conflicts
|
7
|
+
|
8
|
+
require 'mail/multibyte'
|
9
|
+
|
10
|
+
class String
|
11
|
+
if RUBY_VERSION >= "1.9"
|
12
|
+
# == Multibyte proxy
|
13
|
+
#
|
14
|
+
# +mb_chars+ is a multibyte safe proxy for string methods.
|
15
|
+
#
|
16
|
+
# In Ruby 1.8 and older it creates and returns an instance of the Mail::Multibyte::Chars class which
|
17
|
+
# encapsulates the original string. A Unicode safe version of all the String methods are defined on this proxy
|
18
|
+
# class. If the proxy class doesn't respond to a certain method, it's forwarded to the encapsuled string.
|
19
|
+
#
|
20
|
+
# name = 'Claus Müller'
|
21
|
+
# name.reverse # => "rell??M sualC"
|
22
|
+
# name.length # => 13
|
23
|
+
#
|
24
|
+
# name.mb_chars.reverse.to_s # => "rellüM sualC"
|
25
|
+
# name.mb_chars.length # => 12
|
26
|
+
#
|
27
|
+
# In Ruby 1.9 and newer +mb_chars+ returns +self+ because String is (mostly) encoding aware. This means that
|
28
|
+
# it becomes easy to run one version of your code on multiple Ruby versions.
|
29
|
+
#
|
30
|
+
# == Method chaining
|
31
|
+
#
|
32
|
+
# All the methods on the Chars proxy which normally return a string will return a Chars object. This allows
|
33
|
+
# method chaining on the result of any of these methods.
|
34
|
+
#
|
35
|
+
# name.mb_chars.reverse.length # => 12
|
36
|
+
#
|
37
|
+
# == Interoperability and configuration
|
38
|
+
#
|
39
|
+
# The Chars object tries to be as interchangeable with String objects as possible: sorting and comparing between
|
40
|
+
# String and Char work like expected. The bang! methods change the internal string representation in the Chars
|
41
|
+
# object. Interoperability problems can be resolved easily with a +to_s+ call.
|
42
|
+
#
|
43
|
+
# For more information about the methods defined on the Chars proxy see Mail::Multibyte::Chars. For
|
44
|
+
# information about how to change the default Multibyte behaviour see Mail::Multibyte.
|
45
|
+
def mb_chars
|
46
|
+
if Mail::Multibyte.proxy_class.consumes?(self)
|
47
|
+
Mail::Multibyte.proxy_class.new(self)
|
48
|
+
else
|
49
|
+
self
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def is_utf8? #:nodoc
|
54
|
+
case encoding
|
55
|
+
when Encoding::UTF_8
|
56
|
+
valid_encoding?
|
57
|
+
when Encoding::ASCII_8BIT, Encoding::US_ASCII
|
58
|
+
dup.force_encoding(Encoding::UTF_8).valid_encoding?
|
59
|
+
else
|
60
|
+
false
|
61
|
+
end
|
62
|
+
end
|
63
|
+
else
|
64
|
+
def mb_chars
|
65
|
+
if Mail::Multibyte.proxy_class.wants?(self)
|
66
|
+
Mail::Multibyte.proxy_class.new(self)
|
67
|
+
else
|
68
|
+
self
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
# Returns true if the string has UTF-8 semantics (a String used for purely byte resources is unlikely to have
|
73
|
+
# them), returns false otherwise.
|
74
|
+
def is_utf8?
|
75
|
+
Mail::Multibyte::Chars.consumes?(self)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Mail
|
2
|
+
register_autoload :Address, 'mail/elements/address'
|
3
|
+
register_autoload :AddressList, 'mail/elements/address_list'
|
4
|
+
register_autoload :ContentDispositionElement, 'mail/elements/content_disposition_element'
|
5
|
+
register_autoload :ContentLocationElement, 'mail/elements/content_location_element'
|
6
|
+
register_autoload :ContentTransferEncodingElement, 'mail/elements/content_transfer_encoding_element'
|
7
|
+
register_autoload :ContentTypeElement, 'mail/elements/content_type_element'
|
8
|
+
register_autoload :DateTimeElement, 'mail/elements/date_time_element'
|
9
|
+
register_autoload :EnvelopeFromElement, 'mail/elements/envelope_from_element'
|
10
|
+
register_autoload :MessageIdsElement, 'mail/elements/message_ids_element'
|
11
|
+
register_autoload :MimeVersionElement, 'mail/elements/mime_version_element'
|
12
|
+
register_autoload :PhraseList, 'mail/elements/phrase_list'
|
13
|
+
register_autoload :ReceivedElement, 'mail/elements/received_element'
|
14
|
+
end
|
@@ -0,0 +1,270 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Mail
|
3
|
+
class Address
|
4
|
+
|
5
|
+
include Mail::Utilities
|
6
|
+
|
7
|
+
# Mail::Address handles all email addresses in Mail. It takes an email address string
|
8
|
+
# and parses it, breaking it down into its component parts and allowing you to get the
|
9
|
+
# address, comments, display name, name, local part, domain part and fully formatted
|
10
|
+
# address.
|
11
|
+
#
|
12
|
+
# Mail::Address requires a correctly formatted email address per RFC2822 or RFC822. It
|
13
|
+
# handles all obsolete versions including obsolete domain routing on the local part.
|
14
|
+
#
|
15
|
+
# a = Address.new('Mikel Lindsaar (My email address) <mikel@test.lindsaar.net>')
|
16
|
+
# a.format #=> 'Mikel Lindsaar <mikel@test.lindsaar.net> (My email address)'
|
17
|
+
# a.address #=> 'mikel@test.lindsaar.net'
|
18
|
+
# a.display_name #=> 'Mikel Lindsaar'
|
19
|
+
# a.local #=> 'mikel'
|
20
|
+
# a.domain #=> 'test.lindsaar.net'
|
21
|
+
# a.comments #=> ['My email address']
|
22
|
+
# a.to_s #=> 'Mikel Lindsaar <mikel@test.lindsaar.net> (My email address)'
|
23
|
+
def initialize(value = nil)
|
24
|
+
@output_type = :decode
|
25
|
+
if value.nil?
|
26
|
+
@parsed = false
|
27
|
+
@data = nil
|
28
|
+
return
|
29
|
+
else
|
30
|
+
parse(value)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# Returns the raw input of the passed in string, this is before it is passed
|
35
|
+
# by the parser.
|
36
|
+
def raw
|
37
|
+
@data.raw
|
38
|
+
end
|
39
|
+
|
40
|
+
# Returns a correctly formatted address for the email going out. If given
|
41
|
+
# an incorrectly formatted address as input, Mail::Address will do its best
|
42
|
+
# to format it correctly. This includes quoting display names as needed and
|
43
|
+
# putting the address in angle brackets etc.
|
44
|
+
#
|
45
|
+
# a = Address.new('Mikel Lindsaar (My email address) <mikel@test.lindsaar.net>')
|
46
|
+
# a.format #=> 'Mikel Lindsaar <mikel@test.lindsaar.net> (My email address)'
|
47
|
+
def format
|
48
|
+
parse unless @parsed
|
49
|
+
if @data.nil?
|
50
|
+
''
|
51
|
+
elsif display_name
|
52
|
+
[quote_phrase(display_name), "<#{address}>", format_comments].compact.join(" ")
|
53
|
+
elsif address
|
54
|
+
[address, format_comments].compact.join(" ")
|
55
|
+
else
|
56
|
+
raw
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# Returns the address that is in the address itself. That is, the
|
61
|
+
# local@domain string, without any angle brackets or the like.
|
62
|
+
#
|
63
|
+
# a = Address.new('Mikel Lindsaar (My email address) <mikel@test.lindsaar.net>')
|
64
|
+
# a.address #=> 'mikel@test.lindsaar.net'
|
65
|
+
def address
|
66
|
+
parse unless @parsed
|
67
|
+
domain ? "#{local}@#{domain}" : local
|
68
|
+
end
|
69
|
+
|
70
|
+
# Provides a way to assign an address to an already made Mail::Address object.
|
71
|
+
#
|
72
|
+
# a = Address.new
|
73
|
+
# a.address = 'Mikel Lindsaar (My email address) <mikel@test.lindsaar.net>'
|
74
|
+
# a.address #=> 'mikel@test.lindsaar.net'
|
75
|
+
def address=(value)
|
76
|
+
parse(value)
|
77
|
+
end
|
78
|
+
|
79
|
+
# Returns the display name of the email address passed in.
|
80
|
+
#
|
81
|
+
# a = Address.new('Mikel Lindsaar (My email address) <mikel@test.lindsaar.net>')
|
82
|
+
# a.display_name #=> 'Mikel Lindsaar'
|
83
|
+
def display_name
|
84
|
+
parse unless @parsed
|
85
|
+
@display_name ||= get_display_name
|
86
|
+
Encodings.decode_encode(@display_name.to_s, @output_type) if @display_name
|
87
|
+
end
|
88
|
+
|
89
|
+
# Provides a way to assign a display name to an already made Mail::Address object.
|
90
|
+
#
|
91
|
+
# a = Address.new
|
92
|
+
# a.address = 'mikel@test.lindsaar.net'
|
93
|
+
# a.display_name = 'Mikel Lindsaar'
|
94
|
+
# a.format #=> 'Mikel Lindsaar <mikel@test.lindsaar.net>'
|
95
|
+
def display_name=( str )
|
96
|
+
@display_name = str
|
97
|
+
end
|
98
|
+
|
99
|
+
# Returns the local part (the left hand side of the @ sign in the email address) of
|
100
|
+
# the address
|
101
|
+
#
|
102
|
+
# a = Address.new('Mikel Lindsaar (My email address) <mikel@test.lindsaar.net>')
|
103
|
+
# a.local #=> 'mikel'
|
104
|
+
def local
|
105
|
+
parse unless @parsed
|
106
|
+
"#{@data.obs_domain_list}#{get_local.strip}" if get_local
|
107
|
+
end
|
108
|
+
|
109
|
+
# Returns the domain part (the right hand side of the @ sign in the email address) of
|
110
|
+
# the address
|
111
|
+
#
|
112
|
+
# a = Address.new('Mikel Lindsaar (My email address) <mikel@test.lindsaar.net>')
|
113
|
+
# a.domain #=> 'test.lindsaar.net'
|
114
|
+
def domain
|
115
|
+
parse unless @parsed
|
116
|
+
strip_all_comments(get_domain) if get_domain
|
117
|
+
end
|
118
|
+
|
119
|
+
# Returns an array of comments that are in the email, or an empty array if there
|
120
|
+
# are no comments
|
121
|
+
#
|
122
|
+
# a = Address.new('Mikel Lindsaar (My email address) <mikel@test.lindsaar.net>')
|
123
|
+
# a.comments #=> ['My email address']
|
124
|
+
def comments
|
125
|
+
parse unless @parsed
|
126
|
+
if get_comments.empty?
|
127
|
+
nil
|
128
|
+
else
|
129
|
+
get_comments.map { |c| c.squeeze(" ") }
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
# Sometimes an address will not have a display name, but might have the name
|
134
|
+
# as a comment field after the address. This returns that name if it exists.
|
135
|
+
#
|
136
|
+
# a = Address.new('mikel@test.lindsaar.net (Mikel Lindsaar)')
|
137
|
+
# a.name #=> 'Mikel Lindsaar'
|
138
|
+
def name
|
139
|
+
parse unless @parsed
|
140
|
+
get_name
|
141
|
+
end
|
142
|
+
|
143
|
+
# Returns the format of the address, or returns nothing
|
144
|
+
#
|
145
|
+
# a = Address.new('Mikel Lindsaar (My email address) <mikel@test.lindsaar.net>')
|
146
|
+
# a.format #=> 'Mikel Lindsaar <mikel@test.lindsaar.net> (My email address)'
|
147
|
+
def to_s
|
148
|
+
parse unless @parsed
|
149
|
+
format
|
150
|
+
end
|
151
|
+
|
152
|
+
# Shows the Address object basic details, including the Address
|
153
|
+
# a = Address.new('Mikel (My email) <mikel@test.lindsaar.net>')
|
154
|
+
# a.inspect #=> "#<Mail::Address:14184910 Address: |Mikel <mikel@test.lindsaar.net> (My email)| >"
|
155
|
+
def inspect
|
156
|
+
parse unless @parsed
|
157
|
+
"#<#{self.class}:#{self.object_id} Address: |#{to_s}| >"
|
158
|
+
end
|
159
|
+
|
160
|
+
def encoded
|
161
|
+
@output_type = :encode
|
162
|
+
format
|
163
|
+
end
|
164
|
+
|
165
|
+
def decoded
|
166
|
+
@output_type = :decode
|
167
|
+
format
|
168
|
+
end
|
169
|
+
|
170
|
+
private
|
171
|
+
|
172
|
+
def parse(value = nil)
|
173
|
+
@parsed = true
|
174
|
+
|
175
|
+
case value
|
176
|
+
when NilClass
|
177
|
+
@data = nil
|
178
|
+
nil
|
179
|
+
when Mail::Parsers::AddressStruct
|
180
|
+
@data = value
|
181
|
+
when String
|
182
|
+
@raw_text = value
|
183
|
+
if value.blank?
|
184
|
+
@data = nil
|
185
|
+
else
|
186
|
+
address_list = Mail::Parsers::AddressListsParser.new.parse(value)
|
187
|
+
@data = address_list.addresses.first
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
def strip_all_comments(string)
|
193
|
+
unless comments.blank?
|
194
|
+
comments.each do |comment|
|
195
|
+
string = string.gsub("(#{comment})", '')
|
196
|
+
end
|
197
|
+
end
|
198
|
+
string.strip
|
199
|
+
end
|
200
|
+
|
201
|
+
def strip_domain_comments(value)
|
202
|
+
unless comments.blank?
|
203
|
+
comments.each do |comment|
|
204
|
+
if @data.domain && @data.domain.include?("(#{comment})")
|
205
|
+
value = value.gsub("(#{comment})", '')
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
209
|
+
value.to_s.strip
|
210
|
+
end
|
211
|
+
|
212
|
+
def get_display_name
|
213
|
+
if @data.display_name
|
214
|
+
str = strip_all_comments(@data.display_name.to_s)
|
215
|
+
elsif @data.comments
|
216
|
+
if @data.domain
|
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
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
def get_name
|
233
|
+
if display_name
|
234
|
+
str = display_name
|
235
|
+
else
|
236
|
+
if comments
|
237
|
+
comment_text = comments.join(' ').squeeze(" ")
|
238
|
+
str = "(#{comment_text})"
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
if str.blank?
|
243
|
+
nil
|
244
|
+
else
|
245
|
+
unparen(str)
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
249
|
+
def format_comments
|
250
|
+
if comments
|
251
|
+
comment_text = comments.map {|c| escape_paren(c) }.join(' ').squeeze(" ")
|
252
|
+
@format_comments ||= "(#{comment_text})"
|
253
|
+
else
|
254
|
+
nil
|
255
|
+
end
|
256
|
+
end
|
257
|
+
|
258
|
+
def get_local
|
259
|
+
@data && @data.local
|
260
|
+
end
|
261
|
+
|
262
|
+
def get_domain
|
263
|
+
@data && @data.domain
|
264
|
+
end
|
265
|
+
|
266
|
+
def get_comments
|
267
|
+
@data && @data.comments
|
268
|
+
end
|
269
|
+
end
|
270
|
+
end
|