mail 1.0.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of mail might be problematic. Click here for more details.

Files changed (107) hide show
  1. data/.gitignore +4 -0
  2. data/Manifest.txt +106 -0
  3. data/README.rdoc +441 -0
  4. data/Rakefile +38 -0
  5. data/lib/mail.rb +86 -0
  6. data/lib/mail/attachment.rb +90 -0
  7. data/lib/mail/body.rb +149 -0
  8. data/lib/mail/configuration.rb +90 -0
  9. data/lib/mail/core_extensions.rb +6 -0
  10. data/lib/mail/core_extensions/blank.rb +41 -0
  11. data/lib/mail/core_extensions/nil.rb +15 -0
  12. data/lib/mail/core_extensions/string.rb +31 -0
  13. data/lib/mail/elements/address.rb +293 -0
  14. data/lib/mail/elements/address_list.rb +62 -0
  15. data/lib/mail/elements/content_disposition_element.rb +34 -0
  16. data/lib/mail/elements/content_transfer_encoding_element.rb +21 -0
  17. data/lib/mail/elements/content_type_element.rb +39 -0
  18. data/lib/mail/elements/date_time_element.rb +26 -0
  19. data/lib/mail/elements/envelope_from_element.rb +34 -0
  20. data/lib/mail/elements/message_ids_element.rb +29 -0
  21. data/lib/mail/elements/mime_version_element.rb +26 -0
  22. data/lib/mail/elements/phrase_list.rb +21 -0
  23. data/lib/mail/elements/received_element.rb +30 -0
  24. data/lib/mail/encodings/base64.rb +17 -0
  25. data/lib/mail/encodings/encodings.rb +24 -0
  26. data/lib/mail/encodings/quoted_printable.rb +26 -0
  27. data/lib/mail/envelope.rb +35 -0
  28. data/lib/mail/field.rb +202 -0
  29. data/lib/mail/field_list.rb +33 -0
  30. data/lib/mail/fields/bcc_field.rb +40 -0
  31. data/lib/mail/fields/cc_field.rb +40 -0
  32. data/lib/mail/fields/comments_field.rb +41 -0
  33. data/lib/mail/fields/common/common_address.rb +62 -0
  34. data/lib/mail/fields/common/common_date.rb +35 -0
  35. data/lib/mail/fields/common/common_field.rb +128 -0
  36. data/lib/mail/fields/common/common_message_id.rb +35 -0
  37. data/lib/mail/fields/content_description_field.rb +15 -0
  38. data/lib/mail/fields/content_disposition_field.rb +34 -0
  39. data/lib/mail/fields/content_id_field.rb +50 -0
  40. data/lib/mail/fields/content_transfer_encoding_field.rb +28 -0
  41. data/lib/mail/fields/content_type_field.rb +50 -0
  42. data/lib/mail/fields/date_field.rb +44 -0
  43. data/lib/mail/fields/from_field.rb +40 -0
  44. data/lib/mail/fields/in_reply_to_field.rb +42 -0
  45. data/lib/mail/fields/keywords_field.rb +22 -0
  46. data/lib/mail/fields/message_id_field.rb +70 -0
  47. data/lib/mail/fields/mime_version_field.rb +42 -0
  48. data/lib/mail/fields/optional_field.rb +11 -0
  49. data/lib/mail/fields/received_field.rb +49 -0
  50. data/lib/mail/fields/references_field.rb +42 -0
  51. data/lib/mail/fields/reply_to_field.rb +40 -0
  52. data/lib/mail/fields/resent_bcc_field.rb +40 -0
  53. data/lib/mail/fields/resent_cc_field.rb +40 -0
  54. data/lib/mail/fields/resent_date_field.rb +16 -0
  55. data/lib/mail/fields/resent_from_field.rb +40 -0
  56. data/lib/mail/fields/resent_message_id_field.rb +20 -0
  57. data/lib/mail/fields/resent_sender_field.rb +48 -0
  58. data/lib/mail/fields/resent_to_field.rb +40 -0
  59. data/lib/mail/fields/return_path_field.rb +34 -0
  60. data/lib/mail/fields/sender_field.rb +48 -0
  61. data/lib/mail/fields/structured_field.rb +32 -0
  62. data/lib/mail/fields/subject_field.rb +14 -0
  63. data/lib/mail/fields/to_field.rb +40 -0
  64. data/lib/mail/fields/unstructured_field.rb +27 -0
  65. data/lib/mail/header.rb +213 -0
  66. data/lib/mail/mail.rb +120 -0
  67. data/lib/mail/message.rb +648 -0
  68. data/lib/mail/network/deliverable.rb +42 -0
  69. data/lib/mail/network/retrievable.rb +63 -0
  70. data/lib/mail/parsers/address_lists.rb +61 -0
  71. data/lib/mail/parsers/address_lists.treetop +19 -0
  72. data/lib/mail/parsers/content_disposition.rb +358 -0
  73. data/lib/mail/parsers/content_disposition.treetop +45 -0
  74. data/lib/mail/parsers/content_transfer_encoding.rb +179 -0
  75. data/lib/mail/parsers/content_transfer_encoding.treetop +25 -0
  76. data/lib/mail/parsers/content_type.rb +507 -0
  77. data/lib/mail/parsers/content_type.treetop +58 -0
  78. data/lib/mail/parsers/date_time.rb +111 -0
  79. data/lib/mail/parsers/date_time.treetop +11 -0
  80. data/lib/mail/parsers/envelope_from.rb +188 -0
  81. data/lib/mail/parsers/envelope_from.treetop +32 -0
  82. data/lib/mail/parsers/message_ids.rb +42 -0
  83. data/lib/mail/parsers/message_ids.treetop +15 -0
  84. data/lib/mail/parsers/mime_version.rb +141 -0
  85. data/lib/mail/parsers/mime_version.treetop +19 -0
  86. data/lib/mail/parsers/phrase_lists.rb +42 -0
  87. data/lib/mail/parsers/phrase_lists.treetop +15 -0
  88. data/lib/mail/parsers/received.rb +68 -0
  89. data/lib/mail/parsers/received.treetop +11 -0
  90. data/lib/mail/parsers/rfc2045.rb +406 -0
  91. data/lib/mail/parsers/rfc2045.treetop +35 -0
  92. data/lib/mail/parsers/rfc2822.rb +5005 -0
  93. data/lib/mail/parsers/rfc2822.treetop +402 -0
  94. data/lib/mail/parsers/rfc2822_obsolete.rb +3607 -0
  95. data/lib/mail/parsers/rfc2822_obsolete.treetop +241 -0
  96. data/lib/mail/part.rb +120 -0
  97. data/lib/mail/patterns.rb +42 -0
  98. data/lib/mail/utilities.rb +142 -0
  99. data/lib/mail/version.rb +10 -0
  100. data/lib/mail/version_specific/multibyte.rb +62 -0
  101. data/lib/mail/version_specific/multibyte/chars.rb +701 -0
  102. data/lib/mail/version_specific/multibyte/exceptions.rb +8 -0
  103. data/lib/mail/version_specific/multibyte/unicode_database.rb +71 -0
  104. data/lib/mail/version_specific/ruby_1_8.rb +61 -0
  105. data/lib/mail/version_specific/ruby_1_8_string.rb +88 -0
  106. data/lib/mail/version_specific/ruby_1_9.rb +49 -0
  107. metadata +192 -0
@@ -0,0 +1,38 @@
1
+ require 'rake'
2
+ require 'rake/rdoctask'
3
+ require 'rake/testtask'
4
+ require 'rubygems'
5
+ require 'spec/rake/spectask'
6
+ require 'cucumber/rake/task'
7
+
8
+ task :default => :spec
9
+
10
+ Cucumber::Rake::Task.new do |t|
11
+ t.cucumber_opts = "spec/features --format pretty"
12
+ end
13
+
14
+ Spec::Rake::SpecTask.new(:rcov) do |t|
15
+ gem 'relevance-rcov', '>= 0.8.4.1'
16
+ t.spec_files = FileList['**/test/**/tc_*.rb', '**/spec/**/*_spec.rb']
17
+ t.rcov = true
18
+ t.rcov_opts = t.rcov_opts << ['--exclude', '/Library,/opt,/System']
19
+ end
20
+
21
+ Spec::Rake::SpecTask.new(:spec) do |t|
22
+ t.spec_files = FileList['**/spec/**/*_spec.rb']
23
+ end
24
+
25
+ Rake::TestTask.new(:test) do |t|
26
+ t.libs << 'test'
27
+ t.pattern = '**/test/**/tc_*.rb'
28
+ t.verbose = true
29
+ t.warning = false
30
+ end
31
+
32
+ Rake::RDocTask.new(:rdoc) do |rdoc|
33
+ rdoc.rdoc_dir = 'rdoc'
34
+ rdoc.title = 'Mail'
35
+ rdoc.options << '--line-numbers' << '--inline-source'
36
+ rdoc.rdoc_files.include('README')
37
+ rdoc.rdoc_files.include('lib/**/*.rb')
38
+ end
@@ -0,0 +1,86 @@
1
+ # encoding: utf-8
2
+ module Mail # :doc:
3
+
4
+ require 'date'
5
+
6
+ gem "treetop", ">= 1.4"
7
+ require 'treetop'
8
+
9
+ require 'net/smtp'
10
+ require 'mime/types'
11
+ require 'tlsmail' if RUBY_VERSION <= '1.8.6'
12
+
13
+ dir_name = File.join(File.dirname(__FILE__), 'mail')
14
+
15
+ if RUBY_VERSION >= "1.9.1"
16
+ require File.join(dir_name, 'version_specific', 'ruby_1_9.rb')
17
+ RubyVer = Mail::Ruby19
18
+ else
19
+ require File.join(dir_name, 'version_specific', 'ruby_1_8.rb')
20
+ require File.join(dir_name, 'version_specific', 'ruby_1_8_string.rb')
21
+ RubyVer = Mail::Ruby18
22
+ end
23
+
24
+ require File.join(dir_name, 'version')
25
+ require File.join(dir_name, 'core_extensions')
26
+ require File.join(dir_name, 'patterns')
27
+ require File.join(dir_name, 'utilities')
28
+ require File.join(dir_name, 'configuration')
29
+ require File.join(dir_name, 'network', 'deliverable')
30
+ require File.join(dir_name, 'network', 'retrievable')
31
+
32
+ require File.join(dir_name, 'message')
33
+ require File.join(dir_name, 'part')
34
+ require File.join(dir_name, 'header')
35
+ require File.join(dir_name, 'body')
36
+ require File.join(dir_name, 'field')
37
+ require File.join(dir_name, 'field_list')
38
+ require File.join(dir_name, 'attachment')
39
+
40
+ # Load in all common header fields modules
41
+ commons = Dir.glob(File.join(dir_name, 'fields', 'common', '*.rb'))
42
+ commons.each do |common|
43
+ require common
44
+ end
45
+
46
+ require File.join(dir_name, 'fields', 'structured_field')
47
+ require File.join(dir_name, 'fields', 'unstructured_field')
48
+ require File.join(dir_name, 'envelope')
49
+
50
+ parsers = %w[ rfc2822_obsolete rfc2822 address_lists phrase_lists
51
+ date_time received message_ids envelope_from rfc2045
52
+ mime_version content_type content_disposition
53
+ content_transfer_encoding ]
54
+
55
+ parsers.each do |parser|
56
+ begin
57
+ # Try requiring the pre-compiled ruby version first
58
+ require File.join(dir_name, 'parsers', parser)
59
+ rescue LoadError
60
+ # Otherwise, get treetop to compile and load it
61
+ Treetop.load(File.join(dir_name, 'parsers', parser))
62
+ end
63
+ end
64
+
65
+ # Load in all header field elements
66
+ elems = Dir.glob(File.join(dir_name, 'elements', '*.rb'))
67
+ elems.each do |elem|
68
+ require elem
69
+ end
70
+
71
+ # Load in all header fields
72
+ fields = Dir.glob(File.join(dir_name, 'fields', '*.rb'))
73
+ fields.each do |field|
74
+ require field
75
+ end
76
+
77
+ # Load in all transfer encodings
78
+ elems = Dir.glob(File.join(dir_name, 'encodings', '*.rb'))
79
+ elems.each do |elem|
80
+ require elem
81
+ end
82
+
83
+ # Finally... require all the Mail.methods
84
+ require File.join(dir_name, 'mail')
85
+
86
+ end
@@ -0,0 +1,90 @@
1
+ # encoding: utf-8
2
+ module Mail
3
+ # An attachment is any data you want to attach to a mail message that is
4
+ # not part of the body and can be extracted to a file in it's own right
5
+ #
6
+ # This includes images, sound files, text files, documents, anything really,
7
+ # the only requisite is that it has a file name and an encoding.
8
+ #
9
+ # If you do not pass in an encoding when creating a new attachment, then
10
+ # Mail::Attachment will assume that the data you pass in is raw data and
11
+ # encode it with base64.
12
+ #
13
+ # If you pass in an encoding, Mail::Attachment will assume that the data
14
+ # is encoded data and attempt to decode the data string with the encoding
15
+ # you supply.
16
+ #
17
+ # So, raw data should be given in with no encoding, pre encoded data should
18
+ # be given with an encoding type.
19
+ #
20
+ # Attachment will always encode with Base64, it's safe, it works, maybe in
21
+ # the future we will allow you to encode with different types. If you really
22
+ # want to encode with a different encoder, then pre encode the data and pass
23
+ # it in with an encoding. Mail::Attachment will happily initialize for you,
24
+ # however, if it doesn't understand the encoding, it will not decode for you
25
+ # and raise an error, but if you can encode it, we assume you know how to
26
+ # decode it, so just get back the encoded source (with #encoded) and then
27
+ # decode at your leisure.
28
+ class Attachment
29
+
30
+ include Utilities
31
+
32
+ # Raised when attempting to decode an unknown encoding type
33
+ class UnknownEncodingType < StandardError #:nodoc:
34
+ end
35
+
36
+ def initialize(options_hash)
37
+ case
38
+ when options_hash[:data]
39
+ @filename = options_hash[:filename]
40
+ add_file(options_hash[:data], options_hash[:encoding])
41
+ when options_hash[:filename]
42
+ @filename = File.basename(options_hash[:filename])
43
+ data = File.read(options_hash[:filename])
44
+ add_file(data, options_hash[:encoding])
45
+ end
46
+ set_mime_type(@filename, options_hash[:mime_type])
47
+ end
48
+
49
+ def filename
50
+ @filename
51
+ end
52
+
53
+ def encoded
54
+ @encoded_data
55
+ end
56
+
57
+ def decoded
58
+ if Mail::Encodings.defined?(@encoding)
59
+ Mail::Encodings.get_encoding(@encoding).decode(@encoded_data)
60
+ else
61
+ raise UnknownEncodingType, "Don't know how to decode #{@encoding}, please call #encoded and decode it yourself."
62
+ end
63
+ end
64
+
65
+ def mime_type
66
+ @mime_type.to_s
67
+ end
68
+
69
+ private
70
+
71
+ def set_mime_type(filename, mime_type)
72
+ unless mime_type
73
+ @mime_type = MIME::Types.type_for(filename).first
74
+ else
75
+ @mime_type = mime_type
76
+ end
77
+ end
78
+
79
+ def add_file(data, encoding)
80
+ if encoding # We are being given encoded data
81
+ @encoded_data = data
82
+ @encoding = encoding.to_s
83
+ else # this is raw data
84
+ @encoded_data = Mail::Encodings::Base64.encode(data)
85
+ @encoding = 'base64'
86
+ end
87
+ end
88
+
89
+ end
90
+ end
@@ -0,0 +1,149 @@
1
+ # encoding: utf-8
2
+ module Mail
3
+
4
+ # = Body
5
+ #
6
+ # The body is where the text of the email is stored. Mail treats the body
7
+ # as a single object. The body itself has no information about boundaries
8
+ # used in the MIME standard, it just looks at it's content as either a single
9
+ # block of text, or (if it is a multipart message) as an array of blocks o text.
10
+ #
11
+ # A body has to be told to split itself up into a multipart message by calling
12
+ # #split with the correct boundary. This is because the body object has no way
13
+ # of knowing what the correct boundary is for itself (there could be many
14
+ # boundaries in a body in the case of a nested MIME text).
15
+ #
16
+ # Once split is called, Mail::Body will slice itself up on this boundary,
17
+ # assigning anything that appears before the first part to the preamble, and
18
+ # anything that appears after the closing boundary to the epilogue, then
19
+ # each part gets initialized into a Mail::Part object.
20
+ #
21
+ # The boundary that is used to split up the Body is also stored in the Body
22
+ # object for use on encoding itself back out to a string. You can
23
+ # overwrite this if it needs to be changed.
24
+ #
25
+ # On encoding, the body will return the preamble, then each part joined by
26
+ # the boundary, followed by a closing boundary string and then the epilogue.
27
+ class Body
28
+
29
+ def initialize(string = '')
30
+ if string.blank?
31
+ @raw_source = ''
32
+ else
33
+ @raw_source = string
34
+ end
35
+ set_charset
36
+ end
37
+
38
+ # Returns the raw source that the body was initialized with, without
39
+ # any tampering
40
+ def raw_source
41
+ @raw_source
42
+ end
43
+
44
+ # Returns a US-ASCII 7-bit compliant body. Right now just returns the
45
+ # raw source. Need to implement
46
+ def encoded
47
+ if multipart?
48
+ encoded_parts = parts.map { |p| p.to_s }
49
+ ([preamble] + encoded_parts).join(crlf_boundary) + end_boundary + epilogue.to_s
50
+ else
51
+ raw_source
52
+ end
53
+ end
54
+
55
+ alias :to_s :encoded
56
+
57
+ def charset
58
+ @charset
59
+ end
60
+
61
+ def charset=( val )
62
+ @charset = val
63
+ end
64
+
65
+ def encoding
66
+ @encoding
67
+ end
68
+
69
+ def encoding=( val )
70
+ @encoding = val
71
+ end
72
+
73
+ # Returns the preamble (any text that is before the first MIME boundary)
74
+ def preamble
75
+ @preamble
76
+ end
77
+
78
+ # Sets the preamble to a string (adds text before the first mime boundary)
79
+ def preamble=( val )
80
+ @preamble = val
81
+ end
82
+
83
+ # Returns the epilogue (any text that is after the last MIME boundary)
84
+ def epilogue
85
+ @epilogue
86
+ end
87
+
88
+ # Sets the epilogue to a string (adds text after the last mime boundary)
89
+ def epilogue=( val )
90
+ @epilogue = val
91
+ end
92
+
93
+ # Returns true if there are parts defined in the body
94
+ def multipart?
95
+ true unless parts.empty?
96
+ end
97
+
98
+ # Returns the boundary used by the body
99
+ def boundary
100
+ @boundary
101
+ end
102
+
103
+ # Allows you to change the boundary of this Body object
104
+ def boundary=( val )
105
+ @boundary = val
106
+ end
107
+
108
+ def parts
109
+ @parts ||= []
110
+ end
111
+
112
+ def <<( val )
113
+ if @parts
114
+ @parts << val
115
+ else
116
+ @parts = [val]
117
+ end
118
+ end
119
+
120
+ def split!(boundary)
121
+ self.boundary = boundary
122
+ parts = raw_source.split("--#{boundary}")
123
+ # Make the preamble equal to the preamble (if any)
124
+ self.preamble = parts[0].to_s.strip
125
+ # Make the epilogue equal to the epilogue (if any)
126
+ self.epilogue = parts[-1].to_s.sub('--', '').strip
127
+ @parts = parts[1...-1].map { |part| Mail::Part.new(part) }
128
+ self
129
+ end
130
+
131
+ def only_us_ascii?
132
+ !!raw_source.to_s.ascii_only?
133
+ end
134
+
135
+ private
136
+
137
+ def crlf_boundary
138
+ "\r\n\r\n--#{boundary}\r\n"
139
+ end
140
+
141
+ def end_boundary
142
+ "\r\n\r\n--#{boundary}--\r\n"
143
+ end
144
+
145
+ def set_charset
146
+ raw_source.ascii_only? ? @charset = 'US-ASCII' : @charset = nil
147
+ end
148
+ end
149
+ end
@@ -0,0 +1,90 @@
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 SMTP, POP3 and IMAP operations handled by Mail.
11
+ # See Mail.defaults for more information.
12
+ class Configuration
13
+ include Singleton
14
+
15
+ # Creates a new Mail::Configuration object through .defaults
16
+ def defaults(&block)
17
+ if block_given?
18
+ instance_eval(&block)
19
+ end
20
+ self
21
+ end
22
+
23
+ # Allows you to specify the SMTP Server by passing the hostname
24
+ # or IP Address as a String with an optional port number as a
25
+ # string or integer.
26
+ #
27
+ # Defaults to 127.0.0.1 and port 25.
28
+ #
29
+ # Example:
30
+ #
31
+ # Mail.defaults.do
32
+ # smtp '127.0.0.1'
33
+ # end
34
+ #
35
+ # Mail.defaults do
36
+ # smtp '127.0.0.1', 25
37
+ # end
38
+ def smtp(*args)
39
+ if args.size > 0
40
+ @smtp = [args[0], (args[1].to_i > 0 ? args[1] : 25)]
41
+ end
42
+ @smtp
43
+ end
44
+
45
+ # Allows you to specify the POP3 Server by passing the hostname
46
+ # or IP Address as a String with an optional port number as a
47
+ # string or integer.
48
+ #
49
+ # Defaults to 127.0.0.1 and port 110.
50
+ #
51
+ # Example:
52
+ #
53
+ # Mail.defaults.do
54
+ # pop3 '127.0.0.1'
55
+ # end
56
+ #
57
+ # Mail.defaults do
58
+ # pop3 '127.0.0.1', 110
59
+ # end
60
+ def pop3(*args)
61
+ if args.size > 0
62
+ @pop3 = [args[0], (args[1].to_i > 0 ? args[1] : 110)]
63
+ end
64
+ @pop3
65
+ end
66
+
67
+ # Pass in the username to use for POP3 or IMAP access
68
+ def user(value = nil)
69
+ value ? @user = value : @user
70
+ end
71
+
72
+ def pass(value = nil)
73
+ value ? @pass = value : @pass
74
+ end
75
+
76
+ def enable_tls
77
+ @tls = true
78
+ end
79
+
80
+ def disable_tls
81
+ @tls = false
82
+ end
83
+
84
+ def tls?
85
+ @tls || false
86
+ end
87
+
88
+ end
89
+
90
+ end