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.
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