actionmailer 1.0.1 → 1.1.1

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

Potentially problematic release.


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

Files changed (37) hide show
  1. data/CHANGELOG +34 -0
  2. data/lib/action_mailer.rb +2 -4
  3. data/lib/action_mailer/adv_attr_accessor.rb +0 -29
  4. data/lib/action_mailer/base.rb +141 -44
  5. data/lib/action_mailer/helpers.rb +3 -3
  6. data/lib/action_mailer/mail_helper.rb +5 -3
  7. data/lib/action_mailer/part.rb +35 -3
  8. data/lib/action_mailer/part_container.rb +18 -1
  9. data/lib/action_mailer/quoting.rb +8 -48
  10. data/lib/action_mailer/vendor/text/format.rb +33 -14
  11. data/lib/action_mailer/vendor/tmail/address.rb +22 -3
  12. data/lib/action_mailer/vendor/tmail/attachments.rb +3 -1
  13. data/lib/action_mailer/vendor/tmail/base64.rb +22 -3
  14. data/lib/action_mailer/vendor/tmail/config.rb +22 -3
  15. data/lib/action_mailer/vendor/tmail/encode.rb +22 -3
  16. data/lib/action_mailer/vendor/tmail/facade.rb +22 -3
  17. data/lib/action_mailer/vendor/tmail/header.rb +27 -6
  18. data/lib/action_mailer/vendor/tmail/info.rb +22 -3
  19. data/lib/action_mailer/vendor/tmail/mail.rb +22 -3
  20. data/lib/action_mailer/vendor/tmail/mailbox.rb +22 -3
  21. data/lib/action_mailer/vendor/tmail/net.rb +22 -3
  22. data/lib/action_mailer/vendor/tmail/obsolete.rb +22 -3
  23. data/lib/action_mailer/vendor/tmail/parser.rb +22 -3
  24. data/lib/action_mailer/vendor/tmail/port.rb +22 -3
  25. data/lib/action_mailer/vendor/tmail/quoting.rb +6 -5
  26. data/lib/action_mailer/vendor/tmail/scanner.rb +22 -3
  27. data/lib/action_mailer/vendor/tmail/scanner_r.rb +22 -3
  28. data/lib/action_mailer/vendor/tmail/stringio.rb +22 -5
  29. data/lib/action_mailer/vendor/tmail/utils.rb +22 -3
  30. data/lib/action_mailer/version.rb +9 -0
  31. data/rakefile +5 -4
  32. data/test/fixtures/raw_email12 +32 -0
  33. data/test/mail_render_test.rb +48 -0
  34. data/test/mail_service_test.rb +62 -5
  35. data/test/quoting_test.rb +48 -0
  36. data/test/tmail_test.rb +17 -0
  37. metadata +8 -3
data/CHANGELOG CHANGED
@@ -1,3 +1,37 @@
1
+ *1.1.1* (October 19th, 2005)
2
+
3
+ * Upgraded to Action Pack 1.10.1
4
+
5
+
6
+ *1.1.0* (October 16th, 2005)
7
+
8
+ * Update and extend documentation (rdoc)
9
+
10
+ * Minero Aoki made TMail available to Rails/ActionMailer under the MIT license (instead of LGPL) [RubyConf '05]
11
+
12
+ * Austin Ziegler made Text::Simple available to Rails/ActionMailer under a MIT-like licens [See rails ML, subject "Text::Format Licence Exception" on Oct 15, 2005]
13
+
14
+ * Fix vendor require paths to prevent files being required twice
15
+
16
+ * Don't add charset to content-type header for a part that contains subparts (for AOL compatibility) #2013 [John Long]
17
+
18
+ * Preserve underscores when unquoting message bodies #1930
19
+
20
+ * Encode multibyte characters correctly #1894
21
+
22
+ * Multipart messages specify a MIME-Version header automatically #2003 [John Long]
23
+
24
+ * Add a unified render method to ActionMailer (delegates to ActionView::Base#render)
25
+
26
+ * Move mailer initialization to a separate (overridable) method, so that subclasses may alter the various defaults #1727
27
+
28
+ * Look at content-location header (if available) to determine filename of attachments #1670
29
+
30
+ * ActionMailer::Base.deliver(email) had been accidentally removed, but was documented in the Rails book #1849
31
+
32
+ * Fix problem with sendmail delivery where headers should be delimited by \n characters instead of \r\n, which confuses some mail readers #1742 [Kent Sibilev]
33
+
34
+
1
35
  *1.0.1* (11 July, 2005)
2
36
 
3
37
  * Bind to Action Pack 1.9.1
@@ -38,7 +38,7 @@ require 'action_mailer/base'
38
38
  require 'action_mailer/helpers'
39
39
  require 'action_mailer/mail_helper'
40
40
  require 'action_mailer/quoting'
41
- require 'action_mailer/vendor/tmail'
41
+ require 'tmail'
42
42
  require 'net/smtp'
43
43
 
44
44
  ActionMailer::Base.class_eval do
@@ -48,6 +48,4 @@ ActionMailer::Base.class_eval do
48
48
  helper MailHelper
49
49
  end
50
50
 
51
- old_verbose, $VERBOSE = $VERBOSE, nil
52
- TMail::Encoder.const_set("MAX_LINE_LEN", 200)
53
- $VERBOSE = old_verbose
51
+ silence_warnings { TMail::Encoder.const_set("MAX_LINE_LEN", 200) }
@@ -25,32 +25,3 @@ module ActionMailer
25
25
  end
26
26
  end
27
27
  end
28
-
29
- module ActionMailer
30
- module AdvAttrAccessor #:nodoc:
31
- def self.append_features(base)
32
- super
33
- base.extend(ClassMethods)
34
- end
35
-
36
- module ClassMethods #:nodoc:
37
- def adv_attr_accessor(*names)
38
- names.each do |name|
39
- define_method("#{name}=") do |value|
40
- instance_variable_set("@#{name}", value)
41
- end
42
-
43
- define_method(name) do |*parameters|
44
- raise ArgumentError, "expected 0 or 1 parameters" unless parameters.length <= 1
45
- if parameters.empty?
46
- instance_variable_get("@#{name}")
47
- else
48
- instance_variable_set("@#{name}", parameters.first)
49
- end
50
- end
51
- end
52
- end
53
-
54
- end
55
- end
56
- end
@@ -4,7 +4,7 @@ require 'action_mailer/part_container'
4
4
  require 'action_mailer/utils'
5
5
  require 'tmail/net'
6
6
 
7
- module ActionMailer #:nodoc:
7
+ module ActionMailer
8
8
  # Usage:
9
9
  #
10
10
  # class ApplicationMailer < ActionMailer::Base
@@ -110,6 +110,9 @@ module ActionMailer #:nodoc:
110
110
  # pick a different charset from inside a method with <tt>@charset</tt>.
111
111
  # * <tt>default_content_type</tt> - The default content type used for main part of the message. Defaults to "text/plain". You
112
112
  # can also pick a different content type from inside a method with <tt>@content_type</tt>.
113
+ # * <tt>default_mime_version</tt> - The default mime version used for the message. Defaults to nil. You
114
+ # can also pick a different value from inside a method with <tt>@mime_version</tt>. When multipart messages are in
115
+ # use, <tt>@mime_version</tt> will be set to "1.0" if it is not set inside a method.
113
116
  # * <tt>default_implicit_parts_order</tt> - When a message is built implicitly (i.e. multiple parts are assemble from templates
114
117
  # which specify the content type in their filenames) this variable controls how the parts are ordered. Defaults to
115
118
  # ["text/html", "text/enriched", "text/plain"]. Items that appear first in the array have higher priority in the mail client
@@ -150,15 +153,107 @@ module ActionMailer #:nodoc:
150
153
 
151
154
  @@default_content_type = "text/plain"
152
155
  cattr_accessor :default_content_type
156
+
157
+ @@default_mime_version = nil
158
+ cattr_accessor :default_mime_version
153
159
 
154
160
  @@default_implicit_parts_order = [ "text/html", "text/enriched", "text/plain" ]
155
161
  cattr_accessor :default_implicit_parts_order
156
162
 
157
- adv_attr_accessor :recipients, :subject, :body, :from, :sent_on, :headers,
158
- :bcc, :cc, :charset, :content_type, :implicit_parts_order,
159
- :template
163
+ # Specify the BCC addresses for the message
164
+ adv_attr_accessor :bcc
165
+
166
+ # Define the body of the message. This is either a Hash (in which case it
167
+ # specifies the variables to pass to the template when it is rendered),
168
+ # or a string, in which case it specifies the actual text of the message.
169
+ adv_attr_accessor :body
170
+
171
+ # Specify the CC addresses for the message.
172
+ adv_attr_accessor :cc
173
+
174
+ # Specify the charset to use for the message. This defaults to the
175
+ # +default_charset+ specified for ActionMailer::Base.
176
+ adv_attr_accessor :charset
177
+
178
+ # Specify the content type for the message. This defaults to <tt>text/plain</tt>
179
+ # in most cases, but can be automatically set in some situations.
180
+ adv_attr_accessor :content_type
181
+
182
+ # Specify the from address for the message.
183
+ adv_attr_accessor :from
184
+
185
+ # Specify additional headers to be added to the message.
186
+ adv_attr_accessor :headers
187
+
188
+ # Specify the order in which parts should be sorted, based on content-type.
189
+ # This defaults to the value for the +default_implicit_parts_order+.
190
+ adv_attr_accessor :implicit_parts_order
191
+
192
+ # Override the mailer name, which defaults to an inflected version of the
193
+ # mailer's class name. If you want to use a template in a non-standard
194
+ # location, you can use this to specify that location.
195
+ adv_attr_accessor :mailer_name
196
+
197
+ # Defaults to "1.0", but may be explicitly given if needed.
198
+ adv_attr_accessor :mime_version
199
+
200
+ # The recipient addresses for the message, either as a string (for a single
201
+ # address) or an array (for multiple addresses).
202
+ adv_attr_accessor :recipients
203
+
204
+ # The date on which the message was sent. If not set (the default), the
205
+ # header will be set by the delivery agent.
206
+ adv_attr_accessor :sent_on
207
+
208
+ # Specify the subject of the message.
209
+ adv_attr_accessor :subject
210
+
211
+ # Specify the template name to use for current message. This is the "base"
212
+ # template name, without the extension or directory, and may be used to
213
+ # have multiple mailer methods share the same template.
214
+ adv_attr_accessor :template
215
+
216
+ # The mail object instance referenced by this mailer.
217
+ attr_reader :mail
218
+
219
+ class << self
220
+ def method_missing(method_symbol, *parameters)#:nodoc:
221
+ case method_symbol.id2name
222
+ when /^create_([_a-z]\w*)/ then new($1, *parameters).mail
223
+ when /^deliver_([_a-z]\w*)/ then new($1, *parameters).deliver!
224
+ when "new" then nil
225
+ else super
226
+ end
227
+ end
228
+
229
+ # Receives a raw email, parses it into an email object, decodes it,
230
+ # instantiates a new mailer, and passes the email object to the mailer
231
+ # object's #receive method. If you want your mailer to be able to
232
+ # process incoming messages, you'll need to implement a #receive
233
+ # method that accepts the email object as a parameter:
234
+ #
235
+ # class MyMailer < ActionMailer::Base
236
+ # def receive(mail)
237
+ # ...
238
+ # end
239
+ # end
240
+ def receive(raw_email)
241
+ logger.info "Received mail:\n #{raw_email}" unless logger.nil?
242
+ mail = TMail::Mail.parse(raw_email)
243
+ mail.base64_decode
244
+ new.receive(mail)
245
+ end
160
246
 
161
- attr_reader :mail
247
+ # Deliver the given mail object directly. This can be used to deliver
248
+ # a preconstructed mail object, like:
249
+ #
250
+ # email = MyMailer.create_some_mail(parameters)
251
+ # email.set_some_obscure_header "frobnicate"
252
+ # MyMailer.deliver(email)
253
+ def deliver(mail)
254
+ new.deliver!(mail)
255
+ end
256
+ end
162
257
 
163
258
  # Instantiate a new mailer object. If +method_name+ is not +nil+, the mailer
164
259
  # will be initialized according to the named method. If not, the mailer will
@@ -171,22 +266,15 @@ module ActionMailer #:nodoc:
171
266
  # Initialize the mailer via the given +method_name+. The body will be
172
267
  # rendered and a new TMail::Mail object created.
173
268
  def create!(method_name, *parameters) #:nodoc:
174
- @bcc = @cc = @from = @recipients = @sent_on = @subject = nil
175
- @charset = @@default_charset.dup
176
- @content_type = @@default_content_type.dup
177
- @implicit_parts_order = @@default_implicit_parts_order.dup
178
- @template = method_name
179
- @parts = []
180
- @headers = {}
181
- @body = {}
182
-
269
+ initialize_defaults(method_name)
183
270
  send(method_name, *parameters)
184
271
 
185
272
  # If an explicit, textual body has not been set, we check assumptions.
186
273
  unless String === @body
187
274
  # First, we look to see if there are any likely templates that match,
188
275
  # which include the content-type in their file name (i.e.,
189
- # "the_template_file.text.html.rhtml", etc.).
276
+ # "the_template_file.text.html.rhtml", etc.). Only do this if parts
277
+ # have not already been specified manually.
190
278
  if @parts.empty?
191
279
  templates = Dir.glob("#{template_path}/#{@template}.*")
192
280
  templates.each do |path|
@@ -198,6 +286,7 @@ module ActionMailer #:nodoc:
198
286
  end
199
287
  unless @parts.empty?
200
288
  @content_type = "multipart/alternative"
289
+ @charset = nil
201
290
  @parts = sort_parts(@parts, @implicit_parts_order)
202
291
  end
203
292
  end
@@ -219,32 +308,58 @@ module ActionMailer #:nodoc:
219
308
  end
220
309
  end
221
310
 
311
+ # If this is a multipart e-mail add the mime_version if it is not
312
+ # already set.
313
+ @mime_version ||= "1.0" if !@parts.empty?
314
+
222
315
  # build the mail object itself
223
316
  @mail = create_mail
224
317
  end
225
318
 
226
- # Delivers the cached TMail::Mail object. If no TMail::Mail object has been
227
- # created (via the #create! method, for instance) this will fail.
228
- def deliver! #:nodoc:
229
- raise "no mail object available for delivery!" unless @mail
319
+ # Delivers a TMail::Mail object. By default, it delivers the cached mail
320
+ # object (from the #create! method). If no cached mail object exists, and
321
+ # no alternate has been given as the parameter, this will fail.
322
+ def deliver!(mail = @mail)
323
+ raise "no mail object available for delivery!" unless mail
230
324
  logger.info "Sent mail:\n #{mail.encoded}" unless logger.nil?
231
325
 
232
326
  begin
233
- send("perform_delivery_#{delivery_method}", @mail) if perform_deliveries
327
+ send("perform_delivery_#{delivery_method}", mail) if perform_deliveries
234
328
  rescue Object => e
235
329
  raise e if raise_delivery_errors
236
330
  end
237
331
 
238
- return @mail
332
+ return mail
239
333
  end
240
334
 
241
335
  private
336
+ # Set up the default values for the various instance variables of this
337
+ # mailer. Subclasses may override this method to provide different
338
+ # defaults.
339
+ def initialize_defaults(method_name)
340
+ @bcc = @cc = @from = @recipients = @sent_on = @subject = nil
341
+ @charset = @@default_charset.dup
342
+ @content_type = @@default_content_type.dup
343
+ @implicit_parts_order = @@default_implicit_parts_order.dup
344
+ @template = method_name
345
+ @mailer_name = Inflector.underscore(self.class.name)
346
+ @parts = []
347
+ @headers = {}
348
+ @body = {}
349
+ @mime_version = @@default_mime_version.dup if @@default_mime_version
350
+ end
351
+
242
352
  def render_message(method_name, body)
243
- initialize_template_class(body).render_file(method_name)
353
+ render :file => method_name, :body => body
244
354
  end
245
-
355
+
356
+ def render(opts)
357
+ body = opts.delete(:body)
358
+ initialize_template_class(body).render(opts)
359
+ end
360
+
246
361
  def template_path
247
- template_root + "/" + Inflector.underscore(self.class.name)
362
+ "#{template_root}/#{mailer_name}"
248
363
  end
249
364
 
250
365
  def initialize_template_class(assigns)
@@ -288,6 +403,7 @@ module ActionMailer #:nodoc:
288
403
  m.bcc = quote_address_if_necessary(bcc, charset) unless bcc.nil?
289
404
  m.cc = quote_address_if_necessary(cc, charset) unless cc.nil?
290
405
 
406
+ m.mime_version = mime_version unless mime_version.nil?
291
407
  m.date = sent_on.to_time rescue sent_on if sent_on
292
408
  headers.each { |k, v| m[k] = v }
293
409
 
@@ -326,7 +442,7 @@ module ActionMailer #:nodoc:
326
442
 
327
443
  def perform_delivery_sendmail(mail)
328
444
  IO.popen("/usr/sbin/sendmail -i -t","w+") do |sm|
329
- sm.print(mail.encoded)
445
+ sm.print(mail.encoded.gsub(/\r/, ''))
330
446
  sm.flush
331
447
  end
332
448
  end
@@ -334,24 +450,5 @@ module ActionMailer #:nodoc:
334
450
  def perform_delivery_test(mail)
335
451
  deliveries << mail
336
452
  end
337
-
338
- class << self
339
- def method_missing(method_symbol, *parameters)#:nodoc:
340
- case method_symbol.id2name
341
- when /^create_([_a-z]\w*)/ then new($1, *parameters).mail
342
- when /^deliver_([_a-z]\w*)/ then new($1, *parameters).deliver!
343
- when "new" then nil
344
- else super
345
- end
346
- end
347
-
348
- def receive(raw_email)
349
- logger.info "Received mail:\n #{raw_email}" unless logger.nil?
350
- mail = TMail::Mail.parse(raw_email)
351
- mail.base64_decode
352
- new.receive(mail)
353
- end
354
-
355
- end
356
453
  end
357
454
  end
@@ -1,6 +1,6 @@
1
- module ActionMailer #:nodoc:
1
+ module ActionMailer
2
2
  module Helpers #:nodoc:
3
- def self.append_features(base)
3
+ def self.append_features(base) #:nodoc:
4
4
  super
5
5
 
6
6
  # Initialize the base module to aggregate its helpers.
@@ -24,7 +24,7 @@ module ActionMailer #:nodoc:
24
24
  end
25
25
  end
26
26
 
27
- module ClassMethods #:nodoc:
27
+ module ClassMethods
28
28
  # Makes all the (instance) methods in the helper module available to templates rendered through this controller.
29
29
  # See ActionView::Helpers (link:classes/ActionView/Helpers.html) for more about making your own helper modules
30
30
  # available to the templates.
@@ -1,6 +1,8 @@
1
- require 'action_mailer/vendor/text/format'
1
+ require 'text/format'
2
2
 
3
- module MailHelper#:nodoc:
3
+ module MailHelper
4
+ # Uses Text::Format to take the text and format it, indented two spaces for
5
+ # each line, and wrapped at 72 columns.
4
6
  def block_format(text)
5
7
  formatted = text.split(/\n\r\n/).collect { |paragraph|
6
8
  Text::Format.new(
@@ -14,4 +16,4 @@ module MailHelper#:nodoc:
14
16
 
15
17
  formatted
16
18
  end
17
- end
19
+ end
@@ -3,13 +3,43 @@ require 'action_mailer/part_container'
3
3
  require 'action_mailer/utils'
4
4
 
5
5
  module ActionMailer
6
- class Part #:nodoc:
6
+ # Represents a subpart of an email message. It shares many similar
7
+ # attributes of ActionMailer::Base. Although you can create parts manually
8
+ # and add them to the #parts list of the mailer, it is easier
9
+ # to use the helper methods in ActionMailer::PartContainer.
10
+ class Part
7
11
  include ActionMailer::AdvAttrAccessor
8
12
  include ActionMailer::PartContainer
9
13
 
10
- adv_attr_accessor :content_type, :content_disposition, :charset, :body
11
- adv_attr_accessor :filename, :transfer_encoding, :headers
14
+ # Represents the body of the part, as a string. This should not be a
15
+ # Hash (like ActionMailer::Base), but if you want a template to be rendered
16
+ # into the body of a subpart you can do it with the mailer's #render method
17
+ # and assign the result here.
18
+ adv_attr_accessor :body
19
+
20
+ # Specify the charset for this subpart. By default, it will be the charset
21
+ # of the containing part or mailer.
22
+ adv_attr_accessor :charset
23
+
24
+ # The content disposition of this part, typically either "inline" or
25
+ # "attachment".
26
+ adv_attr_accessor :content_disposition
27
+
28
+ # The content type of the part.
29
+ adv_attr_accessor :content_type
30
+
31
+ # The filename to use for this subpart (usually for attachments).
32
+ adv_attr_accessor :filename
33
+
34
+ # Accessor for specifying additional headers to include with this part.
35
+ adv_attr_accessor :headers
36
+
37
+ # The transfer encoding to use for this subpart, like "base64" or
38
+ # "quoted-printable".
39
+ adv_attr_accessor :transfer_encoding
12
40
 
41
+ # Create a new part from the given +params+ hash. The valid params keys
42
+ # correspond to the accessors.
13
43
  def initialize(params)
14
44
  @content_type = params[:content_type]
15
45
  @content_disposition = params[:disposition] || "inline"
@@ -21,6 +51,8 @@ module ActionMailer
21
51
  @parts = []
22
52
  end
23
53
 
54
+ # Convert the part to a mail object which can be included in the parts
55
+ # list of another mail object.
24
56
  def to_mail(defaults)
25
57
  part = TMail::Mail.new
26
58