mail-portertech 2.6.2.edge

Sign up to get free protection for your applications and to get access to all the features.
Files changed (153) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.rdoc +753 -0
  3. data/CONTRIBUTING.md +60 -0
  4. data/Dependencies.txt +2 -0
  5. data/Gemfile +15 -0
  6. data/MIT-LICENSE +20 -0
  7. data/README.md +683 -0
  8. data/Rakefile +29 -0
  9. data/TODO.rdoc +9 -0
  10. data/lib/mail.rb +91 -0
  11. data/lib/mail/attachments_list.rb +104 -0
  12. data/lib/mail/body.rb +291 -0
  13. data/lib/mail/check_delivery_params.rb +20 -0
  14. data/lib/mail/configuration.rb +75 -0
  15. data/lib/mail/core_extensions/nil.rb +19 -0
  16. data/lib/mail/core_extensions/object.rb +13 -0
  17. data/lib/mail/core_extensions/smtp.rb +24 -0
  18. data/lib/mail/core_extensions/string.rb +43 -0
  19. data/lib/mail/core_extensions/string/access.rb +145 -0
  20. data/lib/mail/core_extensions/string/multibyte.rb +78 -0
  21. data/lib/mail/elements.rb +14 -0
  22. data/lib/mail/elements/address.rb +270 -0
  23. data/lib/mail/elements/address_list.rb +51 -0
  24. data/lib/mail/elements/content_disposition_element.rb +26 -0
  25. data/lib/mail/elements/content_location_element.rb +21 -0
  26. data/lib/mail/elements/content_transfer_encoding_element.rb +17 -0
  27. data/lib/mail/elements/content_type_element.rb +31 -0
  28. data/lib/mail/elements/date_time_element.rb +22 -0
  29. data/lib/mail/elements/envelope_from_element.rb +39 -0
  30. data/lib/mail/elements/message_ids_element.rb +24 -0
  31. data/lib/mail/elements/mime_version_element.rb +22 -0
  32. data/lib/mail/elements/phrase_list.rb +16 -0
  33. data/lib/mail/elements/received_element.rb +26 -0
  34. data/lib/mail/encodings.rb +304 -0
  35. data/lib/mail/encodings/7bit.rb +31 -0
  36. data/lib/mail/encodings/8bit.rb +31 -0
  37. data/lib/mail/encodings/base64.rb +33 -0
  38. data/lib/mail/encodings/binary.rb +31 -0
  39. data/lib/mail/encodings/quoted_printable.rb +39 -0
  40. data/lib/mail/encodings/transfer_encoding.rb +58 -0
  41. data/lib/mail/envelope.rb +30 -0
  42. data/lib/mail/field.rb +247 -0
  43. data/lib/mail/field_list.rb +33 -0
  44. data/lib/mail/fields.rb +35 -0
  45. data/lib/mail/fields/bcc_field.rb +56 -0
  46. data/lib/mail/fields/cc_field.rb +55 -0
  47. data/lib/mail/fields/comments_field.rb +41 -0
  48. data/lib/mail/fields/common/address_container.rb +16 -0
  49. data/lib/mail/fields/common/common_address.rb +135 -0
  50. data/lib/mail/fields/common/common_date.rb +35 -0
  51. data/lib/mail/fields/common/common_field.rb +57 -0
  52. data/lib/mail/fields/common/common_message_id.rb +48 -0
  53. data/lib/mail/fields/common/parameter_hash.rb +58 -0
  54. data/lib/mail/fields/content_description_field.rb +19 -0
  55. data/lib/mail/fields/content_disposition_field.rb +70 -0
  56. data/lib/mail/fields/content_id_field.rb +62 -0
  57. data/lib/mail/fields/content_location_field.rb +42 -0
  58. data/lib/mail/fields/content_transfer_encoding_field.rb +44 -0
  59. data/lib/mail/fields/content_type_field.rb +201 -0
  60. data/lib/mail/fields/date_field.rb +57 -0
  61. data/lib/mail/fields/from_field.rb +55 -0
  62. data/lib/mail/fields/in_reply_to_field.rb +56 -0
  63. data/lib/mail/fields/keywords_field.rb +44 -0
  64. data/lib/mail/fields/message_id_field.rb +82 -0
  65. data/lib/mail/fields/mime_version_field.rb +53 -0
  66. data/lib/mail/fields/optional_field.rb +13 -0
  67. data/lib/mail/fields/received_field.rb +75 -0
  68. data/lib/mail/fields/references_field.rb +56 -0
  69. data/lib/mail/fields/reply_to_field.rb +55 -0
  70. data/lib/mail/fields/resent_bcc_field.rb +55 -0
  71. data/lib/mail/fields/resent_cc_field.rb +55 -0
  72. data/lib/mail/fields/resent_date_field.rb +35 -0
  73. data/lib/mail/fields/resent_from_field.rb +55 -0
  74. data/lib/mail/fields/resent_message_id_field.rb +34 -0
  75. data/lib/mail/fields/resent_sender_field.rb +62 -0
  76. data/lib/mail/fields/resent_to_field.rb +55 -0
  77. data/lib/mail/fields/return_path_field.rb +65 -0
  78. data/lib/mail/fields/sender_field.rb +67 -0
  79. data/lib/mail/fields/structured_field.rb +51 -0
  80. data/lib/mail/fields/subject_field.rb +16 -0
  81. data/lib/mail/fields/to_field.rb +55 -0
  82. data/lib/mail/fields/unstructured_field.rb +204 -0
  83. data/lib/mail/header.rb +274 -0
  84. data/lib/mail/indifferent_hash.rb +146 -0
  85. data/lib/mail/mail.rb +267 -0
  86. data/lib/mail/matchers/has_sent_mail.rb +157 -0
  87. data/lib/mail/message.rb +2160 -0
  88. data/lib/mail/multibyte.rb +42 -0
  89. data/lib/mail/multibyte/chars.rb +474 -0
  90. data/lib/mail/multibyte/exceptions.rb +8 -0
  91. data/lib/mail/multibyte/unicode.rb +400 -0
  92. data/lib/mail/multibyte/utils.rb +60 -0
  93. data/lib/mail/network.rb +14 -0
  94. data/lib/mail/network/delivery_methods/exim.rb +52 -0
  95. data/lib/mail/network/delivery_methods/file_delivery.rb +45 -0
  96. data/lib/mail/network/delivery_methods/sendmail.rb +89 -0
  97. data/lib/mail/network/delivery_methods/smtp.rb +142 -0
  98. data/lib/mail/network/delivery_methods/smtp_connection.rb +61 -0
  99. data/lib/mail/network/delivery_methods/test_mailer.rb +44 -0
  100. data/lib/mail/network/retriever_methods/base.rb +63 -0
  101. data/lib/mail/network/retriever_methods/imap.rb +173 -0
  102. data/lib/mail/network/retriever_methods/pop3.rb +140 -0
  103. data/lib/mail/network/retriever_methods/test_retriever.rb +43 -0
  104. data/lib/mail/parsers.rb +26 -0
  105. data/lib/mail/parsers/address_lists_parser.rb +132 -0
  106. data/lib/mail/parsers/content_disposition_parser.rb +67 -0
  107. data/lib/mail/parsers/content_location_parser.rb +35 -0
  108. data/lib/mail/parsers/content_transfer_encoding_parser.rb +33 -0
  109. data/lib/mail/parsers/content_type_parser.rb +64 -0
  110. data/lib/mail/parsers/date_time_parser.rb +36 -0
  111. data/lib/mail/parsers/envelope_from_parser.rb +45 -0
  112. data/lib/mail/parsers/message_ids_parser.rb +39 -0
  113. data/lib/mail/parsers/mime_version_parser.rb +41 -0
  114. data/lib/mail/parsers/phrase_lists_parser.rb +33 -0
  115. data/lib/mail/parsers/ragel.rb +17 -0
  116. data/lib/mail/parsers/ragel/common.rl +184 -0
  117. data/lib/mail/parsers/ragel/date_time.rl +30 -0
  118. data/lib/mail/parsers/ragel/parser_info.rb +61 -0
  119. data/lib/mail/parsers/ragel/ruby.rb +39 -0
  120. data/lib/mail/parsers/ragel/ruby/machines/address_lists_machine.rb +14864 -0
  121. data/lib/mail/parsers/ragel/ruby/machines/address_lists_machine.rb.rl +37 -0
  122. data/lib/mail/parsers/ragel/ruby/machines/content_disposition_machine.rb +751 -0
  123. data/lib/mail/parsers/ragel/ruby/machines/content_disposition_machine.rb.rl +37 -0
  124. data/lib/mail/parsers/ragel/ruby/machines/content_location_machine.rb +614 -0
  125. data/lib/mail/parsers/ragel/ruby/machines/content_location_machine.rb.rl +37 -0
  126. data/lib/mail/parsers/ragel/ruby/machines/content_transfer_encoding_machine.rb +447 -0
  127. data/lib/mail/parsers/ragel/ruby/machines/content_transfer_encoding_machine.rb.rl +37 -0
  128. data/lib/mail/parsers/ragel/ruby/machines/content_type_machine.rb +825 -0
  129. data/lib/mail/parsers/ragel/ruby/machines/content_type_machine.rb.rl +37 -0
  130. data/lib/mail/parsers/ragel/ruby/machines/date_time_machine.rb +817 -0
  131. data/lib/mail/parsers/ragel/ruby/machines/date_time_machine.rb.rl +37 -0
  132. data/lib/mail/parsers/ragel/ruby/machines/envelope_from_machine.rb +2129 -0
  133. data/lib/mail/parsers/ragel/ruby/machines/envelope_from_machine.rb.rl +37 -0
  134. data/lib/mail/parsers/ragel/ruby/machines/message_ids_machine.rb +1570 -0
  135. data/lib/mail/parsers/ragel/ruby/machines/message_ids_machine.rb.rl +37 -0
  136. data/lib/mail/parsers/ragel/ruby/machines/mime_version_machine.rb +440 -0
  137. data/lib/mail/parsers/ragel/ruby/machines/mime_version_machine.rb.rl +37 -0
  138. data/lib/mail/parsers/ragel/ruby/machines/phrase_lists_machine.rb +564 -0
  139. data/lib/mail/parsers/ragel/ruby/machines/phrase_lists_machine.rb.rl +37 -0
  140. data/lib/mail/parsers/ragel/ruby/machines/rb_actions.rl +51 -0
  141. data/lib/mail/parsers/ragel/ruby/machines/received_machine.rb +5144 -0
  142. data/lib/mail/parsers/ragel/ruby/machines/received_machine.rb.rl +37 -0
  143. data/lib/mail/parsers/ragel/ruby/parser.rb.rl.erb +37 -0
  144. data/lib/mail/parsers/received_parser.rb +47 -0
  145. data/lib/mail/part.rb +120 -0
  146. data/lib/mail/parts_list.rb +57 -0
  147. data/lib/mail/patterns.rb +37 -0
  148. data/lib/mail/utilities.rb +225 -0
  149. data/lib/mail/values/unicode_tables.dat +0 -0
  150. data/lib/mail/version.rb +4 -0
  151. data/lib/mail/version_specific/ruby_1_8.rb +119 -0
  152. data/lib/mail/version_specific/ruby_1_9.rb +159 -0
  153. 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,19 @@
1
+ # encoding: utf-8
2
+
3
+ # This is not loaded if ActiveSupport is already loaded
4
+
5
+ class NilClass #:nodoc:
6
+ unless nil.respond_to? :blank?
7
+ def blank?
8
+ true
9
+ end
10
+ end
11
+
12
+ def to_crlf
13
+ ''
14
+ end
15
+
16
+ def to_lf
17
+ ''
18
+ end
19
+ end
@@ -0,0 +1,13 @@
1
+ # encoding: utf-8
2
+
3
+ unless Object.method_defined? :blank?
4
+ class Object
5
+ def blank?
6
+ if respond_to?(:empty?)
7
+ empty?
8
+ else
9
+ !self
10
+ end
11
+ end
12
+ end
13
+ 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