aboutsummaryrefslogtreecommitdiffstats
path: root/actionmailer
diff options
context:
space:
mode:
Diffstat (limited to 'actionmailer')
-rw-r--r--actionmailer/CHANGELOG.md16
-rw-r--r--actionmailer/lib/action_mailer/base.rb19
-rw-r--r--actionmailer/lib/action_mailer/log_subscriber.rb24
-rw-r--r--actionmailer/lib/action_mailer/preview.rb12
-rw-r--r--actionmailer/lib/action_mailer/railtie.rb10
-rw-r--r--actionmailer/test/abstract_unit.rb26
-rw-r--r--actionmailer/test/asset_host_test.rb17
-rw-r--r--actionmailer/test/base_test.rb39
-rw-r--r--actionmailer/test/delivery_methods_test.rb2
-rw-r--r--actionmailer/test/fixtures/test_helper_mailer/welcome1
-rw-r--r--actionmailer/test/i18n_with_controller_test.rb18
-rw-r--r--actionmailer/test/test_helper_test.rb9
12 files changed, 140 insertions, 53 deletions
diff --git a/actionmailer/CHANGELOG.md b/actionmailer/CHANGELOG.md
index 97ff62fa87..bcfde6d96f 100644
--- a/actionmailer/CHANGELOG.md
+++ b/actionmailer/CHANGELOG.md
@@ -1,3 +1,19 @@
+* Raise an exception when attachments are added after `mail` was called.
+ This is a safeguard to prevent invalid emails.
+
+ Fixes #16163.
+
+ *Yves Senn*
+
+* Add `config.action_mailer.show_previews` configuration option.
+
+ This config option can be used to enable the mail preview in environments
+ other than development (such as staging).
+
+ Defaults to `true` in development and false elsewhere.
+
+ *Leonard Garvey*
+
* Allow preview interceptors to be registered through
`config.action_mailer.preview_interceptors`.
diff --git a/actionmailer/lib/action_mailer/base.rb b/actionmailer/lib/action_mailer/base.rb
index 135cf35ac0..d9b88ec608 100644
--- a/actionmailer/lib/action_mailer/base.rb
+++ b/actionmailer/lib/action_mailer/base.rb
@@ -394,7 +394,7 @@ module ActionMailer
# implement for a custom delivery agent.
#
# * <tt>perform_deliveries</tt> - Determines whether emails are actually sent from Action Mailer when you
- # call <tt>.deliver</tt> on an mail message or on an Action Mailer method. This is on by default but can
+ # call <tt>.deliver</tt> on an email message or on an Action Mailer method. This is on by default but can
# be turned off to aid in functional testing.
#
# * <tt>deliveries</tt> - Keeps an array of all the emails sent out through the Action Mailer with
@@ -649,7 +649,22 @@ module ActionMailer
# mail.attachments[0] # => Mail::Part (first attachment)
#
def attachments
- @_message.attachments
+ if @_mail_was_called
+ LateAttachmentsProxy.new(@_message.attachments)
+ else
+ @_message.attachments
+ end
+ end
+
+ class LateAttachmentsProxy < SimpleDelegator
+ def inline; _raise_error end
+ def []=(_name, _content); _raise_error end
+
+ private
+ def _raise_error
+ raise RuntimeError, "Can't add attachments after `mail` was called.\n" \
+ "Make sure to use `attachments[]=` before calling `mail`."
+ end
end
# The main method that creates the message and renders the email templates. There are
diff --git a/actionmailer/lib/action_mailer/log_subscriber.rb b/actionmailer/lib/action_mailer/log_subscriber.rb
index e4aaab34b1..5b57c75ec3 100644
--- a/actionmailer/lib/action_mailer/log_subscriber.rb
+++ b/actionmailer/lib/action_mailer/log_subscriber.rb
@@ -6,25 +6,27 @@ module ActionMailer
class LogSubscriber < ActiveSupport::LogSubscriber
# An email was delivered.
def deliver(event)
- return unless logger.info?
- recipients = Array(event.payload[:to]).join(', ')
- info("\nSent mail to #{recipients} (#{event.duration.round(1)}ms)")
- debug(event.payload[:mail])
+ info do
+ recipients = Array(event.payload[:to]).join(', ')
+ "\nSent mail to #{recipients} (#{event.duration.round(1)}ms)"
+ end
+
+ debug { event.payload[:mail] }
end
# An email was received.
def receive(event)
- return unless logger.info?
- info("\nReceived mail (#{event.duration.round(1)}ms)")
- debug(event.payload[:mail])
+ info { "\nReceived mail (#{event.duration.round(1)}ms)" }
+ debug { event.payload[:mail] }
end
# An email was generated.
def process(event)
- return unless logger.debug?
- mailer = event.payload[:mailer]
- action = event.payload[:action]
- debug("\n#{mailer}##{action}: processed outbound mail in #{event.duration.round(1)}ms")
+ debug do
+ mailer = event.payload[:mailer]
+ action = event.payload[:action]
+ "\n#{mailer}##{action}: processed outbound mail in #{event.duration.round(1)}ms"
+ end
end
# Use the logger configured for ActionMailer::Base
diff --git a/actionmailer/lib/action_mailer/preview.rb b/actionmailer/lib/action_mailer/preview.rb
index 33a9faa7e7..33de1dc049 100644
--- a/actionmailer/lib/action_mailer/preview.rb
+++ b/actionmailer/lib/action_mailer/preview.rb
@@ -11,6 +11,14 @@ module ActionMailer
#
mattr_accessor :preview_path, instance_writer: false
+ # Enable or disable mailer previews through app configuration:
+ #
+ # config.action_mailer.show_previews = true
+ #
+ # Defaults to true for development environment
+ #
+ mattr_accessor :show_previews, instance_writer: false
+
# :nodoc:
mattr_accessor :preview_interceptors, instance_writer: false
self.preview_interceptors = []
@@ -94,6 +102,10 @@ module ActionMailer
Base.preview_path
end
+ def show_previews #:nodoc:
+ Base.show_previews
+ end
+
def inform_preview_interceptors(message) #:nodoc:
Base.preview_interceptors.each do |interceptor|
interceptor.previewing_email(message)
diff --git a/actionmailer/lib/action_mailer/railtie.rb b/actionmailer/lib/action_mailer/railtie.rb
index 671551fa53..6f760732e2 100644
--- a/actionmailer/lib/action_mailer/railtie.rb
+++ b/actionmailer/lib/action_mailer/railtie.rb
@@ -18,8 +18,9 @@ module ActionMailer
options.assets_dir ||= paths["public"].first
options.javascripts_dir ||= paths["public/javascripts"].first
options.stylesheets_dir ||= paths["public/stylesheets"].first
+ options.show_previews = Rails.env.development? if options.show_previews.nil?
- if Rails.env.development?
+ if options.show_previews
options.preview_path ||= defined?(Rails.root) ? "#{Rails.root}/test/mailers/previews" : nil
end
@@ -37,6 +38,13 @@ module ActionMailer
register_observers(options.delete(:observers))
options.each { |k,v| send("#{k}=", v) }
+
+ if options.show_previews
+ app.routes.append do
+ get '/rails/mailers' => "rails/mailers#index"
+ get '/rails/mailers/*path' => "rails/mailers#preview"
+ end
+ end
end
end
diff --git a/actionmailer/test/abstract_unit.rb b/actionmailer/test/abstract_unit.rb
index 4e5a9c3715..98d266bd73 100644
--- a/actionmailer/test/abstract_unit.rb
+++ b/actionmailer/test/abstract_unit.rb
@@ -26,27 +26,9 @@ I18n.enforce_available_locales = false
FIXTURE_LOAD_PATH = File.expand_path('fixtures', File.dirname(__FILE__))
ActionMailer::Base.view_paths = FIXTURE_LOAD_PATH
-class MockSMTP
- def self.deliveries
- @@deliveries
- end
-
- def initialize
- @@deliveries = []
- end
-
- def sendmail(mail, from, to)
- @@deliveries << [mail, from, to]
- end
-
- def start(*args)
- yield self
- end
-end
-
-class Net::SMTP
- def self.new(*args)
- MockSMTP.new
+class Rails
+ def self.root
+ File.expand_path('../', File.dirname(__FILE__))
end
end
@@ -67,3 +49,5 @@ end
def jruby_skip(message = '')
skip message if defined?(JRUBY_VERSION)
end
+
+require 'mocha/setup' # FIXME: stop using mocha
diff --git a/actionmailer/test/asset_host_test.rb b/actionmailer/test/asset_host_test.rb
index 00f1348a53..9ba67c2842 100644
--- a/actionmailer/test/asset_host_test.rb
+++ b/actionmailer/test/asset_host_test.rb
@@ -31,25 +31,10 @@ class AssetHostTest < ActiveSupport::TestCase
def test_asset_host_as_one_argument_proc
AssetHostMailer.config.asset_host = Proc.new { |source|
if source.starts_with?('/images')
- "http://images.example.com"
- else
- "http://assets.example.com"
+ 'http://images.example.com'
end
}
mail = AssetHostMailer.email_with_asset
assert_equal %Q{<img alt="Somelogo" src="http://images.example.com/images/somelogo.png" />}, mail.body.to_s.strip
end
-
- def test_asset_host_as_two_argument_proc
- ActionController::Base.config.asset_host = Proc.new {|source,request|
- if request && request.ssl?
- "https://www.example.com"
- else
- "http://www.example.com"
- end
- }
- mail = nil
- assert_nothing_raised { mail = AssetHostMailer.email_with_asset }
- assert_equal %Q{<img alt="Somelogo" src="http://www.example.com/images/somelogo.png" />}, mail.body.to_s.strip
- end
end
diff --git a/actionmailer/test/base_test.rb b/actionmailer/test/base_test.rb
index 229ded8e04..6116d1e29f 100644
--- a/actionmailer/test/base_test.rb
+++ b/actionmailer/test/base_test.rb
@@ -232,6 +232,45 @@ class BaseTest < ActiveSupport::TestCase
end
end
+ test "adding attachments after mail was called raises exception" do
+ class LateAttachmentMailer < ActionMailer::Base
+ def welcome
+ mail body: "yay", from: "welcome@example.com", to: "to@example.com"
+ attachments['invoice.pdf'] = 'This is test File content'
+ end
+ end
+
+ e = assert_raises(RuntimeError) { LateAttachmentMailer.welcome }
+ assert_match(/Can't add attachments after `mail` was called./, e.message)
+ end
+
+ test "adding inline attachments after mail was called raises exception" do
+ class LateInlineAttachmentMailer < ActionMailer::Base
+ def welcome
+ mail body: "yay", from: "welcome@example.com", to: "to@example.com"
+ attachments.inline['invoice.pdf'] = 'This is test File content'
+ end
+ end
+
+ e = assert_raises(RuntimeError) { LateInlineAttachmentMailer.welcome }
+ assert_match(/Can't add attachments after `mail` was called./, e.message)
+ end
+
+ test "accessing attachments works after mail was called" do
+ class LateAttachmentAccessorMailer < ActionMailer::Base
+ def welcome
+ attachments['invoice.pdf'] = 'This is test File content'
+ mail body: "yay", from: "welcome@example.com", to: "to@example.com"
+
+ unless attachments.map(&:filename) == ["invoice.pdf"]
+ raise Minitest::Assertion, "Should allow access to attachments"
+ end
+ end
+ end
+
+ assert_nothing_raised { LateAttachmentAccessorMailer.welcome }
+ end
+
# Implicit multipart
test "implicit multipart" do
email = BaseMailer.implicit_multipart
diff --git a/actionmailer/test/delivery_methods_test.rb b/actionmailer/test/delivery_methods_test.rb
index 16e8638542..a76ac6d295 100644
--- a/actionmailer/test/delivery_methods_test.rb
+++ b/actionmailer/test/delivery_methods_test.rb
@@ -108,6 +108,7 @@ class MailDeliveryTest < ActiveSupport::TestCase
end
test "delivery method can be customized per instance" do
+ Mail::SMTP.any_instance.expects(:deliver!)
email = DeliveryMailer.welcome.deliver
assert_instance_of Mail::SMTP, email.delivery_method
email = DeliveryMailer.welcome(delivery_method: :test).deliver
@@ -117,7 +118,6 @@ class MailDeliveryTest < ActiveSupport::TestCase
test "delivery method can be customized in subclasses not changing the parent" do
DeliveryMailer.delivery_method = :test
assert_equal :smtp, ActionMailer::Base.delivery_method
- $BREAK = true
email = DeliveryMailer.welcome.deliver
assert_instance_of Mail::TestMailer, email.delivery_method
end
diff --git a/actionmailer/test/fixtures/test_helper_mailer/welcome b/actionmailer/test/fixtures/test_helper_mailer/welcome
new file mode 100644
index 0000000000..61ce70d578
--- /dev/null
+++ b/actionmailer/test/fixtures/test_helper_mailer/welcome
@@ -0,0 +1 @@
+Welcome! \ No newline at end of file
diff --git a/actionmailer/test/i18n_with_controller_test.rb b/actionmailer/test/i18n_with_controller_test.rb
index d9d588a950..ee36b89dd6 100644
--- a/actionmailer/test/i18n_with_controller_test.rb
+++ b/actionmailer/test/i18n_with_controller_test.rb
@@ -28,8 +28,23 @@ class ActionMailerI18nWithControllerTest < ActionDispatch::IntegrationTest
get ':controller(/:action(/:id))'
end
+ class RoutedRackApp
+ attr_reader :routes
+
+ def initialize(routes, &blk)
+ @routes = routes
+ @stack = ActionDispatch::MiddlewareStack.new(&blk).build(@routes)
+ end
+
+ def call(env)
+ @stack.call(env)
+ end
+ end
+
+ APP = RoutedRackApp.new(Routes)
+
def app
- Routes
+ APP
end
teardown do
@@ -37,6 +52,7 @@ class ActionMailerI18nWithControllerTest < ActionDispatch::IntegrationTest
end
def test_send_mail
+ Mail::SMTP.any_instance.expects(:deliver!)
with_translation 'de', email_subject: '[Anmeldung] Willkommen' do
get '/test/send_mail'
assert_equal "Mail sent - Subject: [Anmeldung] Willkommen", @response.body
diff --git a/actionmailer/test/test_helper_test.rb b/actionmailer/test/test_helper_test.rb
index 7c7f0b6fdc..1ff08a3b6e 100644
--- a/actionmailer/test/test_helper_test.rb
+++ b/actionmailer/test/test_helper_test.rb
@@ -1,3 +1,4 @@
+# encoding: utf-8
require 'abstract_unit'
class TestHelperMailer < ActionMailer::Base
@@ -36,6 +37,14 @@ class TestHelperMailerTest < ActionMailer::TestCase
assert_equal "UTF-8", charset
end
+ def test_encode
+ assert_equal '=?UTF-8?Q?This_is_=E3=81=82_string?=', encode('This is あ string')
+ end
+
+ def test_read_fixture
+ assert_equal ['Welcome!'], read_fixture('welcome')
+ end
+
def test_assert_emails
assert_nothing_raised do
assert_emails 1 do