mail 1.6.0 → 2.0.3

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.

data/CHANGELOG.rdoc CHANGED
@@ -1,3 +1,40 @@
1
+ == Sat Jan 23 05:32:53 UTC 2010 Mikel Lindsaar <raasdnil@gmail.com>
2
+
3
+ * Version bump to 2.0.3
4
+ * Made body.sort_parts! recursive, to do the entire body
5
+ * Added ability to use << on the results returned by the various address fields, ie, mail.to << 'new@address' now works
6
+ * Message now adds multipart/mixed as the content type if nothing is set and there are parts to the message
7
+ * Added #display_names and #addrs to all address fields. #addrs returns the actual Mail::Address object for each address in the field.
8
+ * Body should call to_s on given input... incase someone gave it an IO.readlines result (Array)
9
+ *
10
+
11
+ == Thu Jan 21 05:27:17 UTC 2010 Mikel Lindsaar <raasdnil@gmail.com>
12
+
13
+ * Version bump to 2.0.2
14
+ * Major change to attachments, add_file now only accepts
15
+ {:filename => 'full/path/to/file.png'} or
16
+ {:filename => 'file.png', :content => 'string of file content'}
17
+ you can also now do mail.attachments['filename.png'] = File.read('path/to/file.png')
18
+ which is nice too!
19
+
20
+ == Fri Jan 15 09:20:51 UTC 2010 Mikel Lindsaar <raasdnil@gmail.com>
21
+
22
+ * Rewrote all network classes to not use singletons. Means different Mail::Message objects can have different delivery methods.
23
+ * Added examples for how to send via GMail, MobileMe, Sendmail, File etc.
24
+ * Version bump to 2.0.0 as Network API changed drastically, now not a singleton class.
25
+ * Fixed that return-path should only return one address
26
+
27
+ == Thu Jan 14 10:41:22 UTC 2010 Mikel Lindsaar <raasdnil@gmail.com>
28
+
29
+ * Version update to 1.6.0 - API change on mail.address_fields to always return arrays
30
+ * Updated all message.address_field methods to always return arrays, so mail.from #=> ['one@address.com'] now, is least surprise
31
+ * Updated handling of empty group lists so it didn't crash
32
+
33
+ == Thu Jan 12 10:41:47 UTC 2010 Mikel Lindsaar <raasdnil@gmail.com>
34
+
35
+ * Version 1.5.3, handling invalid input on fields. Highly recommended update
36
+ * Updated fields to always try parsing the given data (unless blank). This allows mail to catch invalid input and return UnstructuredFields. Makes mail a lot more resistant to invalid input.
37
+
1
38
  == Fri 8 Jan 2010 00:00:08 UTC Mikel Lindsaar <raasdnil@gmail.com>
2
39
 
3
40
  * Version bump to 1.5.2
data/README.rdoc CHANGED
@@ -230,7 +230,7 @@ what you are doing.
230
230
  to 'you@test.lindsaar.net'
231
231
  subject 'Here is the image you wanted'
232
232
  body File.read('body.txt')
233
- add_file '/somefile.png'
233
+ add_file '/full/path/to/somefile.png'
234
234
  end
235
235
 
236
236
  or
@@ -244,11 +244,12 @@ or
244
244
  to 'you@test.lindsaar.net'
245
245
  subject 'Here is the image you wanted'
246
246
  body File.read('body.txt')
247
- add_file {:filename => 'somefile.png', :data => File.read('/somefile.png')}
247
+ add_file {:filename => 'somefile.png', :content => File.read('/somefile.png')}
248
248
  end
249
249
 
250
250
  mail.deliver!
251
251
 
252
+
252
253
  === Getting emails from a pop server:
253
254
 
254
255
  The most recent email:
@@ -451,7 +452,7 @@ You can just read the file off an absolute path, Mail will try
451
452
  to guess the mime_type and will encode the file in Base64 for you.
452
453
 
453
454
  @mail = Mail.new
454
- @mail.add_file(:filename => "/path/to/file.jpg")
455
+ @mail.add_file("/path/to/file.jpg")
455
456
  @mail.parts.first.attachment? #=> true
456
457
  @mail.parts.first.content_transfer_encoding.to_s #=> 'base64'
457
458
  @mail.attachments.first.mime_type #=> 'image/jpg'
@@ -462,8 +463,7 @@ Or You can pass in file_data and give it a filename, again, mail
462
463
  will try and guess the mime_type for you.
463
464
 
464
465
  @mail = Mail.new
465
- file_data = File.read('path/to/myfile.pdf')
466
- @mail.add_file(:filename => 'myfile.pdf', :data => file_data)
466
+ @mail.attachments['myfile.pdf'] = File.read('path/to/myfile.pdf')
467
467
  @mail.parts.first.attachment? #=> true
468
468
  @mail.attachments.first.mime_type #=> 'application/pdf'
469
469
  @mail.attachments.first.decoded == File.read('path/to/myfile.pdf') #=> true
@@ -473,9 +473,8 @@ than mail (this should be rarely needed)
473
473
 
474
474
  @mail = Mail.new
475
475
  file_data = File.read('path/to/myfile.pdf')
476
- @mail.add_file(:filename => 'myfile.pdf',
477
- :data => file_data,
478
- :mime_type => 'application/x-pdf')
476
+ @mail.attachments['myfile.pdf'] = { :mime_type => 'application/x-pdf',
477
+ :content => File.read('path/to/myfile.pdf') }
479
478
  @mail.parts.first.mime_type #=> 'application/x-pdf'
480
479
 
481
480
  Of course... Mail will round trip an attachment as well
@@ -491,7 +490,7 @@ Of course... Mail will round trip an attachment as well
491
490
  content_type 'text/html; charset=UTF-8'
492
491
  body '<h1>Funky Title</h1><p>Here is the attachment you wanted</p>'
493
492
  end
494
- add_file :filename => '/path/to/myfile.pdf'
493
+ add_file '/path/to/myfile.pdf'
495
494
  end
496
495
 
497
496
  @round_tripped_mail = Mail.new(@mail.encoded)
@@ -507,7 +506,7 @@ sending emails, the TestMailer can do this for you.
507
506
  require 'mail'
508
507
  => true
509
508
  Mail.defaults do
510
- delivery_method(:test)
509
+ delivery_method :test
511
510
  end
512
511
  => #<Mail::Configuration:0x19345a8 @delivery_method=Mail::TestMailer>
513
512
  Mail.deliveries
data/Rakefile CHANGED
@@ -12,7 +12,7 @@ require 'bundler'
12
12
 
13
13
  spec = Gem::Specification.new do |s|
14
14
  s.name = "mail"
15
- s.version = "1.6.0"
15
+ s.version = "2.0.3"
16
16
  s.author = "Mike Lindsaar"
17
17
  s.email = "raasdnil@gmail.com"
18
18
  s.homepage = "http://github.com/mikel/mail"
data/lib/mail.rb CHANGED
@@ -46,24 +46,24 @@ module Mail # :doc:
46
46
  require 'mail/patterns'
47
47
  require 'mail/utilities'
48
48
  require 'mail/configuration'
49
- require 'mail/network/deliverable'
50
49
  require 'mail/network/delivery_methods/smtp'
51
50
  require 'mail/network/delivery_methods/file_delivery'
52
51
  require 'mail/network/delivery_methods/sendmail'
53
52
  require 'mail/network/delivery_methods/test_mailer'
54
- require 'mail/network/retrievable'
55
53
  require 'mail/network/retriever_methods/pop3'
56
54
  require 'mail/network/retriever_methods/imap'
57
55
 
58
56
  require 'mail/message'
59
57
  require 'mail/part'
60
58
  require 'mail/header'
59
+ require 'mail/parts_list'
60
+ require 'mail/attachments_list'
61
61
  require 'mail/body'
62
62
  require 'mail/field'
63
63
  require 'mail/field_list'
64
- require 'mail/attachment'
65
64
 
66
65
  # Load in all common header fields modules
66
+ require 'mail/fields/common/address_container'
67
67
  require 'mail/fields/common/common_address'
68
68
  require 'mail/fields/common/common_date'
69
69
  require 'mail/fields/common/common_field'
@@ -0,0 +1,76 @@
1
+ module Mail
2
+ class AttachmentsList < Array
3
+
4
+ def initialize(parts_list)
5
+ @parts_list = parts_list
6
+ parts_list.map { |p|
7
+ if p.parts.empty?
8
+ p if p.attachment?
9
+ else
10
+ p.attachments
11
+ end
12
+ }.flatten.compact.each { |a| self << a }
13
+ self
14
+ end
15
+
16
+ # Returns the attachment by filename or at index.
17
+ #
18
+ # mail.attachments['test.png'] = File.read('test.png')
19
+ # mail.attachments['test.jpg'] = File.read('test.jpg')
20
+ #
21
+ # mail.attachments['test.png'].filename #=> 'test.png'
22
+ # mail.attachments[1].filename #=> 'test.jpg'
23
+ def [](index_value)
24
+ if index_value.is_a?(Fixnum)
25
+ self.fetch(index_value)
26
+ else
27
+ self.select { |a| a.filename == index_value }.first
28
+ end
29
+ end
30
+
31
+ def []=(name, value)
32
+ default_values = { :content_type => "#{set_mime_type(name)}; filename=\"#{name}\"",
33
+ :content_transfer_encoding => 'Base64',
34
+ :content_disposition => "attachment; filename=\"#{name}\"" }
35
+
36
+ if value.is_a?(Hash)
37
+
38
+ default_values[:body] = value.delete(:content) if value[:content]
39
+
40
+ default_values[:body] = value.delete(:data) if value[:data]
41
+
42
+ # Only force encode base64 if the user has not specified an encoding
43
+ if value[:transfer_encoding]
44
+ default_values[:content_transfer_encoding] = value.delete(:transfer_encoding)
45
+ elsif value[:encoding]
46
+ default_values[:content_transfer_encoding] = value.delete(:encoding)
47
+ else
48
+ default_values[:body] = Mail::Encodings::Base64.encode(default_values[:body])
49
+ end
50
+
51
+ if value[:mime_type]
52
+ default_values[:content_type] = value.delete(:mime_type)
53
+ end
54
+
55
+ hash = default_values.merge(value)
56
+ else
57
+ default_values[:body] = Mail::Encodings::Base64.encode(value)
58
+ hash = default_values
59
+ end
60
+
61
+ @parts_list << Part.new(hash)
62
+ end
63
+
64
+ def set_mime_type(filename)
65
+ # Have to do this because MIME::Types is not Ruby 1.9 safe yet
66
+ if RUBY_VERSION >= '1.9'
67
+ new_file = String.new(filename).force_encoding(Encoding::BINARY)
68
+ ext = new_file.split('.'.force_encoding(Encoding::BINARY)).last
69
+ filename = "file.#{ext}".force_encoding('US-ASCII')
70
+ end
71
+ @mime_type = MIME::Types.type_for(filename).first
72
+ end
73
+
74
+ end
75
+ end
76
+
data/lib/mail/body.rb CHANGED
@@ -31,11 +31,18 @@ module Mail
31
31
  @preamble = nil
32
32
  @epilogue = nil
33
33
  @part_sort_order = [ "text/plain", "text/enriched", "text/html" ]
34
- @parts = []
34
+ @parts = Mail::PartsList.new
35
35
  if string.blank?
36
36
  @raw_source = ''
37
37
  else
38
- @raw_source = string
38
+ # Do join first incase we have been given an Array in Ruby 1.9
39
+ if string.respond_to?(:join)
40
+ @raw_source = string.join('')
41
+ elsif string.respond_to?(:to_s)
42
+ @raw_source = string.to_s
43
+ else
44
+ raise "You can only assign a string or an object that responds_to? :join or :to_s to a body."
45
+ end
39
46
  end
40
47
  @encoding = nil
41
48
  set_charset
@@ -103,15 +110,12 @@ module Mail
103
110
  #
104
111
  # sort_parts! is also called from :encode, so there is no need for you to call this explicitly
105
112
  def sort_parts!
106
- order = @part_sort_order
107
- @parts = @parts.sort do |a, b|
108
- # OK, 10000 is arbitrary... if anyone actually wants to explicitly sort 10000 parts of a
109
- # single email message... please show me a use case and I'll put more work into this method,
110
- # in the meantime, it works :)
111
- a_order = order.index(a[:content_type].string.downcase) || 10000
112
- b_order = order.index(b[:content_type].string.downcase) || 10000
113
- a_order <=> b_order
113
+ @parts.each do |p|
114
+ p.body.set_sort_order(@part_sort_order)
115
+ @parts.sort!(@part_sort_order)
116
+ p.body.sort_parts!
114
117
  end
118
+ # @parts.sort!(@part_sort_order)
115
119
  end
116
120
 
117
121
  # Returns the raw source that the body was initialized with, without
@@ -144,10 +148,6 @@ module Mail
144
148
  decoded
145
149
  end
146
150
 
147
- def to_str
148
- to_s
149
- end
150
-
151
151
  def charset
152
152
  @charset
153
153
  end
@@ -207,7 +207,7 @@ module Mail
207
207
  if @parts
208
208
  @parts << val
209
209
  else
210
- @parts = [val]
210
+ @parts = Mail::PartsList.new[val]
211
211
  end
212
212
  end
213
213
 
@@ -218,7 +218,7 @@ module Mail
218
218
  self.preamble = parts[0].to_s.strip
219
219
  # Make the epilogue equal to the epilogue (if any)
220
220
  self.epilogue = parts[-1].to_s.sub('--', '').strip
221
- @parts = parts[1...-1].to_a.map { |part| Mail::Part.new(part) }
221
+ parts[1...-1].to_a.each { |part| @parts << Mail::Part.new(part) }
222
222
  self
223
223
  end
224
224
 
@@ -7,134 +7,58 @@ require 'singleton'
7
7
  module Mail
8
8
 
9
9
  # The Configuration class is a Singleton used to hold the default
10
- # configuration for all class wide configurations of Mail.
10
+ # configuration for all Mail objects.
11
11
  #
12
- # This includes things like running in Test mode, the POP3, IMAP,
13
- # SMTP, Sendmail and File delivery method information et al.
14
- #
15
- # See Mail.defaults for more information.
12
+ # Each new mail object gets a copy of these values at initialization
13
+ # which can be overwritten on a per mail object basis.
16
14
  class Configuration
17
15
  include Singleton
18
16
 
19
- # Creates a new Mail::Configuration object through .defaults
20
- def defaults(&block)
21
- if block_given?
22
- instance_eval(&block)
23
- end
24
- self
25
- end
26
-
27
- # Allows you to specify the SMTP Server by passing the hostname
28
- # or IP Address as a String with an optional port number as a
29
- # string or integer.
30
- #
31
- # Defaults to 127.0.0.1 and port 25.
32
- #
33
- # Example:
34
- #
35
- # Mail.defaults.do
36
- # smtp '127.0.0.1'
37
- # end
38
- #
39
- # Mail.defaults do
40
- # smtp '127.0.0.1', 25
41
- # end
42
- def smtp(*args, &block)
43
- if args.size > 0
44
- host_array = [args[0], (args[1].to_i > 0 ? args[1] : 25)]
45
- end
46
- set_settings(Mail::SMTP, host_array, &block)
47
- end
17
+ @delivery_method = nil
18
+ @retriever_method = nil
48
19
 
49
- # Allows you to define the delivery method for mail, defaults to SMTP
50
- #
51
- # This can either be a symbol (:smtp, :sendmail, :file, :test) or you can pass
52
- # in your own delivery class, in which case this will be set.
53
- def delivery_method(value = nil)
54
- value ? @delivery_method = lookup_delivery_method(value) : @delivery_method ||= Mail::SMTP
20
+ def delivery_method(method = nil, settings = {})
21
+ return @delivery_method if @delivery_method && method.nil?
22
+ @delivery_method = lookup_delivery_method(method).new(settings)
55
23
  end
56
-
57
- # Allows you to specify the POP3 Server by passing the hostname
58
- # or IP Address as a String with an optional port number as a
59
- # string or integer.
60
- #
61
- # Defaults to 127.0.0.1 and port 110.
62
- #
63
- # Example:
64
- #
65
- # Mail.defaults.do
66
- # pop3 '127.0.0.1'
67
- # end
68
- #
69
- # Mail.defaults do
70
- # pop3 '127.0.0.1', 995 do
71
- # enable_tls
72
- # end
73
- # end
74
- def pop3(*args, &block)
75
- if args.size > 0
76
- host_array = [args[0], (args[1].to_i > 0 ? args[1] : 110)]
24
+
25
+ def lookup_delivery_method(method)
26
+ case method
27
+ when nil
28
+ Mail::SMTP
29
+ when :smtp
30
+ Mail::SMTP
31
+ when :sendmail
32
+ Mail::Sendmail
33
+ when :file
34
+ Mail::FileDelivery
35
+ when :test
36
+ Mail::TestMailer
37
+ else
38
+ method
77
39
  end
78
- set_settings(Mail::POP3, host_array, &block)
79
40
  end
80
41
 
81
- def sendmail(sendmail_path = nil)
82
- delivery_method :sendmail
83
- set_settings(Mail::Sendmail) do
84
- path sendmail_path
85
- end
42
+ def retriever_method(method = nil, settings = {})
43
+ return @retriever_method if @retriever_method && method.nil?
44
+ @retriever_method = lookup_retriever_method(method).new(settings)
86
45
  end
87
46
 
88
- # Allows you to define the retriever method for mail, defaults to POP3
89
- #
90
- # This can either be a symbol (:pop3, :imap) or you can pass
91
- # in your own retriever class, in which case this will be set.
92
- def retriever_method(value = nil)
93
- value ? @retriever_method = lookup_retriever_method(value) : @retriever_method ||= Mail::POP3
47
+ def lookup_retriever_method(method)
48
+ case method
49
+ when nil
50
+ Mail::POP3
51
+ when :pop3
52
+ Mail::POP3
53
+ else
54
+ method
55
+ end
94
56
  end
95
57
 
96
58
  def param_encode_language(value = nil)
97
59
  value ? @encode_language = value : @encode_language ||= 'en'
98
60
  end
99
-
100
- private
101
-
102
- def set_settings(klass, host_array = nil, &block)
103
- if host_array
104
- klass.instance.settings do
105
- host host_array[0]
106
- port host_array[1]
107
- end
108
- end
109
- klass.instance.settings(&block)
110
- end
111
-
112
- def lookup_delivery_method(method)
113
- case method
114
- when :smtp || nil
115
- Mail::SMTP
116
- when :sendmail
117
- Mail::Sendmail
118
- when :file
119
- Mail::FileDelivery
120
- when :test
121
- Mail::TestMailer
122
- else
123
- method
124
- end
125
- end
126
61
 
127
- def lookup_retriever_method(method)
128
- case method
129
- when :pop3 || nil
130
- Mail::POP3
131
- # when :imap
132
- # Mail::IMAP
133
- else
134
- method
135
- end
136
- end
137
-
138
62
  end
139
63
 
140
64
  end