aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--actionmailer/actionmailer.gemspec2
-rw-r--r--actionmailer/lib/action_mailer.rb4
-rw-r--r--actionmailer/lib/action_mailer/adv_attr_accessor.rb2
-rw-r--r--actionmailer/lib/action_mailer/base.rb408
-rw-r--r--actionmailer/lib/action_mailer/delivery_method.rb56
-rw-r--r--actionmailer/lib/action_mailer/delivery_method/file.rb21
-rw-r--r--actionmailer/lib/action_mailer/delivery_method/sendmail.rb22
-rw-r--r--actionmailer/lib/action_mailer/delivery_method/smtp.rb30
-rw-r--r--actionmailer/lib/action_mailer/delivery_method/test.rb12
-rw-r--r--actionmailer/lib/action_mailer/delivery_methods.rb73
-rw-r--r--actionmailer/lib/action_mailer/deprecated_api.rb318
-rw-r--r--actionmailer/lib/action_mailer/deprecated_body.rb46
-rw-r--r--actionmailer/lib/action_mailer/mail_helper.rb5
-rw-r--r--actionmailer/lib/action_mailer/tmail_compat.rb12
-rw-r--r--actionmailer/test/abstract_unit.rb6
-rw-r--r--actionmailer/test/base_test.rb253
-rw-r--r--actionmailer/test/delivery_method_test.rb104
-rw-r--r--actionmailer/test/fixtures/base_mailer/attachment_with_content.erb1
-rw-r--r--actionmailer/test/fixtures/base_mailer/implicit_multipart.html.erb1
-rw-r--r--actionmailer/test/fixtures/base_mailer/implicit_multipart.text.erb1
-rw-r--r--actionmailer/test/fixtures/base_mailer/welcome.erb1
-rw-r--r--actionmailer/test/fixtures/test_mailer/body_ivar.erb2
-rw-r--r--actionmailer/test/mail_layout_test.rb1
-rw-r--r--actionmailer/test/mail_service_test.rb49
-rw-r--r--actionmailer/test/test_helper_test.rb2
-rw-r--r--actionmailer/test/tmail_compat_test.rb2
-rw-r--r--railties/lib/generators/test_unit/mailer/templates/functional_test.rb2
-rw-r--r--railties/lib/rails/configuration.rb2
28 files changed, 835 insertions, 603 deletions
diff --git a/actionmailer/actionmailer.gemspec b/actionmailer/actionmailer.gemspec
index 96549bf29c..576ca97334 100644
--- a/actionmailer/actionmailer.gemspec
+++ b/actionmailer/actionmailer.gemspec
@@ -11,7 +11,7 @@ Gem::Specification.new do |s|
s.homepage = "http://www.rubyonrails.org"
s.add_dependency('actionpack', '= 3.0.pre')
- s.add_dependency('mail', '~> 1.6.0')
+ s.add_dependency('mail', '~> 2.0.3')
s.files = Dir['CHANGELOG', 'README', 'MIT-LICENSE', 'lib/**/*']
s.has_rdoc = true
diff --git a/actionmailer/lib/action_mailer.rb b/actionmailer/lib/action_mailer.rb
index 55ddbb24f4..37c95baea7 100644
--- a/actionmailer/lib/action_mailer.rb
+++ b/actionmailer/lib/action_mailer.rb
@@ -32,8 +32,8 @@ module ActionMailer
autoload :AdvAttrAccessor
autoload :Base
- autoload :DeliveryMethod
- autoload :DeprecatedBody
+ autoload :DeliveryMethods
+ autoload :DeprecatedApi
autoload :MailHelper
autoload :Quoting
autoload :TestCase
diff --git a/actionmailer/lib/action_mailer/adv_attr_accessor.rb b/actionmailer/lib/action_mailer/adv_attr_accessor.rb
index be6b1feca9..91992ed839 100644
--- a/actionmailer/lib/action_mailer/adv_attr_accessor.rb
+++ b/actionmailer/lib/action_mailer/adv_attr_accessor.rb
@@ -1,6 +1,8 @@
module ActionMailer
module AdvAttrAccessor #:nodoc:
def adv_attr_accessor(*names)
+
+ # TODO: ActiveSupport::Deprecation.warn()
names.each do |name|
ivar = "@#{name}"
diff --git a/actionmailer/lib/action_mailer/base.rb b/actionmailer/lib/action_mailer/base.rb
index 356861b591..98e559154a 100644
--- a/actionmailer/lib/action_mailer/base.rb
+++ b/actionmailer/lib/action_mailer/base.rb
@@ -1,4 +1,5 @@
require 'active_support/core_ext/class'
+require "active_support/core_ext/module/delegation"
require 'mail'
require 'action_mailer/tmail_compat'
@@ -252,7 +253,6 @@ module ActionMailer #:nodoc:
# +implicit_parts_order+.
class Base < AbstractController::Base
include Quoting
- extend AdvAttrAccessor
include AbstractController::Logger
include AbstractController::Rendering
@@ -262,7 +262,9 @@ module ActionMailer #:nodoc:
include AbstractController::UrlFor
helper ActionMailer::MailHelper
- include ActionMailer::DeprecatedBody
+ include ActionMailer::DeprecatedApi
+
+ include ActionMailer::DeliveryMethods
private_class_method :new #:nodoc:
@@ -275,14 +277,15 @@ module ActionMailer #:nodoc:
@@deliveries = []
cattr_accessor :deliveries
- @@default_charset = "utf-8"
- cattr_accessor :default_charset
+ extlib_inheritable_accessor :default_charset
+ self.default_charset = "utf-8"
- @@default_content_type = "text/plain"
- cattr_accessor :default_content_type
+ # TODO This should be used when calling render
+ extlib_inheritable_accessor :default_content_type
+ self.default_content_type = "text/plain"
- @@default_mime_version = "1.0"
- cattr_accessor :default_mime_version
+ extlib_inheritable_accessor :default_mime_version
+ self.default_mime_version = "1.0"
# This specifies the order that the parts of a multipart email will be. Usually you put
# text/plain at the top so someone without a MIME capable email reader can read the plain
@@ -290,102 +293,33 @@ module ActionMailer #:nodoc:
#
# Any content type that is not listed here will be inserted in the order you add them to
# the email after the content types you list here.
- @@default_implicit_parts_order = [ "text/plain", "text/enriched", "text/html" ]
- cattr_accessor :default_implicit_parts_order
-
- @@protected_instance_variables = %w(@parts @mail)
- cattr_reader :protected_instance_variables
-
- # Specify the BCC addresses for the message
- adv_attr_accessor :bcc
-
- # Specify the CC addresses for the message.
- adv_attr_accessor :cc
-
- # Specify the charset to use for the message. This defaults to the
- # +default_charset+ specified for ActionMailer::Base.
- adv_attr_accessor :charset
-
- # Specify the content type for the message. This defaults to <tt>text/plain</tt>
- # in most cases, but can be automatically set in some situations.
- adv_attr_accessor :content_type
-
- # Specify the from address for the message.
- adv_attr_accessor :from
-
- # Specify the address (if different than the "from" address) to direct
- # replies to this message.
- adv_attr_accessor :reply_to
-
- # Specify additional headers to be added to the message.
- adv_attr_accessor :headers
-
- # Specify the order in which parts should be sorted, based on content-type.
- # This defaults to the value for the +default_implicit_parts_order+.
- adv_attr_accessor :implicit_parts_order
-
- # Defaults to "1.0", but may be explicitly given if needed.
- adv_attr_accessor :mime_version
-
- # The recipient addresses for the message, either as a string (for a single
- # address) or an array (for multiple addresses).
- adv_attr_accessor :recipients
-
- # The date on which the message was sent. If not set (the default), the
- # header will be set by the delivery agent.
- adv_attr_accessor :sent_on
-
- # Specify the subject of the message.
- adv_attr_accessor :subject
-
- # Specify the template name to use for current message. This is the "base"
- # template name, without the extension or directory, and may be used to
- # have multiple mailer methods share the same template.
- adv_attr_accessor :template
-
- # Override the mailer name, which defaults to an inflected version of the
- # mailer's class name. If you want to use a template in a non-standard
- # location, you can use this to specify that location.
- adv_attr_accessor :mailer_name
-
- # Expose the internal mail
- attr_reader :mail
+ extlib_inheritable_accessor :default_implicit_parts_order
+ self.default_implicit_parts_order = [ "text/plain", "text/enriched", "text/html" ]
+
+ # Expose the internal Mail message
+ attr_reader :message
+
+ def headers(args=nil)
+ if args
+ ActiveSupport::Deprecation.warn "headers(Hash) is deprecated, please do headers[key] = value instead", caller
+ @headers = args
+ else
+ @message
+ end
+ end
- # Alias controller_path to mailer_name so render :partial in views work.
- alias :controller_path :mailer_name
+ def attachments
+ @message.attachments
+ end
class << self
- attr_writer :mailer_name
-
- delegate :settings, :settings=, :to => ActionMailer::DeliveryMethod::File, :prefix => :file
- delegate :settings, :settings=, :to => ActionMailer::DeliveryMethod::Sendmail, :prefix => :sendmail
- delegate :settings, :settings=, :to => ActionMailer::DeliveryMethod::Smtp, :prefix => :smtp
def mailer_name
@mailer_name ||= name.underscore
end
- alias :controller_path :mailer_name
-
- def delivery_method=(method_name)
- @delivery_method = ActionMailer::DeliveryMethod.lookup_method(method_name)
- end
-
- def respond_to?(method_symbol, include_private = false) #:nodoc:
- matches_dynamic_method?(method_symbol) || super
- end
+ attr_writer :mailer_name
- def method_missing(method_symbol, *parameters) #:nodoc:
- if match = matches_dynamic_method?(method_symbol)
- case match[1]
- when 'create' then new(match[2], *parameters).mail
- when 'deliver' then new(match[2], *parameters).deliver!
- when 'new' then nil
- else super
- end
- else
- super
- end
- end
+ alias :controller_path :mailer_name
# Receives a raw email, parses it into an email object, decodes it,
# instantiates a new mailer, and passes the email object to the mailer
@@ -413,7 +347,26 @@ module ActionMailer #:nodoc:
# email.set_some_obscure_header "frobnicate"
# MyMailer.deliver(email)
def deliver(mail)
- new.deliver!(mail)
+ raise "no mail object available for delivery!" unless mail
+
+ ActiveSupport::Notifications.instrument("action_mailer.deliver", :mailer => self.name) do |payload|
+ self.set_payload_for_mail(payload, mail)
+
+ mail.delivery_method delivery_methods[delivery_method],
+ delivery_settings[delivery_method]
+
+ begin
+ # TODO Move me to the instance
+ if @@perform_deliveries
+ mail.deliver!
+ self.deliveries << mail
+ end
+ rescue Exception => e # Net::SMTP errors or sendmail pipe errors
+ raise e if raise_delivery_errors
+ end
+ end
+
+ mail
end
def template_root
@@ -435,61 +388,73 @@ module ActionMailer #:nodoc:
payload[:date] = mail.date
payload[:mail] = mail.encoded
end
+ end
- private
-
- def matches_dynamic_method?(method_name) #:nodoc:
- method_name = method_name.to_s
- /^(create|deliver)_([_a-z]\w*)/.match(method_name) || /^(new)$/.match(method_name)
+ # TODO Add new delivery method goodness
+ def mail(headers = {})
+ # Guard flag to prevent both the old and the new API from firing
+ # Should be removed when old API is deprecated
+ @mail_was_called = true
+ m = @message
+
+ # Get default subject from I18n if none is set
+ headers[:subject] ||= I18n.t(:subject, :scope => [:actionmailer, mailer_name, action_name],
+ :default => action_name.humanize)
+
+ # Give preference to headers and fallbacks to the ones set in mail
+ content_type = headers[:content_type] || m.content_type
+ charset = headers[:charset] || m.charset || self.class.default_charset.dup
+ mime_version = headers[:mime_version] || m.mime_version || self.class.default_mime_version.dup
+
+ m.subject ||= quote_if_necessary(headers[:subject], charset) if headers[:subject]
+ m.to ||= quote_address_if_necessary(headers[:to], charset) if headers[:to]
+ m.from ||= quote_address_if_necessary(headers[:from], charset) if headers[:from]
+ m.cc ||= quote_address_if_necessary(headers[:cc], charset) if headers[:cc]
+ m.bcc ||= quote_address_if_necessary(headers[:bcc], charset) if headers[:bcc]
+ m.reply_to ||= quote_address_if_necessary(headers[:reply_to], charset) if headers[:reply_to]
+ m.date ||= headers[:date] if headers[:date]
+
+ if block_given?
+ # Do something
+ else
+ # TODO Ensure that we don't need to pass I18n.locale as detail
+ templates = self.class.template_root.find_all(action_name, {}, mailer_name)
+
+ if templates.size == 1 && !m.has_attachments?
+ content_type ||= templates[0].mime_type.to_s
+ m.body = render_to_body(:_template => templates[0])
+ elsif templates.size > 1 && m.has_attachments?
+ container = Mail::Part.new
+ container.content_type = "multipart/alternate"
+ templates.each { |t| insert_part(container, t, charset) }
+ m.add_part(container)
+ else
+ templates.each { |t| insert_part(m, t, charset) }
end
- end
- # Configure delivery method. Check ActionMailer::DeliveryMethod for more
- # instructions.
- superclass_delegating_reader :delivery_method
- self.delivery_method = :smtp
-
- # Add a part to a multipart message, with the given content-type. The
- # part itself is yielded to the block so that other properties (charset,
- # body, headers, etc.) can be set on it.
- def part(params)
- params = {:content_type => params} if String === params
-
- if custom_headers = params.delete(:headers)
- ActiveSupport::Deprecation.warn('Passing custom headers with :headers => {} is deprecated. ' <<
- 'Please just pass in custom headers directly.', caller[0,10])
- params.merge!(custom_headers)
+ content_type ||= (m.has_attachments? ? "multipart/mixed" : "multipart/alternate")
end
- part = Mail::Part.new(params)
- yield part if block_given?
- @parts << part
- end
-
- # Add an attachment to a multipart message. This is simply a part with the
- # content-disposition set to "attachment".
- def attachment(params, &block)
- super # Run deprecation hooks
+ # Check if the content_type was not overwriten along the way and if so,
+ # fallback to default.
+ m.content_type = content_type || self.class.default_content_type.dup
+ m.charset = charset
+ m.mime_version = mime_version
- params = { :content_type => params } if String === params
- params = { :content_disposition => "attachment",
- :content_transfer_encoding => "base64" }.merge(params)
+ unless m.parts.empty?
+ m.body.set_sort_order(headers[:parts_order] || self.class.default_implicit_parts_order.dup)
+ m.body.sort_parts!
+ end
- part(params, &block)
+ m
end
- # Allow you to set assigns for your template:
- #
- # body :greetings => "Hi"
- #
- # Will make @greetings available in the template to be rendered.
- def body(object=nil)
- returning(super) do # Run deprecation hooks
- if object.is_a?(Hash)
- @assigns_set = true
- object.each { |k, v| instance_variable_set(:"@#{k}", v) }
- end
- end
+ def insert_part(container, template, charset)
+ part = Mail::Part.new
+ part.content_type = template.mime_type.to_s
+ part.charset = charset
+ part.body = render_to_body(:_template => template)
+ container.add_part(part)
end
# Instantiate a new mailer object. If +method_name+ is not +nil+, the mailer
@@ -498,167 +463,16 @@ module ActionMailer #:nodoc:
# method, for instance).
def initialize(method_name=nil, *args)
super()
+ @message = Mail.new
process(method_name, *args) if method_name
end
- # Process the mailer via the given +method_name+. The body will be
- # rendered and a new Mail object created.
- def process(method_name, *args)
- initialize_defaults(method_name)
- super
-
- # Create e-mail parts
- create_parts
-
- # Set the subject if not set yet
- @subject ||= I18n.t(:subject, :scope => [:actionmailer, mailer_name, method_name],
- :default => method_name.humanize)
-
- # Build the mail object itself
- create_mail
- end
-
# Delivers a Mail object. By default, it delivers the cached mail
# object (from the <tt>create!</tt> method). If no cached mail object exists, and
# no alternate has been given as the parameter, this will fail.
- def deliver!(mail = @mail)
- raise "no mail object available for delivery!" unless mail
-
- ActiveSupport::Notifications.instrument("action_mailer.deliver",
- :template => template, :mailer => self.class.name) do |payload|
-
- self.class.set_payload_for_mail(payload, mail)
-
- begin
- self.delivery_method.perform_delivery(mail) if perform_deliveries
- rescue Exception => e # Net::SMTP errors or sendmail pipe errors
- raise e if raise_delivery_errors
- end
- end
-
- mail
+ def deliver!(mail = @message)
+ self.class.deliver(mail)
end
- private
-
- # Render a message but does not set it as mail body. Useful for rendering
- # data for part and attachments.
- #
- # Examples:
- #
- # render_message "special_message"
- # render_message :template => "special_message"
- # render_message :inline => "<%= 'Hi!' %>"
- def render_message(object)
- case object
- when String
- render_to_body(:template => object)
- else
- render_to_body(object)
- end
- end
-
- # Set up the default values for the various instance variables of this
- # mailer. Subclasses may override this method to provide different
- # defaults.
- def initialize_defaults(method_name) #:nodoc:
- @charset ||= @@default_charset.dup
- @content_type ||= @@default_content_type.dup
- @implicit_parts_order ||= @@default_implicit_parts_order.dup
- @mime_version ||= @@default_mime_version.dup if @@default_mime_version
-
- @mailer_name ||= self.class.mailer_name.dup
- @template ||= method_name
-
- @parts ||= []
- @headers ||= {}
- @sent_on ||= Time.now
-
- super # Run deprecation hooks
- end
-
- def create_parts #:nodoc:
- super # Run deprecation hooks
-
- if String === response_body
- @parts.unshift create_inline_part(response_body)
- else
- self.class.template_root.find_all(@template, {}, @mailer_name).each do |template|
- @parts << create_inline_part(render_to_body(:_template => template), template.mime_type)
- end
-
- if @parts.size > 1
- @content_type = "multipart/alternative" if @content_type !~ /^multipart/
- end
-
- # If this is a multipart e-mail add the mime_version if it is not
- # already set.
- @mime_version ||= "1.0" if !@parts.empty?
- end
- end
-
- def create_inline_part(body, mime_type=nil) #:nodoc:
- ct = mime_type || "text/plain"
- main_type, sub_type = split_content_type(ct.to_s)
-
- Mail::Part.new(
- :content_type => [main_type, sub_type, {:charset => charset}],
- :content_disposition => "inline",
- :body => body
- )
- end
-
- def create_mail #:nodoc:
- m = Mail.new
-
- m.subject, = quote_any_if_necessary(charset, subject)
- m.to, m.from = quote_any_address_if_necessary(charset, recipients, from)
- m.bcc = quote_address_if_necessary(bcc, charset) unless bcc.nil?
- m.cc = quote_address_if_necessary(cc, charset) unless cc.nil?
- m.reply_to = quote_address_if_necessary(reply_to, charset) unless reply_to.nil?
- m.mime_version = mime_version unless mime_version.nil?
- m.date = sent_on.to_time rescue sent_on if sent_on
-
- headers.each { |k, v| m[k] = v }
-
- real_content_type, ctype_attrs = parse_content_type
- main_type, sub_type = split_content_type(real_content_type)
-
- if @parts.size == 1 && @parts.first.parts.empty?
- m.content_type([main_type, sub_type, ctype_attrs])
- m.body = @parts.first.body.encoded
- else
- @parts.each do |p|
- m.add_part(p)
- end
-
- m.body.set_sort_order(@implicit_parts_order)
- m.body.sort_parts!
-
- if real_content_type =~ /multipart/
- ctype_attrs.delete "charset"
- m.content_type([main_type, sub_type, ctype_attrs])
- end
- end
-
- m.content_transfer_encoding = '8bit' unless m.body.only_us_ascii?
-
- @mail = m
- end
-
- def split_content_type(ct) #:nodoc:
- ct.to_s.split("/")
- end
-
- def parse_content_type(defaults=nil) #:nodoc:
- if @content_type.blank?
- [ nil, {} ]
- else
- ctype, *attrs = @content_type.split(/;\s*/)
- attrs = attrs.inject({}) { |h,s| k,v = s.split(/\=/, 2); h[k] = v; h }
- [ctype, {"charset" => @charset}.merge(attrs)]
- end
- end
-
end
end
diff --git a/actionmailer/lib/action_mailer/delivery_method.rb b/actionmailer/lib/action_mailer/delivery_method.rb
deleted file mode 100644
index 4f7d3afc3c..0000000000
--- a/actionmailer/lib/action_mailer/delivery_method.rb
+++ /dev/null
@@ -1,56 +0,0 @@
-require 'active_support/core_ext/class'
-
-module ActionMailer
- module DeliveryMethod
- autoload :File, 'action_mailer/delivery_method/file'
- autoload :Sendmail, 'action_mailer/delivery_method/sendmail'
- autoload :Smtp, 'action_mailer/delivery_method/smtp'
- autoload :Test, 'action_mailer/delivery_method/test'
-
- # Creates a new DeliveryMethod object according to the given options.
- #
- # If no arguments are passed to this method, then a new
- # ActionMailer::DeliveryMethod::Stmp object will be returned.
- #
- # If you pass a Symbol as the first argument, then a corresponding
- # delivery method class under the ActionMailer::DeliveryMethod namespace
- # will be created.
- # For example:
- #
- # ActionMailer::DeliveryMethod.lookup_method(:sendmail)
- # # => returns a new ActionMailer::DeliveryMethod::Sendmail object
- #
- # If the first argument is not a Symbol, then it will simply be returned:
- #
- # ActionMailer::DeliveryMethod.lookup_method(MyOwnDeliveryMethod.new)
- # # => returns MyOwnDeliveryMethod.new
- def self.lookup_method(delivery_method)
- case delivery_method
- when Symbol
- method_name = delivery_method.to_s.camelize
- method_class = ActionMailer::DeliveryMethod.const_get(method_name)
- method_class.new
- when nil # default
- Smtp.new
- else
- delivery_method
- end
- end
-
- # An abstract delivery method class. There are multiple delivery method classes.
- # See the classes under the ActionMailer::DeliveryMethod, e.g.
- # ActionMailer::DeliveryMethod::Smtp.
- # Smtp is the default delivery method for production
- # while Test is used in testing.
- #
- # each delivery method exposes just one method
- #
- # delivery_method = ActionMailer::DeliveryMethod::Smtp.new
- # delivery_method.perform_delivery(mail) # send the mail via smtp
- #
- class Method
- superclass_delegating_accessor :settings
- self.settings = {}
- end
- end
-end
diff --git a/actionmailer/lib/action_mailer/delivery_method/file.rb b/actionmailer/lib/action_mailer/delivery_method/file.rb
deleted file mode 100644
index 571e32df49..0000000000
--- a/actionmailer/lib/action_mailer/delivery_method/file.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-require 'tmpdir'
-
-module ActionMailer
- module DeliveryMethod
-
- # A delivery method implementation which writes all mails to a file.
- class File < Method
- self.settings = {
- :location => defined?(Rails.root) ? "#{Rails.root}/tmp/mails" : "#{Dir.tmpdir}/mails"
- }
-
- def perform_delivery(mail)
- FileUtils.mkdir_p settings[:location]
-
- mail.destinations.uniq.each do |to|
- ::File.open(::File.join(settings[:location], to), 'a') { |f| f.write(mail) }
- end
- end
- end
- end
-end
diff --git a/actionmailer/lib/action_mailer/delivery_method/sendmail.rb b/actionmailer/lib/action_mailer/delivery_method/sendmail.rb
deleted file mode 100644
index db55af79f1..0000000000
--- a/actionmailer/lib/action_mailer/delivery_method/sendmail.rb
+++ /dev/null
@@ -1,22 +0,0 @@
-module ActionMailer
- module DeliveryMethod
-
- # A delivery method implementation which sends via sendmail.
- class Sendmail < Method
- self.settings = {
- :location => '/usr/sbin/sendmail',
- :arguments => '-i -t'
- }
-
- def perform_delivery(mail)
- sendmail_args = settings[:arguments]
- sendmail_args += " -f \"#{mail['return-path']}\"" if mail['return-path']
- IO.popen("#{settings[:location]} #{sendmail_args}","w+") do |sm|
- sm.print(mail.encoded.gsub(/\r/, ''))
- sm.flush
- end
- end
- end
-
- end
-end
diff --git a/actionmailer/lib/action_mailer/delivery_method/smtp.rb b/actionmailer/lib/action_mailer/delivery_method/smtp.rb
deleted file mode 100644
index af30c498b5..0000000000
--- a/actionmailer/lib/action_mailer/delivery_method/smtp.rb
+++ /dev/null
@@ -1,30 +0,0 @@
-require 'net/smtp'
-
-module ActionMailer
- module DeliveryMethod
- # A delivery method implementation which sends via smtp.
- class Smtp < Method
- self.settings = {
- :address => "localhost",
- :port => 25,
- :domain => 'localhost.localdomain',
- :user_name => nil,
- :password => nil,
- :authentication => nil,
- :enable_starttls_auto => true,
- }
-
- def perform_delivery(mail)
- destinations = mail.destinations
- sender = (mail['return-path'] && mail['return-path'].address) || mail['from']
-
- smtp = Net::SMTP.new(settings[:address], settings[:port])
- smtp.enable_starttls_auto if settings[:enable_starttls_auto] && smtp.respond_to?(:enable_starttls_auto)
- smtp.start(settings[:domain], settings[:user_name], settings[:password],
- settings[:authentication]) do |smtp|
- smtp.sendmail(mail.encoded, sender, destinations)
- end
- end
- end
- end
-end
diff --git a/actionmailer/lib/action_mailer/delivery_method/test.rb b/actionmailer/lib/action_mailer/delivery_method/test.rb
deleted file mode 100644
index 6e3239d52a..0000000000
--- a/actionmailer/lib/action_mailer/delivery_method/test.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-module ActionMailer
- module DeliveryMethod
-
- # A delivery method implementation designed for testing, which just appends each record to the :deliveries array
- class Test < Method
- def perform_delivery(mail)
- ActionMailer::Base.deliveries << mail
- end
- end
-
- end
-end
diff --git a/actionmailer/lib/action_mailer/delivery_methods.rb b/actionmailer/lib/action_mailer/delivery_methods.rb
new file mode 100644
index 0000000000..5883e446f2
--- /dev/null
+++ b/actionmailer/lib/action_mailer/delivery_methods.rb
@@ -0,0 +1,73 @@
+module ActionMailer
+ # This modules makes a DSL for adding delivery methods to ActionMailer
+ module DeliveryMethods
+ extend ActiveSupport::Concern
+
+ included do
+ add_delivery_method :smtp, Mail::SMTP,
+ :address => "localhost",
+ :port => 25,
+ :domain => 'localhost.localdomain',
+ :user_name => nil,
+ :password => nil,
+ :authentication => nil,
+ :enable_starttls_auto => true
+
+ add_delivery_method :file, Mail::FileDelivery,
+ :location => defined?(Rails.root) ? "#{Rails.root}/tmp/mails" : "#{Dir.tmpdir}/mails"
+
+ add_delivery_method :sendmail, Mail::Sendmail,
+ :location => '/usr/sbin/sendmail',
+ :arguments => '-i -t'
+
+ add_delivery_method :test, Mail::TestMailer
+
+ superclass_delegating_reader :delivery_method
+ self.delivery_method = :smtp
+ end
+
+ module ClassMethods
+ # TODO Make me class inheritable
+ def delivery_settings
+ @@delivery_settings ||= Hash.new { |h,k| h[k] = {} }
+ end
+
+ def delivery_methods
+ @@delivery_methods ||= {}
+ end
+
+ def delivery_method=(method)
+ raise ArgumentError, "Unknown delivery method #{method.inspect}" unless delivery_methods[method]
+ @delivery_method = method
+ end
+
+ def add_delivery_method(symbol, klass, default_options={})
+ self.delivery_methods[symbol] = klass
+ self.delivery_settings[symbol] = default_options
+ end
+
+ def respond_to?(method_symbol, include_private = false) #:nodoc:
+ matches_settings_method?(method_symbol) || super
+ end
+
+ protected
+
+ # TODO Get rid of this method missing magic
+ def method_missing(method_symbol, *parameters) #:nodoc:
+ if match = matches_settings_method?(method_symbol)
+ if match[2]
+ delivery_settings[match[1].to_sym] = parameters[0]
+ else
+ delivery_settings[match[1].to_sym]
+ end
+ else
+ super
+ end
+ end
+
+ def matches_settings_method?(method_name) #:nodoc:
+ /(#{delivery_methods.keys.join('|')})_settings(=)?$/.match(method_name.to_s)
+ end
+ end
+ end
+end \ No newline at end of file
diff --git a/actionmailer/lib/action_mailer/deprecated_api.rb b/actionmailer/lib/action_mailer/deprecated_api.rb
new file mode 100644
index 0000000000..b2bb6a64aa
--- /dev/null
+++ b/actionmailer/lib/action_mailer/deprecated_api.rb
@@ -0,0 +1,318 @@
+module ActionMailer
+ # TODO Remove this module all together in Rails 3.1. Ensure that super
+ # hooks in ActionMailer::Base are removed as well.
+ #
+ # Moved here to allow us to add the new Mail API
+ module DeprecatedApi #:nodoc:
+ extend ActiveSupport::Concern
+
+ included do
+ extend ActionMailer::AdvAttrAccessor
+
+ @@protected_instance_variables = %w(@parts)
+ cattr_reader :protected_instance_variables
+
+ # Specify the BCC addresses for the message
+ adv_attr_accessor :bcc
+
+ # Specify the CC addresses for the message.
+ adv_attr_accessor :cc
+
+ # Specify the charset to use for the message. This defaults to the
+ # +default_charset+ specified for ActionMailer::Base.
+ adv_attr_accessor :charset
+
+ # Specify the content type for the message. This defaults to <tt>text/plain</tt>
+ # in most cases, but can be automatically set in some situations.
+ adv_attr_accessor :content_type
+
+ # Specify the from address for the message.
+ adv_attr_accessor :from
+
+ # Specify the address (if different than the "from" address) to direct
+ # replies to this message.
+ adv_attr_accessor :reply_to
+
+ # Specify additional headers to be added to the message.
+ adv_attr_accessor :headers
+
+ # Specify the order in which parts should be sorted, based on content-type.
+ # This defaults to the value for the +default_implicit_parts_order+.
+ adv_attr_accessor :implicit_parts_order
+
+ # Defaults to "1.0", but may be explicitly given if needed.
+ adv_attr_accessor :mime_version
+
+ # The recipient addresses for the message, either as a string (for a single
+ # address) or an array (for multiple addresses).
+ adv_attr_accessor :recipients
+
+ # The date on which the message was sent. If not set (the default), the
+ # header will be set by the delivery agent.
+ adv_attr_accessor :sent_on
+
+ # Specify the subject of the message.
+ adv_attr_accessor :subject
+
+ # Specify the template name to use for current message. This is the "base"
+ # template name, without the extension or directory, and may be used to
+ # have multiple mailer methods share the same template.
+ adv_attr_accessor :template
+
+ # Override the mailer name, which defaults to an inflected version of the
+ # mailer's class name. If you want to use a template in a non-standard
+ # location, you can use this to specify that location.
+ adv_attr_accessor :mailer_name
+
+ # Define the body of the message. This is either a Hash (in which case it
+ # specifies the variables to pass to the template when it is rendered),
+ # or a string, in which case it specifies the actual text of the message.
+ adv_attr_accessor :body
+
+ # Alias controller_path to mailer_name so render :partial in views work.
+ alias :controller_path :mailer_name
+ end
+
+ module ClassMethods
+ def respond_to?(method_symbol, include_private = false) #:nodoc:
+ matches_dynamic_method?(method_symbol) || super
+ end
+
+ def method_missing(method_symbol, *parameters) #:nodoc:
+ if match = matches_dynamic_method?(method_symbol)
+ case match[1]
+ when 'create' then new(match[2], *parameters).message
+ when 'deliver' then new(match[2], *parameters).deliver!
+ when 'new' then nil
+ else super
+ end
+ else
+ super
+ end
+ end
+
+ private
+
+ def matches_dynamic_method?(method_name) #:nodoc:
+ method_name = method_name.to_s
+ /^(create|deliver)_([_a-z]\w*)/.match(method_name) || /^(new)$/.match(method_name)
+ end
+ end
+
+ def initialize(*)
+ super()
+ @mail_was_called = false
+ end
+
+ def render(*args)
+ options = args.last.is_a?(Hash) ? args.last : {}
+ if options[:body]
+ ActiveSupport::Deprecation.warn(':body in render deprecated. Please call body ' <<
+ 'with a hash instead', caller[0,1])
+
+ body options.delete(:body)
+ end
+
+ super
+ end
+
+ def process(method_name, *args)
+ initialize_defaults(method_name)
+ super
+ unless @mail_was_called
+ create_parts
+ create_mail
+ end
+ @message
+ end
+
+ # Add a part to a multipart message, with the given content-type. The
+ # part itself is yielded to the block so that other properties (charset,
+ # body, headers, etc.) can be set on it.
+ def part(params)
+ params = {:content_type => params} if String === params
+
+ if custom_headers = params.delete(:headers)
+ params.merge!(custom_headers)
+ end
+
+ part = Mail::Part.new(params)
+
+ yield part if block_given?
+ @parts << part
+ end
+
+ # Add an attachment to a multipart message. This is simply a part with the
+ # content-disposition set to "attachment".
+ def attachment(params, &block)
+ params = { :content_type => params } if String === params
+
+ params[:content] ||= params.delete(:data) || params.delete(:body)
+
+ if params[:filename]
+ params = normalize_file_hash(params)
+ else
+ params = normalize_nonfile_hash(params)
+ end
+
+ part(params, &block)
+ end
+
+ # Render a message but does not set it as mail body. Useful for rendering
+ # data for part and attachments.
+ #
+ # Examples:
+ #
+ # render_message "special_message"
+ # render_message :template => "special_message"
+ # render_message :inline => "<%= 'Hi!' %>"
+ #
+ def render_message(object)
+ case object
+ when String
+ render_to_body(:template => object)
+ else
+ render_to_body(object)
+ end
+ end
+
+ private
+
+ def normalize_nonfile_hash(params)
+ content_disposition = "attachment;"
+
+ mime_type = params.delete(:mime_type)
+
+ if content_type = params.delete(:content_type)
+ content_type = "#{mime_type || content_type};"
+ end
+
+ params[:body] = params.delete(:data) if params[:data]
+
+ { :content_type => content_type,
+ :content_disposition => content_disposition }.merge(params)
+ end
+
+ def normalize_file_hash(params)
+ filename = File.basename(params.delete(:filename))
+ content_disposition = "attachment; filename=\"#{File.basename(filename)}\""
+
+ mime_type = params.delete(:mime_type)
+
+ if (content_type = params.delete(:content_type)) && (content_type !~ /filename=/)
+ content_type = "#{mime_type || content_type}; filename=\"#{filename}\""
+ end
+
+ params[:body] = params.delete(:data) if params[:data]
+
+ { :content_type => content_type,
+ :content_disposition => content_disposition }.merge(params)
+ end
+
+ def create_mail #:nodoc:
+ m = @message
+
+ m.subject, = quote_any_if_necessary(charset, subject)
+ m.to, m.from = quote_any_address_if_necessary(charset, recipients, from)
+ m.bcc = quote_address_if_necessary(bcc, charset) unless bcc.nil?
+ m.cc = quote_address_if_necessary(cc, charset) unless cc.nil?
+ m.reply_to = quote_address_if_necessary(reply_to, charset) unless reply_to.nil?
+ m.mime_version = mime_version unless mime_version.nil?
+ m.date = sent_on.to_time rescue sent_on if sent_on
+
+ @headers.each { |k, v| m[k] = v }
+
+ real_content_type, ctype_attrs = parse_content_type
+ main_type, sub_type = split_content_type(real_content_type)
+
+ if @parts.size == 1 && @parts.first.parts.empty?
+ m.content_type([main_type, sub_type, ctype_attrs])
+ m.body = @parts.first.body.encoded
+ else
+ @parts.each do |p|
+ m.add_part(p)
+ end
+
+ m.body.set_sort_order(@implicit_parts_order)
+ m.body.sort_parts!
+
+ if real_content_type =~ /multipart/
+ ctype_attrs.delete "charset"
+ m.content_type([main_type, sub_type, ctype_attrs])
+ end
+ end
+
+ m.content_transfer_encoding = '8bit' unless m.body.only_us_ascii?
+
+ @message
+ end
+
+ # Set up the default values for the various instance variables of this
+ # mailer. Subclasses may override this method to provide different
+ # defaults.
+ def initialize_defaults(method_name) #:nodoc:
+ @charset ||= self.class.default_charset.dup
+ @content_type ||= self.class.default_content_type.dup
+ @implicit_parts_order ||= self.class.default_implicit_parts_order.dup
+ @mime_version ||= self.class.default_mime_version.dup if self.class.default_mime_version
+
+ @mailer_name ||= self.class.mailer_name.dup
+ @template ||= method_name
+
+ @parts ||= []
+ @headers ||= {}
+ @sent_on ||= Time.now
+ @body ||= {}
+ end
+
+ def create_parts #:nodoc:
+ if String === @body
+ self.response_body = @body
+ elsif @body.is_a?(Hash) && !@body.empty?
+ @body.each { |k, v| instance_variable_set(:"@#{k}", v) }
+ end
+
+ if String === response_body
+ @parts.unshift create_inline_part(response_body)
+ else
+ self.class.template_root.find_all(@template, {}, @mailer_name).each do |template|
+ @parts << create_inline_part(render_to_body(:_template => template), template.mime_type)
+ end
+
+ if @parts.size > 1
+ @content_type = "multipart/alternative" if @content_type !~ /^multipart/
+ end
+
+ # If this is a multipart e-mail add the mime_version if it is not
+ # already set.
+ @mime_version ||= "1.0" if !@parts.empty?
+ end
+ end
+
+ def create_inline_part(body, mime_type=nil) #:nodoc:
+ ct = mime_type || "text/plain"
+ main_type, sub_type = split_content_type(ct.to_s)
+
+ Mail::Part.new(
+ :content_type => [main_type, sub_type, {:charset => charset}],
+ :content_disposition => "inline",
+ :body => body
+ )
+ end
+
+ def split_content_type(ct) #:nodoc:
+ ct.to_s.split("/")
+ end
+
+ def parse_content_type(defaults=nil) #:nodoc:
+ if @content_type.blank?
+ [ nil, {} ]
+ else
+ ctype, *attrs = @content_type.split(/;\s*/)
+ attrs = attrs.inject({}) { |h,s| k,v = s.split(/\=/, 2); h[k] = v; h }
+ [ctype, {"charset" => @charset}.merge(attrs)]
+ end
+ end
+
+ end
+end \ No newline at end of file
diff --git a/actionmailer/lib/action_mailer/deprecated_body.rb b/actionmailer/lib/action_mailer/deprecated_body.rb
deleted file mode 100644
index 5379b33a54..0000000000
--- a/actionmailer/lib/action_mailer/deprecated_body.rb
+++ /dev/null
@@ -1,46 +0,0 @@
-module ActionMailer
- # TODO Remove this module all together in a next release. Ensure that super
- # hooks and @assigns_set in ActionMailer::Base are removed as well.
- module DeprecatedBody
- extend ActionMailer::AdvAttrAccessor
-
- # Define the body of the message. This is either a Hash (in which case it
- # specifies the variables to pass to the template when it is rendered),
- # or a string, in which case it specifies the actual text of the message.
- adv_attr_accessor :body
-
- def initialize_defaults(method_name)
- @body ||= {}
- end
-
- def attachment(params, &block)
- if params[:body]
- ActiveSupport::Deprecation.warn('attachment :body => "string" is deprecated. To set the body of an attachment ' <<
- 'please use :data instead, like attachment :data => "string"', caller[0,10])
- params[:data] = params.delete(:body)
- end
- end
-
- def create_parts
- if String === @body && !defined?(@assigns_set)
- ActiveSupport::Deprecation.warn('body(String) is deprecated. To set the body with a text ' <<
- 'call render(:text => "body")', caller[0,10])
- self.response_body = @body
- elsif self.response_body
- @body = self.response_body
- end
- end
-
- def render(*args)
- options = args.last.is_a?(Hash) ? args.last : {}
- if options[:body]
- ActiveSupport::Deprecation.warn(':body in render deprecated. Please call body ' <<
- 'with a hash instead', caller[0,1])
-
- body options.delete(:body)
- end
-
- super
- end
- end
-end
diff --git a/actionmailer/lib/action_mailer/mail_helper.rb b/actionmailer/lib/action_mailer/mail_helper.rb
index 701dc34431..45ba6f0714 100644
--- a/actionmailer/lib/action_mailer/mail_helper.rb
+++ b/actionmailer/lib/action_mailer/mail_helper.rb
@@ -20,5 +20,10 @@ module ActionMailer
def mailer #:nodoc:
@controller
end
+
+ # Access the message instance.
+ def message #:nodoc:
+ @message
+ end
end
end
diff --git a/actionmailer/lib/action_mailer/tmail_compat.rb b/actionmailer/lib/action_mailer/tmail_compat.rb
index 2fd25ff145..d78332c135 100644
--- a/actionmailer/lib/action_mailer/tmail_compat.rb
+++ b/actionmailer/lib/action_mailer/tmail_compat.rb
@@ -2,19 +2,27 @@ module Mail
class Message
def set_content_type(*args)
- STDERR.puts("Message#set_content_type is deprecated, please just call Message#content_type with the same arguments.\n#{caller}")
+ ActiveSupport::Deprecation.warn('Message#set_content_type is deprecated, please just call ' <<
+ 'Message#content_type with the same arguments', caller[0,10])
content_type(*args)
end
alias :old_transfer_encoding :transfer_encoding
def transfer_encoding(value = nil)
if value
- STDERR.puts("Message#transfer_encoding is deprecated, please call Message#content_transfer_encoding with the same arguments.\n#{caller}")
+ ActiveSupport::Deprecation.warn('Message#transfer_encoding is deprecated, please call ' <<
+ 'Message#content_transfer_encoding with the same arguments', caller[0,10])
content_transfer_encoding(value)
else
old_transfer_encoding
end
end
+ def original_filename
+ ActiveSupport::Deprecation.warn('Message#original_filename is deprecated, ' <<
+ 'please call Message#filename', caller[0,10])
+ filename
+ end
+
end
end \ No newline at end of file
diff --git a/actionmailer/test/abstract_unit.rb b/actionmailer/test/abstract_unit.rb
index 50b8a53006..1fc5ab85e0 100644
--- a/actionmailer/test/abstract_unit.rb
+++ b/actionmailer/test/abstract_unit.rb
@@ -26,6 +26,7 @@ FIXTURE_LOAD_PATH = File.join(File.dirname(__FILE__), 'fixtures')
ActionMailer::Base.template_root = FIXTURE_LOAD_PATH
class MockSMTP
+
def self.deliveries
@@deliveries
end
@@ -41,6 +42,7 @@ class MockSMTP
def start(*args)
yield self
end
+
end
class Net::SMTP
@@ -57,9 +59,9 @@ rescue LoadError
$stderr.puts "Skipping #{test_name} tests. `gem install #{gem_name}` and try again."
end
-def set_delivery_method(delivery_method)
+def set_delivery_method(method)
@old_delivery_method = ActionMailer::Base.delivery_method
- ActionMailer::Base.delivery_method = delivery_method
+ ActionMailer::Base.delivery_method = method
end
def restore_delivery_method
diff --git a/actionmailer/test/base_test.rb b/actionmailer/test/base_test.rb
new file mode 100644
index 0000000000..df0eed695d
--- /dev/null
+++ b/actionmailer/test/base_test.rb
@@ -0,0 +1,253 @@
+# encoding: utf-8
+require 'abstract_unit'
+
+# class Notifier < ActionMailer::Base
+# delivers_from 'notifications@example.com'
+#
+# def welcome(user)
+# @user = user # available to the view
+# mail(:subject => 'Welcome!', :to => user.email_address)
+# # auto renders both welcome.text.erb and welcome.html.erb
+# end
+#
+# def goodbye(user)
+# headers["X-SPAM"] = 'Not-SPAM'
+# mail(:subject => 'Goodbye', :to => user.email_address) do |format|
+# format.html { render "shared_template "}
+# format.text # goodbye.text.erb
+# end
+# end
+#
+# def surprise(user, gift)
+# attachments[gift.name] = File.read(gift.path)
+# mail(:subject => 'Surprise!', :to => user.email_address) do |format|
+# format.html(:charset => "ascii") # surprise.html.erb
+# format.text(:transfer_encoding => "base64") # surprise.text.erb
+# end
+# end
+#
+# def special_surprise(user, gift)
+# attachments[gift.name] = { :content_type => "application/x-gzip", :content => File.read(gift.path) }
+# mail(:to => 'special@example.com') # subject not required
+# # auto renders both special_surprise.text.erb and special_surprise.html.erb
+# end
+# end
+#
+# mail = Notifier.welcome(user) # => returns a Mail object
+# mail.deliver
+#
+# Notifier.welcome(user).deliver # => creates and sends the Mail in one step
+class BaseTest < ActiveSupport::TestCase
+ DEFAULT_HEADERS = {
+ :to => 'mikel@test.lindsaar.net',
+ :from => 'jose@test.plataformatec.com',
+ :subject => 'The first email on new API!'
+ }
+
+ # TODO Think on the simple case where I want to send an e-mail
+ # with attachment and small text (without need to add a template).
+ class BaseMailer < ActionMailer::Base
+ self.mailer_name = "base_mailer"
+
+ def welcome(hash = {})
+ headers['X-SPAM'] = "Not SPAM"
+ mail(DEFAULT_HEADERS.merge(hash))
+ end
+
+ def attachment_with_content
+ attachments['invoice.pdf'] = 'This is test File content'
+ mail(DEFAULT_HEADERS)
+ end
+
+ def attachment_with_hash
+ attachments['invoice.jpg'] = { :content => "you smiling", :mime_type => "image/x-jpg",
+ :transfer_encoding => "base64" }
+ mail(DEFAULT_HEADERS)
+ end
+
+ def implicit_multipart(hash = {})
+ attachments['invoice.pdf'] = 'This is test File content' if hash.delete(:attachments)
+ mail(DEFAULT_HEADERS.merge(hash))
+ end
+ end
+
+ test "method call to mail does not raise error" do
+ assert_nothing_raised { BaseMailer.deliver_welcome }
+ end
+
+ # Basic mail usage without block
+ test "mail() should set the headers of the mail message" do
+ email = BaseMailer.deliver_welcome
+ assert_equal(email.to, ['mikel@test.lindsaar.net'])
+ assert_equal(email.from, ['jose@test.plataformatec.com'])
+ assert_equal(email.subject, 'The first email on new API!')
+ end
+
+ test "mail() with bcc, cc, content_type, charset, mime_version, reply_to and date" do
+ @time = Time.now
+ email = BaseMailer.deliver_welcome(:bcc => 'bcc@test.lindsaar.net',
+ :cc => 'cc@test.lindsaar.net',
+ :content_type => 'multipart/mixed',
+ :charset => 'iso-8559-1',
+ :mime_version => '2.0',
+ :reply_to => 'reply-to@test.lindsaar.net',
+ :date => @time)
+ assert_equal(email.bcc, ['bcc@test.lindsaar.net'])
+ assert_equal(email.cc, ['cc@test.lindsaar.net'])
+ assert_equal(email.content_type, 'multipart/mixed')
+ assert_equal(email.charset, 'iso-8559-1')
+ assert_equal(email.mime_version, '2.0')
+ assert_equal(email.reply_to, ['reply-to@test.lindsaar.net'])
+ assert_equal(email.date, @time)
+ end
+
+ test "mail() renders the template using the method being processed" do
+ email = BaseMailer.deliver_welcome
+ assert_equal("Welcome", email.body.encoded)
+ end
+
+ # Custom headers
+ test "custom headers" do
+ email = BaseMailer.deliver_welcome
+ assert_equal("Not SPAM", email['X-SPAM'].decoded)
+ end
+
+ # Attachments
+ test "attachment with content" do
+ email = BaseMailer.deliver_attachment_with_content
+ assert_equal(1, email.attachments.length)
+ assert_equal('invoice.pdf', email.attachments[0].filename)
+ assert_equal('This is test File content', email.attachments['invoice.pdf'].decoded)
+ end
+
+ test "attachment gets content type from filename" do
+ email = BaseMailer.deliver_attachment_with_content
+ assert_equal('invoice.pdf', email.attachments[0].filename)
+ end
+
+ test "attachment with hash" do
+ email = BaseMailer.deliver_attachment_with_hash
+ assert_equal(1, email.attachments.length)
+ assert_equal('invoice.jpg', email.attachments[0].filename)
+ assert_equal("\312\213\254\232)b", email.attachments['invoice.jpg'].decoded)
+ end
+
+ test "sets mime type to multipart/mixed when attachment is included" do
+ email = BaseMailer.deliver_attachment_with_content
+ assert_equal(1, email.attachments.length)
+ assert_equal("multipart/mixed", email.mime_type)
+ end
+
+ test "adds the rendered template as part" do
+ email = BaseMailer.deliver_attachment_with_content
+ assert_equal(2, email.parts.length)
+ assert_equal("text/html", email.parts[0].mime_type)
+ assert_equal("Attachment with content", email.parts[0].body.encoded)
+ assert_equal("application/pdf", email.parts[1].mime_type)
+ assert_equal("VGhpcyBpcyB0ZXN0IEZpbGUgY29udGVudA==\r\n", email.parts[1].body.encoded)
+ end
+
+ # Defaults values
+ test "uses default charset from class" do
+ swap BaseMailer, :default_charset => "US-ASCII" do
+ email = BaseMailer.deliver_welcome
+ assert_equal("US-ASCII", email.charset)
+
+ email = BaseMailer.deliver_welcome(:charset => "iso-8559-1")
+ assert_equal("iso-8559-1", email.charset)
+ end
+ end
+
+ test "uses default content type from class" do
+ swap BaseMailer, :default_content_type => "text/html" do
+ email = BaseMailer.deliver_welcome
+ assert_equal("text/html", email.mime_type)
+
+ email = BaseMailer.deliver_welcome(:content_type => "text/plain")
+ assert_equal("text/plain", email.mime_type)
+ end
+ end
+
+ test "uses default mime version from class" do
+ swap BaseMailer, :default_mime_version => "2.0" do
+ email = BaseMailer.deliver_welcome
+ assert_equal("2.0", email.mime_version)
+
+ email = BaseMailer.deliver_welcome(:mime_version => "1.0")
+ assert_equal("1.0", email.mime_version)
+ end
+ end
+
+ test "subject gets default from I18n" do
+ email = BaseMailer.deliver_welcome(:subject => nil)
+ assert_equal "Welcome", email.subject
+
+ I18n.backend.store_translations('en', :actionmailer => {:base_mailer => {:welcome => {:subject => "New Subject!"}}})
+ email = BaseMailer.deliver_welcome(:subject => nil)
+ assert_equal "New Subject!", email.subject
+ end
+
+ # Implicit multipart
+ test "implicit multipart tests" do
+ email = BaseMailer.deliver_implicit_multipart
+ assert_equal(2, email.parts.size)
+ assert_equal("multipart/alternate", email.mime_type)
+ assert_equal("text/plain", email.parts[0].mime_type)
+ assert_equal("TEXT Implicit Multipart", email.parts[0].body.encoded)
+ assert_equal("text/html", email.parts[1].mime_type)
+ assert_equal("HTML Implicit Multipart", email.parts[1].body.encoded)
+ end
+
+ test "implicit multipart tests with sort order" do
+ order = ["text/html", "text/plain"]
+ swap BaseMailer, :default_implicit_parts_order => order do
+ email = BaseMailer.deliver_implicit_multipart
+ assert_equal("text/html", email.parts[0].mime_type)
+ assert_equal("text/plain", email.parts[1].mime_type)
+
+ email = BaseMailer.deliver_implicit_multipart(:parts_order => order.reverse)
+ assert_equal("text/plain", email.parts[0].mime_type)
+ assert_equal("text/html", email.parts[1].mime_type)
+ end
+ end
+
+ test "implicit multipart with attachments creates nested parts" do
+ email = BaseMailer.deliver_implicit_multipart(:attachments => true)
+ assert_equal("application/pdf", email.parts[0].mime_type)
+ assert_equal("multipart/alternate", email.parts[1].mime_type)
+ assert_equal("text/plain", email.parts[1].parts[0].mime_type)
+ assert_equal("TEXT Implicit Multipart", email.parts[1].parts[0].body.encoded)
+ assert_equal("text/html", email.parts[1].parts[1].mime_type)
+ assert_equal("HTML Implicit Multipart", email.parts[1].parts[1].body.encoded)
+ end
+
+ # TODO This should be fixed in mail. Sort parts should be recursive.
+ # test "implicit multipart with attachments and sort order" do
+ # order = ["text/html", "text/plain"]
+ # swap BaseMailer, :default_implicit_parts_order => order do
+ # email = BaseMailer.deliver_implicit_multipart(:attachments => true)
+ # assert_equal("application/pdf", email.parts[0].mime_type)
+ # assert_equal("multipart/alternate", email.parts[1].mime_type)
+ # assert_equal("text/plain", email.parts[1].parts[1].mime_type)
+ # assert_equal("text/html", email.parts[1].parts[0].mime_type)
+ # end
+ # end
+
+ protected
+
+ # Execute the block setting the given values and restoring old values after
+ # the block is executed.
+ def swap(object, new_values)
+ old_values = {}
+ new_values.each do |key, value|
+ old_values[key] = object.send key
+ object.send :"#{key}=", value
+ end
+ yield
+ ensure
+ old_values.each do |key, value|
+ object.send :"#{key}=", value
+ end
+ end
+
+end \ No newline at end of file
diff --git a/actionmailer/test/delivery_method_test.rb b/actionmailer/test/delivery_method_test.rb
index 8f8c6b0275..1e7408d6d6 100644
--- a/actionmailer/test/delivery_method_test.rb
+++ b/actionmailer/test/delivery_method_test.rb
@@ -1,101 +1,73 @@
require 'abstract_unit'
+require 'mail'
-class DefaultDeliveryMethodMailer < ActionMailer::Base
+class MyCustomDelivery
end
-class NonDefaultDeliveryMethodMailer < ActionMailer::Base
- self.delivery_method = :sendmail
-end
-
-class FileDeliveryMethodMailer < ActionMailer::Base
- self.delivery_method = :file
-end
-
-class CustomDeliveryMethod
- attr_accessor :custom_deliveries
- def initialize()
- @customer_deliveries = []
- end
-
- def self.perform_delivery(mail)
- self.custom_deliveries << mail
- end
-end
-
-class CustomerDeliveryMailer < ActionMailer::Base
- self.delivery_method = CustomDeliveryMethod.new
-end
-
-class ActionMailerBase_delivery_method_Test < Test::Unit::TestCase
+class DefaultsDeliveryMethodsTest < ActionMailer::TestCase
def setup
set_delivery_method :smtp
end
-
+
def teardown
restore_delivery_method
end
def test_should_be_the_default_smtp
- assert_instance_of ActionMailer::DeliveryMethod::Smtp, ActionMailer::Base.delivery_method
+ assert_equal :smtp, ActionMailer::Base.delivery_method
end
-end
-class DefaultDeliveryMethodMailer_delivery_method_Test < Test::Unit::TestCase
- def setup
- set_delivery_method :smtp
- end
-
- def teardown
- restore_delivery_method
+ def test_should_have_default_smtp_delivery_method_settings
+ settings = { :address => "localhost",
+ :port => 25,
+ :domain => 'localhost.localdomain',
+ :user_name => nil,
+ :password => nil,
+ :authentication => nil,
+ :enable_starttls_auto => true }
+ assert_equal settings, ActionMailer::Base.smtp_settings
end
-
- def test_should_be_the_default_smtp
- assert_instance_of ActionMailer::DeliveryMethod::Smtp, DefaultDeliveryMethodMailer.delivery_method
- end
-end
-class NonDefaultDeliveryMethodMailer_delivery_method_Test < Test::Unit::TestCase
- def setup
- set_delivery_method :smtp
- end
-
- def teardown
- restore_delivery_method
+ def test_should_have_default_file_delivery_method_settings
+ settings = {:location => "#{Dir.tmpdir}/mails"}
+ assert_equal settings, ActionMailer::Base.file_settings
end
- def test_should_be_the_set_delivery_method
- assert_instance_of ActionMailer::DeliveryMethod::Sendmail, NonDefaultDeliveryMethodMailer.delivery_method
+ def test_should_have_default_sendmail_delivery_method_settings
+ settings = {:location => '/usr/sbin/sendmail',
+ :arguments => '-i -t'}
+ assert_equal settings, ActionMailer::Base.sendmail_settings
end
end
-class FileDeliveryMethodMailer_delivery_method_Test < Test::Unit::TestCase
+class CustomDeliveryMethodsTest < ActionMailer::TestCase
def setup
- set_delivery_method :smtp
+ ActionMailer::Base.add_delivery_method :custom, MyCustomDelivery
end
def teardown
- restore_delivery_method
- end
-
- def test_should_be_the_set_delivery_method
- assert_instance_of ActionMailer::DeliveryMethod::File, FileDeliveryMethodMailer.delivery_method
+ ActionMailer::Base.delivery_methods.delete(:custom)
+ ActionMailer::Base.delivery_settings.delete(:custom)
end
- def test_should_default_location_to_the_tmpdir
- assert_equal "#{Dir.tmpdir}/mails", ActionMailer::Base.file_settings[:location]
+ def test_allow_to_add_a_custom_delivery_method
+ ActionMailer::Base.delivery_method = :custom
+ assert_equal :custom, ActionMailer::Base.delivery_method
end
-end
-class CustomDeliveryMethodMailer_delivery_method_Test < Test::Unit::TestCase
- def setup
- set_delivery_method :smtp
+ def test_allow_to_customize_custom_settings
+ ActionMailer::Base.custom_settings = { :foo => :bar }
+ assert_equal Hash[:foo => :bar], ActionMailer::Base.custom_settings
end
- def teardown
- restore_delivery_method
+ def test_respond_to_custom_method_settings
+ assert_respond_to ActionMailer::Base, :custom_settings
+ assert_respond_to ActionMailer::Base, :custom_settings=
end
- def test_should_be_the_set_delivery_method
- assert_instance_of CustomDeliveryMethod, CustomerDeliveryMailer.delivery_method
+ def test_should_not_respond_for_invalid_method_settings
+ assert_raise NoMethodError do
+ ActionMailer::Base.another_settings
+ end
end
end
diff --git a/actionmailer/test/fixtures/base_mailer/attachment_with_content.erb b/actionmailer/test/fixtures/base_mailer/attachment_with_content.erb
new file mode 100644
index 0000000000..deb9dbd03b
--- /dev/null
+++ b/actionmailer/test/fixtures/base_mailer/attachment_with_content.erb
@@ -0,0 +1 @@
+Attachment with content \ No newline at end of file
diff --git a/actionmailer/test/fixtures/base_mailer/implicit_multipart.html.erb b/actionmailer/test/fixtures/base_mailer/implicit_multipart.html.erb
new file mode 100644
index 0000000000..23745cd282
--- /dev/null
+++ b/actionmailer/test/fixtures/base_mailer/implicit_multipart.html.erb
@@ -0,0 +1 @@
+HTML Implicit Multipart \ No newline at end of file
diff --git a/actionmailer/test/fixtures/base_mailer/implicit_multipart.text.erb b/actionmailer/test/fixtures/base_mailer/implicit_multipart.text.erb
new file mode 100644
index 0000000000..d51437fc72
--- /dev/null
+++ b/actionmailer/test/fixtures/base_mailer/implicit_multipart.text.erb
@@ -0,0 +1 @@
+TEXT Implicit Multipart \ No newline at end of file
diff --git a/actionmailer/test/fixtures/base_mailer/welcome.erb b/actionmailer/test/fixtures/base_mailer/welcome.erb
new file mode 100644
index 0000000000..01f3f00c63
--- /dev/null
+++ b/actionmailer/test/fixtures/base_mailer/welcome.erb
@@ -0,0 +1 @@
+Welcome \ No newline at end of file
diff --git a/actionmailer/test/fixtures/test_mailer/body_ivar.erb b/actionmailer/test/fixtures/test_mailer/body_ivar.erb
deleted file mode 100644
index 1421e5c908..0000000000
--- a/actionmailer/test/fixtures/test_mailer/body_ivar.erb
+++ /dev/null
@@ -1,2 +0,0 @@
-body: <%= @body %>
-bar: <%= @bar %> \ No newline at end of file
diff --git a/actionmailer/test/mail_layout_test.rb b/actionmailer/test/mail_layout_test.rb
index 0877e7b2cb..b9ff075461 100644
--- a/actionmailer/test/mail_layout_test.rb
+++ b/actionmailer/test/mail_layout_test.rb
@@ -1,6 +1,7 @@
require 'abstract_unit'
class AutoLayoutMailer < ActionMailer::Base
+
def hello(recipient)
recipients recipient
subject "You have a mail"
diff --git a/actionmailer/test/mail_service_test.rb b/actionmailer/test/mail_service_test.rb
index f87d9b2e5b..62422fb4b3 100644
--- a/actionmailer/test/mail_service_test.rb
+++ b/actionmailer/test/mail_service_test.rb
@@ -301,13 +301,6 @@ class TestMailer < ActionMailer::Base
render :text => "testing"
end
- def body_ivar(recipient)
- recipients recipient
- subject "Body as a local variable"
- from "test@example.com"
- body :body => "foo", :bar => "baz"
- end
-
def subject_with_i18n(recipient)
recipients recipient
from "system@loudthinking.com"
@@ -423,15 +416,6 @@ class ActionMailerTest < Test::Unit::TestCase
assert_equal expected.encoded, delivered.encoded
end
- def test_subject_with_i18n
- assert_nothing_raised { TestMailer.deliver_subject_with_i18n(@recipient) }
- assert_equal "Subject with i18n", ActionMailer::Base.deliveries.first.subject.to_s
-
- I18n.backend.store_translations('en', :actionmailer => {:test_mailer => {:subject_with_i18n => {:subject => "New Subject!"}}})
- assert_nothing_raised { TestMailer.deliver_subject_with_i18n(@recipient) }
- assert_equal "New Subject!", ActionMailer::Base.deliveries.last.subject.to_s
- end
-
def test_custom_template
expected = new_mail
expected.to = @recipient
@@ -545,7 +529,7 @@ class ActionMailerTest < Test::Unit::TestCase
assert_not_nil mail
mail, from, to = mail
- assert_equal 'system@loudthinking.com', from.addresses.first
+ assert_equal 'system@loudthinking.com', from
end
def test_reply_to
@@ -674,15 +658,12 @@ class ActionMailerTest < Test::Unit::TestCase
def test_doesnt_raise_errors_when_raise_delivery_errors_is_false
ActionMailer::Base.raise_delivery_errors = false
- TestMailer.delivery_method.expects(:perform_delivery).raises(Exception)
+ Mail::Message.any_instance.expects(:deliver!).raises(Exception)
assert_nothing_raised { TestMailer.deliver_signed_up(@recipient) }
end
def test_performs_delivery_via_sendmail
- sm = mock()
- sm.expects(:print).with(anything)
- sm.expects(:flush)
- IO.expects(:popen).once.with('/usr/sbin/sendmail -i -t', 'w+').yields(sm)
+ IO.expects(:popen).once.with('/usr/sbin/sendmail -i -t -f "system@loudthinking.com" test@localhost', 'w+')
ActionMailer::Base.delivery_method = :sendmail
TestMailer.deliver_signed_up(@recipient)
end
@@ -901,6 +882,7 @@ EOF
assert_equal "iso-8859-1", mail.parts[1].charset
assert_equal "image/jpeg", mail.parts[2].mime_type
+
assert_equal "attachment", mail.parts[2][:content_disposition].disposition_type
assert_equal "foo.jpg", mail.parts[2][:content_disposition].filename
assert_equal "foo.jpg", mail.parts[2][:content_type].filename
@@ -1038,7 +1020,7 @@ EOF
def test_empty_header_values_omitted
result = TestMailer.create_unnamed_attachment(@recipient).encoded
assert_match %r{Content-Type: application/octet-stream;}, result
- assert_match %r{Content-Disposition: attachment[^;]}, result
+ assert_match %r{Content-Disposition: attachment;}, result
end
def test_headers_with_nonalpha_chars
@@ -1072,12 +1054,7 @@ EOF
def test_return_path_with_create
mail = TestMailer.create_return_path
- assert_equal "another@somewhere.test", mail['return-path'].to_s
- end
-
- def test_return_path_with_create
- mail = TestMailer.create_return_path
- assert_equal ["another@somewhere.test"], mail.return_path
+ assert_equal "another@somewhere.test", mail.return_path
end
def test_return_path_with_deliver
@@ -1087,13 +1064,8 @@ EOF
assert_equal "another@somewhere.test", MockSMTP.deliveries[0][1].to_s
end
- def test_body_is_stored_as_an_ivar
- mail = TestMailer.create_body_ivar(@recipient)
- assert_equal "body: foo\nbar: baz", mail.body.to_s
- end
-
def test_starttls_is_enabled_if_supported
- ActionMailer::Base.smtp_settings[:enable_starttls_auto] = true
+ ActionMailer::Base.delivery_settings[:smtp].merge!(:enable_starttls_auto => true)
MockSMTP.any_instance.expects(:respond_to?).with(:enable_starttls_auto).returns(true)
MockSMTP.any_instance.expects(:enable_starttls_auto)
ActionMailer::Base.delivery_method = :smtp
@@ -1101,7 +1073,7 @@ EOF
end
def test_starttls_is_disabled_if_not_supported
- ActionMailer::Base.smtp_settings[:enable_starttls_auto] = true
+ ActionMailer::Base.delivery_settings[:smtp].merge!(:enable_starttls_auto => true)
MockSMTP.any_instance.expects(:respond_to?).with(:enable_starttls_auto).returns(false)
MockSMTP.any_instance.expects(:enable_starttls_auto).never
ActionMailer::Base.delivery_method = :smtp
@@ -1109,13 +1081,12 @@ EOF
end
def test_starttls_is_not_enabled
- ActionMailer::Base.smtp_settings[:enable_starttls_auto] = false
+ ActionMailer::Base.delivery_settings[:smtp].merge!(:enable_starttls_auto => false)
MockSMTP.any_instance.expects(:respond_to?).never
- MockSMTP.any_instance.expects(:enable_starttls_auto).never
ActionMailer::Base.delivery_method = :smtp
TestMailer.deliver_signed_up(@recipient)
ensure
- ActionMailer::Base.smtp_settings[:enable_starttls_auto] = true
+ ActionMailer::Base.delivery_settings[:smtp].merge!(:enable_starttls_auto => true)
end
end
diff --git a/actionmailer/test/test_helper_test.rb b/actionmailer/test/test_helper_test.rb
index 1fed26f78f..48e4433e98 100644
--- a/actionmailer/test/test_helper_test.rb
+++ b/actionmailer/test/test_helper_test.rb
@@ -12,7 +12,7 @@ end
class TestHelperMailerTest < ActionMailer::TestCase
def test_setup_sets_right_action_mailer_options
- assert_instance_of ActionMailer::DeliveryMethod::Test, ActionMailer::Base.delivery_method
+ assert_equal :test, ActionMailer::Base.delivery_method
assert ActionMailer::Base.perform_deliveries
assert_equal [], ActionMailer::Base.deliveries
end
diff --git a/actionmailer/test/tmail_compat_test.rb b/actionmailer/test/tmail_compat_test.rb
index a1ca6a7243..b7fcb3cfea 100644
--- a/actionmailer/test/tmail_compat_test.rb
+++ b/actionmailer/test/tmail_compat_test.rb
@@ -4,7 +4,6 @@ class TmailCompatTest < Test::Unit::TestCase
def test_set_content_type_raises_deprecation_warning
mail = Mail.new
- STDERR.expects(:puts) # Deprecation warning
assert_nothing_raised do
mail.set_content_type "text/plain"
end
@@ -13,7 +12,6 @@ class TmailCompatTest < Test::Unit::TestCase
def test_transfer_encoding_raises_deprecation_warning
mail = Mail.new
- STDERR.expects(:puts) # Deprecation warning
assert_nothing_raised do
mail.transfer_encoding "base64"
end
diff --git a/railties/lib/generators/test_unit/mailer/templates/functional_test.rb b/railties/lib/generators/test_unit/mailer/templates/functional_test.rb
index 4de94076e9..d7366fea5f 100644
--- a/railties/lib/generators/test_unit/mailer/templates/functional_test.rb
+++ b/railties/lib/generators/test_unit/mailer/templates/functional_test.rb
@@ -7,7 +7,7 @@ class <%= class_name %>Test < ActionMailer::TestCase
@expected.body = read_fixture('<%= action %>')
@expected.date = Time.now
- assert_equal @expected.encoded, <%= class_name %>.create_<%= action %>(@expected.date).encoded
+ assert_equal @expected, <%= class_name %>.create_<%= action %>(@expected.date)
end
<% end -%>
diff --git a/railties/lib/rails/configuration.rb b/railties/lib/rails/configuration.rb
index 7f1783a6b9..21736a28eb 100644
--- a/railties/lib/rails/configuration.rb
+++ b/railties/lib/rails/configuration.rb
@@ -137,7 +137,7 @@ module Rails
end
def frameworks(*args)
- raise "config.frameworks in no longer supported. See the generated " \
+ raise "config.frameworks is no longer supported. See the generated " \
"config/boot.rb for steps on how to limit the frameworks that " \
"will be loaded"
end