mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
abstract all of the ActionMailer delivery methods into their own classes. thereby the following are equivalent
ActionMailer::Base.delivery_method = :smtp ActionMailer::Base.delivery_method = ActionMailer::DeliveryMethod::Smtp we could equally set our own custom object as long as it provides the instance method :perform_delivery(mail) eg. class MySmsDeliveryMethod def perform_delivery(mail) Sms.send(mail['to'], mail['body']) end end MySmsMailer.delivery_method = MySmsDeliveryMethod.new Signed-off-by: José Valim <jose.valim@gmail.com>
This commit is contained in:
parent
3f56038612
commit
f4f76772fb
11 changed files with 192 additions and 67 deletions
|
@ -44,6 +44,7 @@ Rake::RDocTask.new { |rdoc|
|
||||||
rdoc.rdoc_files.include('README', 'CHANGELOG')
|
rdoc.rdoc_files.include('README', 'CHANGELOG')
|
||||||
rdoc.rdoc_files.include('lib/action_mailer.rb')
|
rdoc.rdoc_files.include('lib/action_mailer.rb')
|
||||||
rdoc.rdoc_files.include('lib/action_mailer/*.rb')
|
rdoc.rdoc_files.include('lib/action_mailer/*.rb')
|
||||||
|
rdoc.rdoc_files.include('lib/action_mailer/delivery_method/*.rb')
|
||||||
}
|
}
|
||||||
|
|
||||||
spec = eval(File.read('actionmailer.gemspec'))
|
spec = eval(File.read('actionmailer.gemspec'))
|
||||||
|
|
|
@ -33,6 +33,7 @@ module ActionMailer
|
||||||
|
|
||||||
autoload :AdvAttrAccessor, 'action_mailer/adv_attr_accessor'
|
autoload :AdvAttrAccessor, 'action_mailer/adv_attr_accessor'
|
||||||
autoload :Base, 'action_mailer/base'
|
autoload :Base, 'action_mailer/base'
|
||||||
|
autoload :DeliveryMethod, 'action_mailer/delivery_method'
|
||||||
autoload :Helpers, 'action_mailer/helpers'
|
autoload :Helpers, 'action_mailer/helpers'
|
||||||
autoload :Part, 'action_mailer/part'
|
autoload :Part, 'action_mailer/part'
|
||||||
autoload :PartContainer, 'action_mailer/part_container'
|
autoload :PartContainer, 'action_mailer/part_container'
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
require 'tmpdir'
|
|
||||||
|
|
||||||
require "active_support/core_ext/class"
|
require "active_support/core_ext/class"
|
||||||
# Use the old layouts until actionmailer gets refactored
|
# Use the old layouts until actionmailer gets refactored
|
||||||
require "action_controller/legacy/layout"
|
require "action_controller/legacy/layout"
|
||||||
|
@ -232,7 +230,7 @@ module ActionMailer #:nodoc:
|
||||||
# * <tt>raise_delivery_errors</tt> - Whether or not errors should be raised if the email fails to be delivered.
|
# * <tt>raise_delivery_errors</tt> - Whether or not errors should be raised if the email fails to be delivered.
|
||||||
#
|
#
|
||||||
# * <tt>delivery_method</tt> - Defines a delivery method. Possible values are <tt>:smtp</tt> (default), <tt>:sendmail</tt>, <tt>:test</tt>,
|
# * <tt>delivery_method</tt> - Defines a delivery method. Possible values are <tt>:smtp</tt> (default), <tt>:sendmail</tt>, <tt>:test</tt>,
|
||||||
# and <tt>:file</tt>.
|
# and <tt>:file</tt>. Or you may provide a custom delivery method object eg. MyOwnDeliveryMethodClass.new
|
||||||
#
|
#
|
||||||
# * <tt>perform_deliveries</tt> - Determines whether <tt>deliver_*</tt> methods are actually carried out. By default they are,
|
# * <tt>perform_deliveries</tt> - Determines whether <tt>deliver_*</tt> methods are actually carried out. By default they are,
|
||||||
# but this can be turned off to help functional testing.
|
# but this can be turned off to help functional testing.
|
||||||
|
@ -270,35 +268,21 @@ module ActionMailer #:nodoc:
|
||||||
|
|
||||||
cattr_accessor :logger
|
cattr_accessor :logger
|
||||||
|
|
||||||
@@smtp_settings = {
|
class << self
|
||||||
:address => "localhost",
|
delegate :settings, :settings=, :to => ActionMailer::DeliveryMethod::File, :prefix => :file
|
||||||
:port => 25,
|
delegate :settings, :settings=, :to => ActionMailer::DeliveryMethod::Sendmail, :prefix => :sendmail
|
||||||
:domain => 'localhost.localdomain',
|
delegate :settings, :settings=, :to => ActionMailer::DeliveryMethod::Smtp, :prefix => :smtp
|
||||||
:user_name => nil,
|
|
||||||
:password => nil,
|
|
||||||
:authentication => nil,
|
|
||||||
:enable_starttls_auto => true,
|
|
||||||
}
|
|
||||||
cattr_accessor :smtp_settings
|
|
||||||
|
|
||||||
@@sendmail_settings = {
|
def delivery_method=(method_name)
|
||||||
:location => '/usr/sbin/sendmail',
|
@delivery_method = ActionMailer::DeliveryMethod.lookup_method(method_name)
|
||||||
:arguments => '-i -t'
|
end
|
||||||
}
|
end
|
||||||
cattr_accessor :sendmail_settings
|
self.delivery_method = :smtp
|
||||||
|
superclass_delegating_reader :delivery_method
|
||||||
@@file_settings = {
|
|
||||||
:location => defined?(Rails) ? "#{Rails.root}/tmp/mails" : "#{Dir.tmpdir}/mails"
|
|
||||||
}
|
|
||||||
|
|
||||||
cattr_accessor :file_settings
|
|
||||||
|
|
||||||
@@raise_delivery_errors = true
|
@@raise_delivery_errors = true
|
||||||
cattr_accessor :raise_delivery_errors
|
cattr_accessor :raise_delivery_errors
|
||||||
|
|
||||||
superclass_delegating_accessor :delivery_method
|
|
||||||
self.delivery_method = :smtp
|
|
||||||
|
|
||||||
@@perform_deliveries = true
|
@@perform_deliveries = true
|
||||||
cattr_accessor :perform_deliveries
|
cattr_accessor :perform_deliveries
|
||||||
|
|
||||||
|
@ -552,7 +536,7 @@ module ActionMailer #:nodoc:
|
||||||
|
|
||||||
ActiveSupport::Notifications.instrument(:deliver_mail, :mail => @mail) do
|
ActiveSupport::Notifications.instrument(:deliver_mail, :mail => @mail) do
|
||||||
begin
|
begin
|
||||||
__send__("perform_delivery_#{delivery_method}", mail) if perform_deliveries
|
self.delivery_method.perform_delivery(mail) if perform_deliveries
|
||||||
rescue Exception => e # Net::SMTP errors or sendmail pipe errors
|
rescue Exception => e # Net::SMTP errors or sendmail pipe errors
|
||||||
raise e if raise_delivery_errors
|
raise e if raise_delivery_errors
|
||||||
end
|
end
|
||||||
|
@ -720,39 +704,6 @@ module ActionMailer #:nodoc:
|
||||||
@mail = m
|
@mail = m
|
||||||
end
|
end
|
||||||
|
|
||||||
def perform_delivery_smtp(mail)
|
|
||||||
destinations = mail.destinations
|
|
||||||
mail.ready_to_send
|
|
||||||
sender = (mail['return-path'] && mail['return-path'].spec) || mail['from']
|
|
||||||
|
|
||||||
smtp = Net::SMTP.new(smtp_settings[:address], smtp_settings[:port])
|
|
||||||
smtp.enable_starttls_auto if smtp_settings[:enable_starttls_auto] && smtp.respond_to?(:enable_starttls_auto)
|
|
||||||
smtp.start(smtp_settings[:domain], smtp_settings[:user_name], smtp_settings[:password],
|
|
||||||
smtp_settings[:authentication]) do |smtp|
|
|
||||||
smtp.sendmail(mail.encoded, sender, destinations)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def perform_delivery_sendmail(mail)
|
|
||||||
sendmail_args = sendmail_settings[:arguments]
|
|
||||||
sendmail_args += " -f \"#{mail['return-path']}\"" if mail['return-path']
|
|
||||||
IO.popen("#{sendmail_settings[:location]} #{sendmail_args}","w+") do |sm|
|
|
||||||
sm.print(mail.encoded.gsub(/\r/, ''))
|
|
||||||
sm.flush
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def perform_delivery_test(mail)
|
|
||||||
deliveries << mail
|
|
||||||
end
|
|
||||||
|
|
||||||
def perform_delivery_file(mail)
|
|
||||||
FileUtils.mkdir_p file_settings[:location]
|
|
||||||
|
|
||||||
(mail.to + mail.cc + mail.bcc).uniq.each do |to|
|
|
||||||
File.open(File.join(file_settings[:location], to), 'a') { |f| f.write(mail) }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
Base.class_eval do
|
Base.class_eval do
|
||||||
|
|
58
actionmailer/lib/action_mailer/delivery_method.rb
Normal file
58
actionmailer/lib/action_mailer/delivery_method.rb
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
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
|
||||||
|
Smtp.new
|
||||||
|
else
|
||||||
|
delivery_method
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# An abstract delivery method class. There are multiple delivery method
|
||||||
|
# classes, documented under
|
||||||
|
# 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
|
21
actionmailer/lib/action_mailer/delivery_method/file.rb
Normal file
21
actionmailer/lib/action_mailer/delivery_method/file.rb
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
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) ? "#{Rails.root}/tmp/mails" : "#{Dir.tmpdir}/mails"
|
||||||
|
}
|
||||||
|
|
||||||
|
def perform_delivery(mail)
|
||||||
|
FileUtils.mkdir_p settings[:location]
|
||||||
|
|
||||||
|
(mail.to + mail.cc + mail.bcc).uniq.each do |to|
|
||||||
|
::File.open(::File.join(settings[:location], to), 'a') { |f| f.write(mail) }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
22
actionmailer/lib/action_mailer/delivery_method/sendmail.rb
Normal file
22
actionmailer/lib/action_mailer/delivery_method/sendmail.rb
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
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
|
31
actionmailer/lib/action_mailer/delivery_method/smtp.rb
Normal file
31
actionmailer/lib/action_mailer/delivery_method/smtp.rb
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
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
|
||||||
|
mail.ready_to_send
|
||||||
|
sender = (mail['return-path'] && mail['return-path'].spec) || 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
|
12
actionmailer/lib/action_mailer/delivery_method/test.rb
Normal file
12
actionmailer/lib/action_mailer/delivery_method/test.rb
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
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
|
|
@ -11,6 +11,21 @@ class FileDeliveryMethodMailer < ActionMailer::Base
|
||||||
self.delivery_method = :file
|
self.delivery_method = :file
|
||||||
end
|
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 ActionMailerBase_delivery_method_Test < Test::Unit::TestCase
|
||||||
def setup
|
def setup
|
||||||
set_delivery_method :smtp
|
set_delivery_method :smtp
|
||||||
|
@ -21,7 +36,7 @@ class ActionMailerBase_delivery_method_Test < Test::Unit::TestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_should_be_the_default_smtp
|
def test_should_be_the_default_smtp
|
||||||
assert_equal :smtp, ActionMailer::Base.delivery_method
|
assert_instance_of ActionMailer::DeliveryMethod::Smtp, ActionMailer::Base.delivery_method
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -35,7 +50,7 @@ class DefaultDeliveryMethodMailer_delivery_method_Test < Test::Unit::TestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_should_be_the_default_smtp
|
def test_should_be_the_default_smtp
|
||||||
assert_equal :smtp, DefaultDeliveryMethodMailer.delivery_method
|
assert_instance_of ActionMailer::DeliveryMethod::Smtp, DefaultDeliveryMethodMailer.delivery_method
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -49,7 +64,7 @@ class NonDefaultDeliveryMethodMailer_delivery_method_Test < Test::Unit::TestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_should_be_the_set_delivery_method
|
def test_should_be_the_set_delivery_method
|
||||||
assert_equal :sendmail, NonDefaultDeliveryMethodMailer.delivery_method
|
assert_instance_of ActionMailer::DeliveryMethod::Sendmail, NonDefaultDeliveryMethodMailer.delivery_method
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -63,7 +78,7 @@ class FileDeliveryMethodMailer_delivery_method_Test < Test::Unit::TestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_should_be_the_set_delivery_method
|
def test_should_be_the_set_delivery_method
|
||||||
assert_equal :file, FileDeliveryMethodMailer.delivery_method
|
assert_instance_of ActionMailer::DeliveryMethod::File, FileDeliveryMethodMailer.delivery_method
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_should_default_location_to_the_tmpdir
|
def test_should_default_location_to_the_tmpdir
|
||||||
|
@ -71,3 +86,16 @@ class FileDeliveryMethodMailer_delivery_method_Test < Test::Unit::TestCase
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
class CustomDeliveryMethodMailer_delivery_method_Test < Test::Unit::TestCase
|
||||||
|
def setup
|
||||||
|
set_delivery_method :smtp
|
||||||
|
end
|
||||||
|
|
||||||
|
def teardown
|
||||||
|
restore_delivery_method
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_should_be_the_set_delivery_method
|
||||||
|
assert_instance_of CustomDeliveryMethod, CustomerDeliveryMailer.delivery_method
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
|
@ -554,7 +554,7 @@ class ActionMailerTest < Test::Unit::TestCase
|
||||||
|
|
||||||
def test_doesnt_raise_errors_when_raise_delivery_errors_is_false
|
def test_doesnt_raise_errors_when_raise_delivery_errors_is_false
|
||||||
ActionMailer::Base.raise_delivery_errors = false
|
ActionMailer::Base.raise_delivery_errors = false
|
||||||
TestMailer.any_instance.expects(:perform_delivery_test).raises(Exception)
|
TestMailer.delivery_method.expects(:perform_delivery).raises(Exception)
|
||||||
assert_nothing_raised { TestMailer.deliver_signed_up(@recipient) }
|
assert_nothing_raised { TestMailer.deliver_signed_up(@recipient) }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ end
|
||||||
|
|
||||||
class TestHelperMailerTest < ActionMailer::TestCase
|
class TestHelperMailerTest < ActionMailer::TestCase
|
||||||
def test_setup_sets_right_action_mailer_options
|
def test_setup_sets_right_action_mailer_options
|
||||||
assert_equal :test, ActionMailer::Base.delivery_method
|
assert_instance_of ActionMailer::DeliveryMethod::Test, ActionMailer::Base.delivery_method
|
||||||
assert ActionMailer::Base.perform_deliveries
|
assert ActionMailer::Base.perform_deliveries
|
||||||
assert_equal [], ActionMailer::Base.deliveries
|
assert_equal [], ActionMailer::Base.deliveries
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue