diff options
Diffstat (limited to 'actionmailer')
58 files changed, 1392 insertions, 1094 deletions
diff --git a/actionmailer/CHANGELOG.md b/actionmailer/CHANGELOG.md index 1659696bfb..86ecb3ee88 100644 --- a/actionmailer/CHANGELOG.md +++ b/actionmailer/CHANGELOG.md @@ -1,7 +1,56 @@ -* invoke mailer defaults as procs only if they are procs, do not convert - with to_proc. That an object is convertible to a proc does not mean it's - meant to be always used as a proc. Fixes #11533 +* Add `assert_enqueued_emails` and `assert_no_enqueued_emails`. - *Alex Tsukernik* + Example: -Please check [4-0-stable](https://github.com/rails/rails/blob/4-0-stable/actionmailer/CHANGELOG.md) for previous changes. + def test_emails + assert_enqueued_emails 2 do + ContactMailer.welcome.deliver_later + ContactMailer.welcome.deliver_later + end + end + + def test_no_emails + assert_no_enqueued_emails do + # No emails enqueued here + end + end + + *George Claghorn* + +* Add `_mailer` suffix to mailers created via generator, following the same + naming convention used in controllers and jobs. + + *Carlos Souza* + +* Remove deprecate `*_path` helpers in email views. + + *Rafael Mendonça França* + +* Remove deprecated `deliver` and `deliver!` methods. + + *claudiob* + +* Template lookup now respects default locale and I18n fallbacks. + + Given the following templates: + + mailer/demo.html.erb + mailer/demo.en.html.erb + mailer/demo.pt.html.erb + + Before this change, for a locale that doesn't have its associated file, the + `mailer/demo.html.erb` would be rendered even if `en` was the default locale. + + Now `mailer/demo.en.html.erb` has precedence over the file without locale. + + Also, it is possible to give a fallback. + + mailer/demo.pt.html.erb + mailer/demo.pt-BR.html.erb + + So if the locale is `pt-PT`, `mailer/demo.pt.html.erb` will be rendered given + the right I18n fallback configuration. + + *Rafael Mendonça França* + +Please check [4-2-stable](https://github.com/rails/rails/blob/4-2-stable/actionmailer/CHANGELOG.md) for previous changes. diff --git a/actionmailer/MIT-LICENSE b/actionmailer/MIT-LICENSE index 5c668d9624..3ec7a617cf 100644 --- a/actionmailer/MIT-LICENSE +++ b/actionmailer/MIT-LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2013 David Heinemeier Hansson +Copyright (c) 2004-2015 David Heinemeier Hansson Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the diff --git a/actionmailer/README.rdoc b/actionmailer/README.rdoc index a14a6ba18f..a4e660d621 100644 --- a/actionmailer/README.rdoc +++ b/actionmailer/README.rdoc @@ -61,24 +61,30 @@ generated would look like this: Thank you for signing up! -In previous version of Rails you would call <tt>create_method_name</tt> and -<tt>deliver_method_name</tt>. Rails 3.0 has a much simpler interface - you -simply call the method and optionally call +deliver+ on the return value. +In order to send mails, you simply call the method and then call +deliver_now+ on the return value. Calling the method returns a Mail Message object: - message = Notifier.welcome("david@loudthinking.com") # => Returns a Mail::Message object - message.deliver # => delivers the email + message = Notifier.welcome("david@loudthinking.com") # => Returns a Mail::Message object + message.deliver_now # => delivers the email Or you can just chain the methods together like: - Notifier.welcome("david@loudthinking.com").deliver # Creates the email and sends it immediately + Notifier.welcome("david@loudthinking.com").deliver_now # Creates the email and sends it immediately == Setting defaults -It is possible to set default values that will be used in every method in your Action Mailer class. To implement this functionality, you just call the public class method <tt>default</tt> which you get for free from ActionMailer::Base. This method accepts a Hash as the parameter. You can use any of the headers e-mail messages has, like <tt>:from</tt> as the key. You can also pass in a string as the key, like "Content-Type", but Action Mailer does this out of the box for you, so you won't need to worry about that. Finally, it is also possible to pass in a Proc that will get evaluated when it is needed. +It is possible to set default values that will be used in every method in your +Action Mailer class. To implement this functionality, you just call the public +class method +default+ which you get for free from <tt>ActionMailer::Base</tt>. +This method accepts a Hash as the parameter. You can use any of the headers, +email messages have, like +:from+ as the key. You can also pass in a string as +the key, like "Content-Type", but Action Mailer does this out of the box for you, +so you won't need to worry about that. Finally, it is also possible to pass in a +Proc that will get evaluated when it is needed. -Note that every value you set with this method will get overwritten if you use the same key in your mailer method. +Note that every value you set with this method will get overwritten if you use the +same key in your mailer method. Example: @@ -89,10 +95,11 @@ Example: == Receiving emails -To receive emails, you need to implement a public instance method called <tt>receive</tt> that takes an -email object as its single parameter. The Action Mailer framework has a corresponding class method, -which is also called <tt>receive</tt>, that accepts a raw, unprocessed email as a string, which it then turns -into the email object and calls the receive instance method. +To receive emails, you need to implement a public instance method called ++receive+ that takes an email object as its single parameter. The Action Mailer +framework has a corresponding class method, which is also called +receive+, that +accepts a raw, unprocessed email as a string, which it then turns into the email +object and calls the receive instance method. Example: @@ -104,7 +111,7 @@ Example: ) if email.has_attachments? - email.attachments.each do |attachment| + email.attachments.each do |attachment| page.attachments.create({ file: attachment, description: email.subject }) @@ -113,13 +120,14 @@ Example: end end -This Mailman can be the target for Postfix or other MTAs. In Rails, you would use the runner in the -trivial case like this: +This Mailman can be the target for Postfix or other MTAs. In Rails, you would use +the runner in the trivial case like this: rails runner 'Mailman.receive(STDIN.read)' -However, invoking Rails in the runner for each mail to be received is very resource intensive. A single -instance of Rails should be run within a daemon, if it is going to process more than just a limited amount of email. +However, invoking Rails in the runner for each mail to be received is very +resource intensive. A single instance of Rails should be run within a daemon, if +it is going to process more than just a limited amount of email. == Configuration @@ -158,7 +166,11 @@ API documentation is at * http://api.rubyonrails.org -Bug reports and feature requests can be filed with the rest for the Ruby on Rails project here: +Bug reports can be filed for the Ruby on Rails project here: * https://github.com/rails/rails/issues +Feature requests should be discussed on the rails-core mailing list here: + +* https://groups.google.com/forum/?fromgroups#!forum/rubyonrails-core + diff --git a/actionmailer/Rakefile b/actionmailer/Rakefile index 5ddd90020b..8f4de8fafa 100644 --- a/actionmailer/Rakefile +++ b/actionmailer/Rakefile @@ -10,6 +10,7 @@ Rake::TestTask.new { |t| t.pattern = 'test/**/*_test.rb' t.warning = true t.verbose = true + t.ruby_opts = ["--dev"] if defined?(JRUBY_VERSION) } namespace :test do diff --git a/actionmailer/actionmailer.gemspec b/actionmailer/actionmailer.gemspec index 9b25feaf75..513c217733 100644 --- a/actionmailer/actionmailer.gemspec +++ b/actionmailer/actionmailer.gemspec @@ -7,7 +7,7 @@ Gem::Specification.new do |s| s.summary = 'Email composition, delivery, and receiving framework (part of Rails).' s.description = 'Email on Rails. Compose, deliver, receive, and test emails using the familiar controller/view pattern. First-class support for multipart email and attachments.' - s.required_ruby_version = '>= 1.9.3' + s.required_ruby_version = '>= 2.2.0' s.license = 'MIT' @@ -21,6 +21,8 @@ Gem::Specification.new do |s| s.add_dependency 'actionpack', version s.add_dependency 'actionview', version + s.add_dependency 'activejob', version - s.add_dependency 'mail', '~> 2.5.4' + s.add_dependency 'mail', ['~> 2.5', '>= 2.5.4'] + s.add_dependency 'rails-dom-testing', '~> 1.0', '>= 1.0.5' end diff --git a/actionmailer/lib/action_mailer.rb b/actionmailer/lib/action_mailer.rb index 5b6960c8fc..17d8dcc208 100644 --- a/actionmailer/lib/action_mailer.rb +++ b/actionmailer/lib/action_mailer.rb @@ -1,5 +1,5 @@ #-- -# Copyright (c) 2004-2013 David Heinemeier Hansson +# Copyright (c) 2004-2015 David Heinemeier Hansson # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -41,6 +41,10 @@ module ActionMailer autoload :Base autoload :DeliveryMethods autoload :MailHelper + autoload :Preview + autoload :Previews, 'action_mailer/preview' autoload :TestCase autoload :TestHelper + autoload :MessageDelivery + autoload :DeliveryJob end diff --git a/actionmailer/lib/action_mailer/base.rb b/actionmailer/lib/action_mailer/base.rb index 9dcd4bf554..7eae76f93b 100644 --- a/actionmailer/lib/action_mailer/base.rb +++ b/actionmailer/lib/action_mailer/base.rb @@ -15,11 +15,17 @@ module ActionMailer # # $ rails generate mailer Notifier # - # The generated model inherits from <tt>ActionMailer::Base</tt>. A mailer model defines methods + # The generated model inherits from <tt>ApplicationMailer</tt> which in turn + # inherits from <tt>ActionMailer::Base</tt>. A mailer model defines methods # used to generate an email message. In these methods, you can setup variables to be used in # the mailer views, options on the mail itself such as the <tt>:from</tt> address, and attachments. # - # class Notifier < ActionMailer::Base + # class ApplicationMailer < ActionMailer::Base + # default from: 'from@exmaple.com' + # layout 'mailer' + # end + # + # class Notifier < ApplicationMailer # default from: 'no-reply@example.com', # return_path: 'system@example.com' # @@ -39,23 +45,20 @@ module ActionMailer # in the same manner as <tt>attachments[]=</tt> # # * <tt>headers[]=</tt> - Allows you to specify any header field in your email such - # as <tt>headers['X-No-Spam'] = 'True'</tt>. Note, while most fields like <tt>To:</tt> - # <tt>From:</tt> can only appear once in an email header, other fields like <tt>X-Anything</tt> - # can appear multiple times. If you want to change a field that can appear multiple times, - # you need to set it to nil first so that Mail knows you are replacing it and not adding - # another field of the same name. + # as <tt>headers['X-No-Spam'] = 'True'</tt>. Note that declaring a header multiple times + # will add many fields of the same name. Read #headers doc for more information. # # * <tt>headers(hash)</tt> - Allows you to specify multiple headers in your email such # as <tt>headers({'X-No-Spam' => 'True', 'In-Reply-To' => '1234@message.id'})</tt> # # * <tt>mail</tt> - Allows you to specify email to be sent. # - # The hash passed to the mail method allows you to specify any header that a Mail::Message - # will accept (any valid Email header including optional fields). + # The hash passed to the mail method allows you to specify any header that a <tt>Mail::Message</tt> + # will accept (any valid email header including optional fields). # # The mail method, if not passed a block, will inspect your views and send all the views with # the same name as the method, so the above action would send the +welcome.text.erb+ view - # file as well as the +welcome.text.html.erb+ view file in a +multipart/alternative+ email. + # file as well as the +welcome.html.erb+ view file in a +multipart/alternative+ email. # # If you want to explicitly render only certain templates, pass a block: # @@ -87,14 +90,15 @@ module ActionMailer # name as the method in your mailer model. For example, in the mailer defined above, the template at # <tt>app/views/notifier/welcome.text.erb</tt> would be used to generate the email. # - # Variables defined in the model are accessible as instance variables in the view. + # Variables defined in the methods of your mailer model are accessible as instance variables in their + # corresponding view. # # Emails by default are sent in plain text, so a sample view for our model example might look like this: # # Hi <%= @account.name %>, # Thanks for joining our service! Please check back often. # - # You can even use Action Pack helpers in these views. For example: + # You can even use Action View helpers in these views. For example: # # You got a new note! # <%= truncate(@note.body, length: 25) %> @@ -128,19 +132,25 @@ module ActionMailer # # config.action_mailer.default_url_options = { host: "example.com" } # - # When you decide to set a default <tt>:host</tt> for your mailers, then you need to make sure to use the - # <tt>only_path: false</tt> option when using <tt>url_for</tt>. Since the <tt>url_for</tt> view helper - # will generate relative URLs by default when a <tt>:host</tt> option isn't explicitly provided, passing - # <tt>only_path: false</tt> will ensure that absolute URLs are generated. - # # = Sending mail # # Once a mailer action and template are defined, you can deliver your message or create it and save it # for delivery later: # - # Notifier.welcome(david).deliver # sends the email - # mail = Notifier.welcome(david) # => a Mail::Message object - # mail.deliver # sends the email + # Notifier.welcome(User.first).deliver_now # sends the email + # mail = Notifier.welcome(User.first) # => an ActionMailer::MessageDelivery object + # mail.deliver_now # sends the email + # + # The <tt>ActionMailer::MessageDelivery</tt> class is a wrapper around a <tt>Mail::Message</tt> object. If + # you want direct access to the <tt>Mail::Message</tt> object you can call the <tt>message</tt> method on + # the <tt>ActionMailer::MessageDelivery</tt> object. + # + # Notifier.welcome(User.first).message # => a Mail::Message object + # + # Action Mailer is nicely integrated with Active Job so you can send emails in the background (example: outside + # of the request-response cycle, so the user doesn't have to wait on it): + # + # Notifier.welcome(User.first).deliver_later # enqueue the email sending to Active Job # # You never instantiate your mailer class. Rather, you just call the method you defined on the class itself. # @@ -154,7 +164,7 @@ module ActionMailer # * signup_notification.text.erb # * signup_notification.html.erb # * signup_notification.xml.builder - # * signup_notification.yaml.erb + # * signup_notification.yml.erb # # Each would be rendered and added as a separate part to the message, with the corresponding content # type. The content type for the entire message is automatically set to <tt>multipart/alternative</tt>, @@ -169,7 +179,7 @@ module ActionMailer # # Sending attachment in emails is easy: # - # class ApplicationMailer < ActionMailer::Base + # class Notifier < ApplicationMailer # def welcome(recipient) # attachments['free_book.pdf'] = File.read('path/to/file.pdf') # mail(to: recipient, subject: "New account information") @@ -185,7 +195,7 @@ module ActionMailer # If you need to send attachments with no content, you need to create an empty view for it, # or add an empty body parameter like this: # - # class ApplicationMailer < ActionMailer::Base + # class Notifier < ApplicationMailer # def welcome(recipient) # attachments['free_book.pdf'] = File.read('path/to/file.pdf') # mail(to: recipient, subject: "New account information", body: "") @@ -197,7 +207,7 @@ module ActionMailer # You can also specify that a file should be displayed inline with other HTML. This is useful # if you want to display a corporate logo or a photo. # - # class ApplicationMailer < ActionMailer::Base + # class Notifier < ApplicationMailer # def welcome(recipient) # attachments.inline['photo.png'] = File.read('path/to/photo.png') # mail(to: recipient, subject: "Here is what we look like") @@ -229,14 +239,14 @@ module ActionMailer # An interceptor class must implement the <tt>:delivering_email(message)</tt> method which will be # called before the email is sent, allowing you to make modifications to the email before it hits # the delivery agents. Your class should make any needed modifications directly to the passed - # in Mail::Message instance. + # in <tt>Mail::Message</tt> instance. # # = Default Hash # # Action Mailer provides some intelligent defaults for your emails, these are usually specified in a # default method inside the class definition: # - # class Notifier < ActionMailer::Base + # class Notifier < ApplicationMailer # default sender: 'system@example.com' # end # @@ -254,7 +264,7 @@ module ActionMailer # As you can pass in any header, you need to either quote the header as a string, or pass it in as # an underscored symbol, so the following will work: # - # class Notifier < ActionMailer::Base + # class Notifier < ApplicationMailer # default 'Content-Transfer-Encoding' => '7bit', # content_description: 'This is a description' # end @@ -262,7 +272,7 @@ module ActionMailer # Finally, Action Mailer also supports passing <tt>Proc</tt> objects into the default hash, so you # can define methods that evaluate as the message is being generated: # - # class Notifier < ActionMailer::Base + # class Notifier < ApplicationMailer # default 'X-Special-Header' => Proc.new { my_method } # # private @@ -287,7 +297,7 @@ module ActionMailer # This may be useful, for example, when you want to add default inline attachments for all # messages sent out by a certain mailer class: # - # class Notifier < ActionMailer::Base + # class Notifier < ApplicationMailer # before_action :add_inline_attachment! # # def welcome @@ -301,12 +311,50 @@ module ActionMailer # end # end # - # Callbacks in ActionMailer are implemented using AbstractController::Callbacks, so you - # can define and configure callbacks in the same manner that you would use callbacks in - # classes that inherit from ActionController::Base. + # Callbacks in Action Mailer are implemented using + # <tt>AbstractController::Callbacks</tt>, so you can define and configure + # callbacks in the same manner that you would use callbacks in classes that + # inherit from <tt>ActionController::Base</tt>. # # Note that unless you have a specific reason to do so, you should prefer using before_action - # rather than after_action in your ActionMailer classes so that headers are parsed properly. + # rather than after_action in your Action Mailer classes so that headers are parsed properly. + # + # = Previewing emails + # + # You can preview your email templates visually by adding a mailer preview file to the + # <tt>ActionMailer::Base.preview_path</tt>. Since most emails do something interesting + # with database data, you'll need to write some scenarios to load messages with fake data: + # + # class NotifierPreview < ActionMailer::Preview + # def welcome + # Notifier.welcome(User.first) + # end + # end + # + # Methods must return a <tt>Mail::Message</tt> object which can be generated by calling the mailer + # method without the additional <tt>deliver_now</tt> / <tt>deliver_later</tt>. The location of the + # mailer previews directory can be configured using the <tt>preview_path</tt> option which has a default + # of <tt>test/mailers/previews</tt>: + # + # config.action_mailer.preview_path = "#{Rails.root}/lib/mailer_previews" + # + # An overview of all previews is accessible at <tt>http://localhost:3000/rails/mailers</tt> + # on a running development server instance. + # + # Previews can also be intercepted in a similar manner as deliveries can be by registering + # a preview interceptor that has a <tt>previewing_email</tt> method: + # + # class CssInlineStyler + # def self.previewing_email(message) + # # inline CSS styles + # end + # end + # + # config.action_mailer.preview_interceptors :css_inline_styler + # + # Note that interceptors need to be registered both with <tt>register_interceptor</tt> + # and <tt>register_preview_interceptor</tt> if they should operate on both sending and + # previewing emails. # # = Configuration options # @@ -317,7 +365,7 @@ module ActionMailer # per the above section. # # * <tt>logger</tt> - the logger is used for generating information on the mailing run if available. - # Can be set to nil for no logging. Compatible with both Ruby's own Logger and Log4r loggers. + # Can be set to +nil+ for no logging. Compatible with both Ruby's own +Logger+ and Log4r loggers. # # * <tt>smtp_settings</tt> - Allows detailed configuration for <tt>:smtp</tt> delivery method: # * <tt>:address</tt> - Allows you to use a remote mail server. Just change it from its default @@ -331,12 +379,13 @@ module ActionMailer # This is a symbol and one of <tt>:plain</tt> (will send the password in the clear), <tt>:login</tt> (will # send password Base64 encoded) or <tt>:cram_md5</tt> (combines a Challenge/Response mechanism to exchange # information and a cryptographic Message Digest 5 algorithm to hash important information) - # * <tt>:enable_starttls_auto</tt> - When set to true, detects if STARTTLS is enabled in your SMTP server - # and starts to use it. + # * <tt>:enable_starttls_auto</tt> - Detects if STARTTLS is enabled in your SMTP server and starts + # to use it. Defaults to <tt>true</tt>. # * <tt>:openssl_verify_mode</tt> - When using TLS, you can set how OpenSSL checks the certificate. This is # really useful if you need to validate a self-signed and/or a wildcard certificate. You can use the name - # of an OpenSSL verify constant ('none', 'peer', 'client_once', 'fail_if_no_peer_cert') or directly the - # constant (OpenSSL::SSL::VERIFY_NONE, OpenSSL::SSL::VERIFY_PEER, ...). + # of an OpenSSL verify constant (<tt>'none'</tt>, <tt>'peer'</tt>, <tt>'client_once'</tt>, + # <tt>'fail_if_no_peer_cert'</tt>) or directly the constant (<tt>OpenSSL::SSL::VERIFY_NONE</tt>, + # <tt>OpenSSL::SSL::VERIFY_PEER</tt>, ...). # # * <tt>sendmail_settings</tt> - Allows you to override options for the <tt>:sendmail</tt> delivery method. # * <tt>:location</tt> - The location of the sendmail executable. Defaults to <tt>/usr/sbin/sendmail</tt>. @@ -351,17 +400,18 @@ module ActionMailer # # * <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>. Or you may provide a custom delivery method - # object e.g. MyOwnDeliveryMethodClass. See the Mail gem documentation on the interface you need to + # object e.g. +MyOwnDeliveryMethodClass+. See the Mail gem documentation on the interface you need to # 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 # <tt>delivery_method :test</tt>. Most useful for unit and functional testing. class Base < AbstractController::Base include DeliveryMethods + include Previews abstract! @@ -373,6 +423,14 @@ module ActionMailer include AbstractController::AssetPaths include AbstractController::Callbacks + include ActionView::Layouts + + PROTECTED_IVARS = AbstractController::Rendering::DEFAULT_PROTECTED_INSTANCE_VARIABLES + [:@_action_has_layout] + + def _protected_ivars # :nodoc: + PROTECTED_IVARS + end + helper ActionMailer::MailHelper private_class_method :new #:nodoc: @@ -385,10 +443,6 @@ module ActionMailer parts_order: [ "text/plain", "text/enriched", "text/html" ] }.freeze - def self.default_protected_instance_vars - super.concat [:@_action_has_layout] - end - class << self # Register one or more Observers which will be notified when mail is delivered. def register_observers(*observers) @@ -401,18 +455,30 @@ module ActionMailer end # Register an Observer which will be notified when mail is delivered. - # Either a class or a string can be passed in as the Observer. If a string is passed in - # it will be +constantize+d. + # Either a class, string or symbol can be passed in as the Observer. + # If a string or symbol is passed in it will be camelized and constantized. def register_observer(observer) - delivery_observer = (observer.is_a?(String) ? observer.constantize : observer) + delivery_observer = case observer + when String, Symbol + observer.to_s.camelize.constantize + else + observer + end + Mail.register_observer(delivery_observer) end # Register an Interceptor which will be called before mail is sent. - # Either a class or a string can be passed in as the Interceptor. If a string is passed in - # it will be <tt>constantize</tt>d. + # Either a class, string or symbol can be passed in as the Interceptor. + # If a string or symbol is passed in it will be camelized and constantized. def register_interceptor(interceptor) - delivery_interceptor = (interceptor.is_a?(String) ? interceptor.constantize : interceptor) + delivery_interceptor = case interceptor + when String, Symbol + interceptor.to_s.camelize.constantize + else + interceptor + end + Mail.register_interceptor(delivery_interceptor) end @@ -427,7 +493,7 @@ module ActionMailer # Sets the defaults through app configuration: # - # config.action_mailer.default { from: "no-reply@example.org" } + # config.action_mailer.default(from: "no-reply@example.org") # # Aliased by ::default_options= def default(value = nil) @@ -460,11 +526,11 @@ module ActionMailer end end - # Wraps an email delivery inside of ActiveSupport::Notifications instrumentation. + # Wraps an email delivery inside of <tt>ActiveSupport::Notifications</tt> instrumentation. # - # This method is actually called by the Mail::Message object itself - # through a callback when you call +:deliver+ on the Mail::Message, - # calling +deliver_mail+ directly and passing a Mail::Message will do + # This method is actually called by the <tt>Mail::Message</tt> object itself + # through a callback when you call <tt>:deliver</tt> on the <tt>Mail::Message</tt>, + # calling +deliver_mail+ directly and passing a <tt>Mail::Message</tt> will do # nothing except tell the logger you sent the email. def deliver_mail(mail) #:nodoc: ActiveSupport::Notifications.instrument("deliver.action_mailer") do |payload| @@ -492,8 +558,8 @@ module ActionMailer end def method_missing(method_name, *args) # :nodoc: - if respond_to?(method_name) - new(method_name, *args).message + if action_methods.include?(method_name.to_s) + MessageDelivery.new(self, method_name, *args) else super end @@ -513,16 +579,25 @@ module ActionMailer process(method_name, *args) if method_name end - def process(*args) #:nodoc: - lookup_context.skip_default_locale! + def process(method_name, *args) #:nodoc: + payload = { + mailer: self.class.name, + action: method_name + } - super - @_message = NullMail.new unless @_mail_was_called + ActiveSupport::Notifications.instrument("process.action_mailer", payload) do + super + @_message = NullMail.new unless @_mail_was_called + end end class NullMail #:nodoc: def body; '' end + def respond_to?(string, include_all=false) + true + end + def method_missing(*args) nil end @@ -533,20 +608,40 @@ module ActionMailer self.class.mailer_name end - # Allows you to pass random and unusual headers to the new Mail::Message + # Allows you to pass random and unusual headers to the new <tt>Mail::Message</tt> # object which will add them to itself. # # headers['X-Special-Domain-Specific-Header'] = "SecretValue" # # You can also pass a hash into headers of header field names and values, - # which will then be set on the Mail::Message object: + # which will then be set on the <tt>Mail::Message</tt> object: # # headers 'X-Special-Domain-Specific-Header' => "SecretValue", # 'In-Reply-To' => incoming.message_id # - # The resulting Mail::Message will have the following in its header: + # The resulting <tt>Mail::Message</tt> will have the following in its header: # # X-Special-Domain-Specific-Header: SecretValue + # + # Note about replacing already defined headers: + # + # * +subject+ + # * +sender+ + # * +from+ + # * +to+ + # * +cc+ + # * +bcc+ + # * +reply-to+ + # * +orig-date+ + # * +message-id+ + # * +references+ + # + # Fields can only appear once in email headers while other fields such as + # <tt>X-Anything</tt> can appear multiple times. + # + # If you want to replace any header which already exists, first set it to + # +nil+ in order to reset the value otherwise another field will be added + # for the same header. def headers(args = nil) if args @_message.headers(args) @@ -586,14 +681,29 @@ 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 # two ways to call this method, with a block, or without a block. # - # Both methods accept a headers hash. This hash allows you to specify the most used headers - # in an email message, these are: + # It accepts a headers hash. This hash allows you to specify + # the most used headers in an email message, these are: # # * +:subject+ - The subject of the message, if this is omitted, Action Mailer will # ask the Rails I18n class for a translated +:subject+ in the scope of @@ -633,13 +743,13 @@ module ActionMailer # templates in the view paths using by default the mailer name and the # method name that it is being called from, it will then create parts for # each of these templates intelligently, making educated guesses on correct - # content type and sequence, and return a fully prepared Mail::Message - # ready to call +:deliver+ on to send. + # content type and sequence, and return a fully prepared <tt>Mail::Message</tt> + # ready to call <tt>:deliver</tt> on to send. # # For example: # # class Notifier < ActionMailer::Base - # default from: 'no-reply@test.lindsaar.net', + # default from: 'no-reply@test.lindsaar.net' # # def welcome # mail(to: 'mikel@test.lindsaar.net') @@ -662,11 +772,11 @@ module ActionMailer # format.html # end # - # You can even render text directly without using a template: + # You can even render plain text directly without using a template: # # mail(to: 'mikel@test.lindsaar.net') do |format| - # format.text { render text: "Hello Mikel!" } - # format.html { render text: "<h1>Hello Mikel!</h1>" } + # format.text { render plain: "Hello Mikel!" } + # format.html { render html: "<h1>Hello Mikel!</h1>".html_safe } # end # # Which will render a +multipart/alternative+ email with +text/plain+ and @@ -680,16 +790,17 @@ module ActionMailer # end # def mail(headers = {}, &block) - @_mail_was_called = true + return @_message if @_mail_was_called && headers.blank? && !block + m = @_message # At the beginning, do not consider class default for content_type content_type = headers[:content_type] # Call all the procs (if any) - class_default = self.class.default - default_values = class_default.merge(class_default) do |k,v| - v.is_a?(Proc) ? instance_eval(&v) : v + default_values = {} + self.class.default.each do |k,v| + default_values[k] = v.is_a?(Proc) ? instance_eval(&v) : v end # Handle defaults @@ -700,7 +811,7 @@ module ActionMailer m.charset = charset = headers[:charset] # Set configure delivery behavior - wrap_delivery_behavior!(headers.delete(:delivery_method),headers.delete(:delivery_method_options)) + wrap_delivery_behavior!(headers.delete(:delivery_method), headers.delete(:delivery_method_options)) # Assign all headers except parts_order, content_type and body assignable = headers.except(:parts_order, :content_type, :body, :template_name, :template_path) @@ -708,6 +819,8 @@ module ActionMailer # Render the templates and blocks responses = collect_responses(headers, &block) + @_mail_was_called = true + create_parts_from_responses(m, responses) # Setup content type, reapply charset and handle parts order @@ -739,7 +852,7 @@ module ActionMailer when user_content_type.present? user_content_type when m.has_attachments? - if m.attachments.detect { |a| a.inline? } + if m.attachments.detect(&:inline?) ["multipart", "related", params] else ["multipart", "mixed", params] @@ -794,7 +907,7 @@ module ActionMailer if templates.empty? raise ActionView::MissingTemplate.new(paths, name, paths, false, 'mailer') else - templates.uniq { |t| t.formats }.each(&block) + templates.uniq(&:formats).each(&block) end end @@ -817,6 +930,11 @@ module ActionMailer container.add_part(part) end + # Emails do not support relative path links. + def self.supports_path? + false + end + ActiveSupport.run_load_hooks(:action_mailer, self) end end diff --git a/actionmailer/lib/action_mailer/delivery_job.rb b/actionmailer/lib/action_mailer/delivery_job.rb new file mode 100644 index 0000000000..e864ab7a4d --- /dev/null +++ b/actionmailer/lib/action_mailer/delivery_job.rb @@ -0,0 +1,13 @@ +require 'active_job' + +module ActionMailer + # The <tt>ActionMailer::DeliveryJob</tt> class is used when you + # want to send emails outside of the request-response cycle. + class DeliveryJob < ActiveJob::Base # :nodoc: + queue_as :mailers + + def perform(mailer, mail_method, delivery_method, *args) #:nodoc: + mailer.constantize.public_send(mail_method, *args).send(delivery_method) + end + end +end diff --git a/actionmailer/lib/action_mailer/delivery_methods.rb b/actionmailer/lib/action_mailer/delivery_methods.rb index 9a1a27c8ed..aedcd81e52 100644 --- a/actionmailer/lib/action_mailer/delivery_methods.rb +++ b/actionmailer/lib/action_mailer/delivery_methods.rb @@ -64,7 +64,7 @@ module ActionMailer raise "Delivery method cannot be nil" when Symbol if klass = delivery_methods[method] - mail.delivery_method(klass,(send(:"#{method}_settings") || {}).merge!(options || {})) + mail.delivery_method(klass, (send(:"#{method}_settings") || {}).merge(options || {})) else raise "Invalid delivery method #{method.inspect}" end diff --git a/actionmailer/lib/action_mailer/gem_version.rb b/actionmailer/lib/action_mailer/gem_version.rb new file mode 100644 index 0000000000..ac79788cf0 --- /dev/null +++ b/actionmailer/lib/action_mailer/gem_version.rb @@ -0,0 +1,15 @@ +module ActionMailer + # Returns the version of the currently loaded Action Mailer as a <tt>Gem::Version</tt> + def self.gem_version + Gem::Version.new VERSION::STRING + end + + module VERSION + MAJOR = 5 + MINOR = 0 + TINY = 0 + PRE = "alpha" + + STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".") + end +end diff --git a/actionmailer/lib/action_mailer/log_subscriber.rb b/actionmailer/lib/action_mailer/log_subscriber.rb index 8467d45986..5b57c75ec3 100644 --- a/actionmailer/lib/action_mailer/log_subscriber.rb +++ b/actionmailer/lib/action_mailer/log_subscriber.rb @@ -6,17 +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) + 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/mail_helper.rb b/actionmailer/lib/action_mailer/mail_helper.rb index 54ad9f066f..cc7935a7e0 100644 --- a/actionmailer/lib/action_mailer/mail_helper.rb +++ b/actionmailer/lib/action_mailer/mail_helper.rb @@ -11,8 +11,8 @@ module ActionMailer }.join("\n\n") # Make list points stand on their own line - formatted.gsub!(/[ ]*([*]+) ([^*]*)/) { |s| " #{$1} #{$2.strip}\n" } - formatted.gsub!(/[ ]*([#]+) ([^#]*)/) { |s| " #{$1} #{$2.strip}\n" } + formatted.gsub!(/[ ]*([*]+) ([^*]*)/) { " #{$1} #{$2.strip}\n" } + formatted.gsub!(/[ ]*([#]+) ([^#]*)/) { " #{$1} #{$2.strip}\n" } formatted end @@ -29,7 +29,7 @@ module ActionMailer # Access the message attachments list. def attachments - @_message.attachments + mailer.attachments end # Returns +text+ wrapped at +len+ columns and indented +indent+ spaces. diff --git a/actionmailer/lib/action_mailer/message_delivery.rb b/actionmailer/lib/action_mailer/message_delivery.rb new file mode 100644 index 0000000000..ff2cb0fd01 --- /dev/null +++ b/actionmailer/lib/action_mailer/message_delivery.rb @@ -0,0 +1,94 @@ +require 'delegate' + +module ActionMailer + + # The <tt>ActionMailer::MessageDelivery</tt> class is used by + # <tt>ActionMailer::Base</tt> when creating a new mailer. + # <tt>MessageDelivery</tt> is a wrapper (+Delegator+ subclass) around a lazy + # created <tt>Mail::Message</tt>. You can get direct access to the + # <tt>Mail::Message</tt>, deliver the email or schedule the email to be sent + # through Active Job. + # + # Notifier.welcome(User.first) # an ActionMailer::MessageDelivery object + # Notifier.welcome(User.first).deliver_now # sends the email + # Notifier.welcome(User.first).deliver_later # enqueue email delivery as a job through Active Job + # Notifier.welcome(User.first).message # a Mail::Message object + class MessageDelivery < Delegator + def initialize(mailer, mail_method, *args) #:nodoc: + @mailer = mailer + @mail_method = mail_method + @args = args + end + + def __getobj__ #:nodoc: + @obj ||= @mailer.send(:new, @mail_method, *@args).message + end + + def __setobj__(obj) #:nodoc: + @obj = obj + end + + # Returns the Mail::Message object + def message + __getobj__ + end + + # Enqueues the email to be delivered through Active Job. When the + # job runs it will send the email using +deliver_now!+. That means + # that the message will be sent bypassing checking +perform_deliveries+ + # and +raise_delivery_errors+, so use with caution. + # + # Notifier.welcome(User.first).deliver_later! + # Notifier.welcome(User.first).deliver_later!(wait: 1.hour) + # Notifier.welcome(User.first).deliver_later!(wait_until: 10.hours.from_now) + # + # Options: + # + # * <tt>:wait</tt> - Enqueue the email to be delivered with a delay + # * <tt>:wait_until</tt> - Enqueue the email to be delivered at (after) a specific date / time + # * <tt>:queue</tt> - Enqueue the email on the specified queue + def deliver_later!(options={}) + enqueue_delivery :deliver_now!, options + end + + # Enqueues the email to be delivered through Active Job. When the + # job runs it will send the email using +deliver_now+. + # + # Notifier.welcome(User.first).deliver_later + # Notifier.welcome(User.first).deliver_later(wait: 1.hour) + # Notifier.welcome(User.first).deliver_later(wait_until: 10.hours.from_now) + # + # Options: + # + # * <tt>:wait</tt> - Enqueue the email to be delivered with a delay + # * <tt>:wait_until</tt> - Enqueue the email to be delivered at (after) a specific date / time + # * <tt>:queue</tt> - Enqueue the email on the specified queue + def deliver_later(options={}) + enqueue_delivery :deliver_now, options + end + + # Delivers an email without checking +perform_deliveries+ and +raise_delivery_errors+, + # so use with caution. + # + # Notifier.welcome(User.first).deliver_now! + # + def deliver_now! + message.deliver! + end + + # Delivers an email: + # + # Notifier.welcome(User.first).deliver_now + # + def deliver_now + message.deliver + end + + private + + def enqueue_delivery(delivery_method, options={}) + args = @mailer.name, @mail_method.to_s, delivery_method.to_s, *@args + ActionMailer::DeliveryJob.set(options).perform_later(*args) + end + end +end diff --git a/actionmailer/lib/action_mailer/preview.rb b/actionmailer/lib/action_mailer/preview.rb new file mode 100644 index 0000000000..44cf6665ba --- /dev/null +++ b/actionmailer/lib/action_mailer/preview.rb @@ -0,0 +1,118 @@ +require 'active_support/descendants_tracker' + +module ActionMailer + module Previews #:nodoc: + extend ActiveSupport::Concern + + included do + # Set the location of mailer previews through app configuration: + # + # config.action_mailer.preview_path = "#{Rails.root}/lib/mailer_previews" + # + 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 = [] + end + + module ClassMethods + # Register one or more Interceptors which will be called before mail is previewed. + def register_preview_interceptors(*interceptors) + interceptors.flatten.compact.each { |interceptor| register_preview_interceptor(interceptor) } + end + + # Register an Interceptor which will be called before mail is previewed. + # Either a class or a string can be passed in as the Interceptor. If a + # string is passed in it will be <tt>constantize</tt>d. + def register_preview_interceptor(interceptor) + preview_interceptor = case interceptor + when String, Symbol + interceptor.to_s.camelize.constantize + else + interceptor + end + + unless preview_interceptors.include?(preview_interceptor) + preview_interceptors << preview_interceptor + end + end + end + end + + class Preview + extend ActiveSupport::DescendantsTracker + + class << self + # Returns all mailer preview classes + def all + load_previews if descendants.empty? + descendants + end + + # Returns the mail object for the given email name. The registered preview + # interceptors will be informed so that they can transform the message + # as they would if the mail was actually being delivered. + def call(email) + preview = self.new + message = preview.public_send(email) + inform_preview_interceptors(message) + message + end + + # Returns all of the available email previews + def emails + public_instance_methods(false).map(&:to_s).sort + end + + # Returns true if the email exists + def email_exists?(email) + emails.include?(email) + end + + # Returns true if the preview exists + def exists?(preview) + all.any?{ |p| p.preview_name == preview } + end + + # Find a mailer preview by its underscored class name + def find(preview) + all.find{ |p| p.preview_name == preview } + end + + # Returns the underscored name of the mailer preview without the suffix + def preview_name + name.sub(/Preview$/, '').underscore + end + + protected + def load_previews #:nodoc: + if preview_path + Dir["#{preview_path}/**/*_preview.rb"].each{ |file| require_dependency file } + end + end + + def preview_path #:nodoc: + 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) + end + end + end + end +end diff --git a/actionmailer/lib/action_mailer/railtie.rb b/actionmailer/lib/action_mailer/railtie.rb index 7677ff3a7c..bebcf4de01 100644 --- a/actionmailer/lib/action_mailer/railtie.rb +++ b/actionmailer/lib/action_mailer/railtie.rb @@ -1,3 +1,4 @@ +require 'active_job/railtie' require "action_mailer" require "rails" require "abstract_controller/railties/routes_helpers" @@ -18,6 +19,11 @@ 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 options.show_previews + options.preview_path ||= defined?(Rails.root) ? "#{Rails.root}/test/mailers/previews" : nil + end # make sure readers methods get compiled options.asset_host ||= app.config.asset_host @@ -25,13 +31,21 @@ module ActionMailer ActiveSupport.on_load(:action_mailer) do include AbstractController::UrlFor - extend ::AbstractController::Railties::RoutesHelpers.with(app.routes) + extend ::AbstractController::Railties::RoutesHelpers.with(app.routes, false) include app.routes.mounted_helpers register_interceptors(options.delete(:interceptors)) + register_preview_interceptors(options.delete(:preview_interceptors)) register_observers(options.delete(:observers)) options.each { |k,v| send("#{k}=", v) } + + if options.show_previews + app.routes.prepend do + get '/rails/mailers' => "rails/mailers#index" + get '/rails/mailers/*path' => "rails/mailers#preview" + end + end end end @@ -40,5 +54,11 @@ module ActionMailer config.compile_methods! if config.respond_to?(:compile_methods!) end end + + config.after_initialize do + if ActionMailer::Base.preview_path + ActiveSupport::Dependencies.autoload_paths << ActionMailer::Base.preview_path + end + end end end diff --git a/actionmailer/lib/action_mailer/test_case.rb b/actionmailer/lib/action_mailer/test_case.rb index 207f949fe2..766215ce96 100644 --- a/actionmailer/lib/action_mailer/test_case.rb +++ b/actionmailer/lib/action_mailer/test_case.rb @@ -1,4 +1,5 @@ require 'active_support/test_case' +require 'rails-dom-testing' module ActionMailer class NonInferrableMailerError < ::StandardError @@ -15,11 +16,14 @@ module ActionMailer include ActiveSupport::Testing::ConstantLookup include TestHelper + include Rails::Dom::Testing::Assertions::SelectorAssertions + include Rails::Dom::Testing::Assertions::DomAssertions included do class_attribute :_mailer_class setup :initialize_test_deliveries setup :set_expected_mail + teardown :restore_test_deliveries end module ClassMethods @@ -54,11 +58,26 @@ module ActionMailer protected def initialize_test_deliveries - ActionMailer::Base.delivery_method = :test + set_delivery_method :test + @old_perform_deliveries = ActionMailer::Base.perform_deliveries ActionMailer::Base.perform_deliveries = true + end + + def restore_test_deliveries + restore_delivery_method + ActionMailer::Base.perform_deliveries = @old_perform_deliveries ActionMailer::Base.deliveries.clear end + def set_delivery_method(method) + @old_delivery_method = ActionMailer::Base.delivery_method + ActionMailer::Base.delivery_method = method + end + + def restore_delivery_method + ActionMailer::Base.delivery_method = @old_delivery_method + end + def set_expected_mail @expected = Mail.new @expected.content_type ["text", "plain", { "charset" => charset }] diff --git a/actionmailer/lib/action_mailer/test_helper.rb b/actionmailer/lib/action_mailer/test_helper.rb index 6452bf616c..524e6e3af1 100644 --- a/actionmailer/lib/action_mailer/test_helper.rb +++ b/actionmailer/lib/action_mailer/test_helper.rb @@ -1,12 +1,18 @@ +require 'active_job' + module ActionMailer + # Provides helper methods for testing Action Mailer, including #assert_emails + # and #assert_no_emails module TestHelper + include ActiveJob::TestHelper + # Asserts that the number of emails sent matches the given number. # # def test_emails # assert_emails 0 - # ContactMailer.welcome.deliver + # ContactMailer.welcome.deliver_now # assert_emails 1 - # ContactMailer.welcome.deliver + # ContactMailer.welcome.deliver_now # assert_emails 2 # end # @@ -15,12 +21,12 @@ module ActionMailer # # def test_emails_again # assert_emails 1 do - # ContactMailer.welcome.deliver + # ContactMailer.welcome.deliver_now # end # # assert_emails 2 do - # ContactMailer.welcome.deliver - # ContactMailer.welcome.deliver + # ContactMailer.welcome.deliver_now + # ContactMailer.welcome.deliver_now # end # end def assert_emails(number) @@ -38,7 +44,7 @@ module ActionMailer # # def test_emails # assert_no_emails - # ContactMailer.welcome.deliver + # ContactMailer.welcome.deliver_now # assert_emails 1 # end # @@ -56,5 +62,52 @@ module ActionMailer def assert_no_emails(&block) assert_emails 0, &block end + + # Asserts that the number of emails enqueued for later delivery matches + # the given number. + # + # def test_emails + # assert_enqueued_emails 0 + # ContactMailer.welcome.deliver_later + # assert_enqueued_emails 1 + # ContactMailer.welcome.deliver_later + # assert_enqueued_emails 2 + # end + # + # If a block is passed, that block should cause the specified number of + # emails to be enqueued. + # + # def test_emails_again + # assert_enqueued_emails 1 do + # ContactMailer.welcome.deliver_later + # end + # + # assert_enqueued_emails 2 do + # ContactMailer.welcome.deliver_later + # ContactMailer.welcome.deliver_later + # end + # end + def assert_enqueued_emails(number, &block) + assert_enqueued_jobs number, only: ActionMailer::DeliveryJob, &block + end + + # Asserts that no emails are enqueued for later delivery. + # + # def test_no_emails + # assert_no_enqueued_emails + # ContactMailer.welcome.deliver_later + # assert_enqueued_emails 1 + # end + # + # If a block is provided, it should not cause any emails to be enqueued. + # + # def test_no_emails + # assert_no_enqueued_emails do + # # No emails should be enqueued from this block + # end + # end + def assert_no_enqueued_emails(&block) + assert_no_enqueued_jobs only: ActionMailer::DeliveryJob, &block + end end end diff --git a/actionmailer/lib/action_mailer/version.rb b/actionmailer/lib/action_mailer/version.rb index 9d00091972..06f80a8fdc 100644 --- a/actionmailer/lib/action_mailer/version.rb +++ b/actionmailer/lib/action_mailer/version.rb @@ -1,11 +1,9 @@ +require_relative 'gem_version' + module ActionMailer - # Returns the version of the currently loaded ActionMailer as a Gem::Version + # Returns the version of the currently loaded Action Mailer as a + # <tt>Gem::Version</tt>. def self.version - Gem::Version.new "4.1.0.beta" - end - - module VERSION #:nodoc: - MAJOR, MINOR, TINY, PRE = ActionMailer.version.segments - STRING = ActionMailer.version.to_s + gem_version end end diff --git a/actionmailer/lib/rails/generators/mailer/USAGE b/actionmailer/lib/rails/generators/mailer/USAGE index 323bb8a87f..d9d9d064d8 100644 --- a/actionmailer/lib/rails/generators/mailer/USAGE +++ b/actionmailer/lib/rails/generators/mailer/USAGE @@ -11,7 +11,7 @@ Example: rails generate mailer Notifications signup forgot_password invoice creates a Notifications mailer class, views, and test: - Mailer: app/mailers/notifications.rb + Mailer: app/mailers/notifications_mailer.rb Views: app/views/notifications/signup.text.erb [...] Test: test/mailers/notifications_test.rb diff --git a/actionmailer/lib/rails/generators/mailer/mailer_generator.rb b/actionmailer/lib/rails/generators/mailer/mailer_generator.rb index d5bf864595..3ec7d3d896 100644 --- a/actionmailer/lib/rails/generators/mailer/mailer_generator.rb +++ b/actionmailer/lib/rails/generators/mailer/mailer_generator.rb @@ -4,13 +4,22 @@ module Rails source_root File.expand_path("../templates", __FILE__) argument :actions, type: :array, default: [], banner: "method method" - check_class_collision + + check_class_collision suffix: "Mailer" def create_mailer_file - template "mailer.rb", File.join('app/mailers', class_path, "#{file_name}.rb") + template "mailer.rb", File.join('app/mailers', class_path, "#{file_name}_mailer.rb") + if self.behavior == :invoke + template "application_mailer.rb", 'app/mailers/application_mailer.rb' + end end hook_for :template_engine, :test_framework + + protected + def file_name + @_file_name ||= super.gsub(/\_mailer/i, '') + end end end end diff --git a/actionmailer/lib/rails/generators/mailer/templates/application_mailer.rb b/actionmailer/lib/rails/generators/mailer/templates/application_mailer.rb new file mode 100644 index 0000000000..d25d8892dd --- /dev/null +++ b/actionmailer/lib/rails/generators/mailer/templates/application_mailer.rb @@ -0,0 +1,4 @@ +class ApplicationMailer < ActionMailer::Base + default from: "from@example.com" + layout 'mailer' +end diff --git a/actionmailer/lib/rails/generators/mailer/templates/mailer.rb b/actionmailer/lib/rails/generators/mailer/templates/mailer.rb index edcfb4233d..348d314758 100644 --- a/actionmailer/lib/rails/generators/mailer/templates/mailer.rb +++ b/actionmailer/lib/rails/generators/mailer/templates/mailer.rb @@ -1,12 +1,11 @@ <% module_namespacing do -%> -class <%= class_name %> < ActionMailer::Base - default from: "from@example.com" +class <%= class_name %>Mailer < ApplicationMailer <% actions.each do |action| -%> # Subject can be set in your I18n file at config/locales/en.yml # with the following lookup: # - # en.<%= file_path.tr("/",".") %>.<%= action %>.subject + # en.<%= file_path.tr("/",".") %>_mailer.<%= action %>.subject # def <%= action %> @greeting = "Hi" diff --git a/actionmailer/test/abstract_unit.rb b/actionmailer/test/abstract_unit.rb index aa18c512c7..c4d5cb8c33 100644 --- a/actionmailer/test/abstract_unit.rb +++ b/actionmailer/test/abstract_unit.rb @@ -15,47 +15,35 @@ require 'mail' # Emulate AV railtie require 'action_view' -ActionMailer::Base.send(:include, ActionView::Layouts) +ActionMailer::Base.include(ActionView::Layouts) # Show backtraces for deprecated behavior for quicker cleanup. ActiveSupport::Deprecation.debug = true -# Bogus template processors -ActionView::Template.register_template_handler :haml, lambda { |template| "Look its HAML!".inspect } -ActionView::Template.register_template_handler :bak, lambda { |template| "Lame backup".inspect } +# Disable available locale checks to avoid warnings running the test suite. +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 +module Rails + def self.root + File.expand_path('../', File.dirname(__FILE__)) end end -class Net::SMTP - def self.new(*args) - MockSMTP.new - end +# Skips the current run on Rubinius using Minitest::Assertions#skip +def rubinius_skip(message = '') + skip message if RUBY_ENGINE == 'rbx' end - -def set_delivery_method(method) - @old_delivery_method = ActionMailer::Base.delivery_method - ActionMailer::Base.delivery_method = method +# Skips the current run on JRuby using Minitest::Assertions#skip +def jruby_skip(message = '') + skip message if defined?(JRUBY_VERSION) end -def restore_delivery_method - ActionMailer::Base.delivery_method = @old_delivery_method -end +require 'mocha/setup' # FIXME: stop using mocha + +# FIXME: we have tests that depend on run order, we should fix that and +# remove this method call. +require 'active_support/test_case' +ActiveSupport::TestCase.test_order = :sorted diff --git a/actionmailer/test/assert_select_email_test.rb b/actionmailer/test/assert_select_email_test.rb new file mode 100644 index 0000000000..cae2e20abd --- /dev/null +++ b/actionmailer/test/assert_select_email_test.rb @@ -0,0 +1,47 @@ +require 'abstract_unit' + +class AssertSelectEmailTest < ActionMailer::TestCase + class AssertSelectMailer < ActionMailer::Base + def test(html) + mail body: html, content_type: "text/html", + subject: "Test e-mail", from: "test@test.host", to: "test <test@test.host>" + end + end + + class AssertMultipartSelectMailer < ActionMailer::Base + def test(options) + mail subject: "Test e-mail", from: "test@test.host", to: "test <test@test.host>" do |format| + format.text { render text: options[:text] } + format.html { render text: options[:html] } + end + end + end + + # + # Test assert_select_email + # + + def test_assert_select_email + assert_raise ActiveSupport::TestCase::Assertion do + assert_select_email {} + end + + AssertSelectMailer.test("<div><p>foo</p><p>bar</p></div>").deliver_now + assert_select_email do + assert_select "div:root" do + assert_select "p:first-child", "foo" + assert_select "p:last-child", "bar" + end + end + end + + def test_assert_select_email_multipart + AssertMultipartSelectMailer.test(html: "<div><p>foo</p><p>bar</p></div>", text: 'foo bar').deliver_now + assert_select_email do + assert_select "div:root" do + assert_select "p:first-child", "foo" + assert_select "p:last-child", "bar" + end + end + end +end diff --git a/actionmailer/test/asset_host_test.rb b/actionmailer/test/asset_host_test.rb index 00f1348a53..10cfdcf693 100644 --- a/actionmailer/test/asset_host_test.rb +++ b/actionmailer/test/asset_host_test.rb @@ -9,11 +9,8 @@ class AssetHostMailer < ActionMailer::Base end end -class AssetHostTest < ActiveSupport::TestCase +class AssetHostTest < ActionMailer::TestCase def setup - set_delivery_method :test - ActionMailer::Base.perform_deliveries = true - ActionMailer::Base.deliveries.clear AssetHostMailer.configure do |c| c.asset_host = "http://www.example.com" end @@ -25,31 +22,16 @@ class AssetHostTest < ActiveSupport::TestCase def test_asset_host_as_string mail = AssetHostMailer.email_with_asset - assert_equal %Q{<img alt="Somelogo" src="http://www.example.com/images/somelogo.png" />}, mail.body.to_s.strip + assert_dom_equal %Q{<img alt="Somelogo" src="http://www.example.com/images/somelogo.png" />}, mail.body.to_s.strip end 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 + assert_dom_equal %Q{<img alt="Somelogo" src="http://images.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 b74728ae34..59c5638f96 100644 --- a/actionmailer/test/base_test.rb +++ b/actionmailer/test/base_test.rb @@ -1,4 +1,3 @@ -# encoding: utf-8 require 'abstract_unit' require 'set' @@ -10,9 +9,20 @@ require 'mailers/proc_mailer' require 'mailers/asset_mailer' class BaseTest < ActiveSupport::TestCase - def teardown - ActionMailer::Base.asset_host = nil - ActionMailer::Base.assets_dir = nil + include Rails::Dom::Testing::Assertions::DomAssertions + + setup do + @original_delivery_method = ActionMailer::Base.delivery_method + ActionMailer::Base.delivery_method = :test + @original_asset_host = ActionMailer::Base.asset_host + @original_assets_dir = ActionMailer::Base.assets_dir + end + + teardown do + ActionMailer::Base.asset_host = @original_asset_host + ActionMailer::Base.assets_dir = @original_assets_dir + BaseMailer.deliveries.clear + ActionMailer::Base.delivery_method = @original_delivery_method end test "method call to mail does not raise error" do @@ -103,6 +113,7 @@ class BaseTest < ActiveSupport::TestCase test "attachment gets content type from filename" do email = BaseMailer.attachment_with_content assert_equal('invoice.pdf', email.attachments[0].filename) + assert_equal('application/pdf', email.attachments[0].mime_type) end test "attachment with hash" do @@ -200,25 +211,82 @@ class BaseTest < ActiveSupport::TestCase end test "subject gets default from I18n" do - BaseMailer.default subject: nil - email = BaseMailer.welcome(subject: nil) - assert_equal "Welcome", email.subject + with_default BaseMailer, subject: nil do + email = BaseMailer.welcome(subject: nil) + assert_equal "Welcome", email.subject - I18n.backend.store_translations('en', base_mailer: {welcome: {subject: "New Subject!"}}) - email = BaseMailer.welcome(subject: nil) - assert_equal "New Subject!", email.subject + with_translation 'en', base_mailer: {welcome: {subject: "New Subject!"}} do + email = BaseMailer.welcome(subject: nil) + assert_equal "New Subject!", email.subject + end + end end test 'default subject can have interpolations' do - I18n.backend.store_translations('en', base_mailer: {with_subject_interpolations: {subject: 'Will the real %{rapper_or_impersonator} please stand up?'}}) - email = BaseMailer.with_subject_interpolations - assert_equal 'Will the real Slim Shady please stand up?', email.subject + with_translation 'en', base_mailer: {with_subject_interpolations: {subject: 'Will the real %{rapper_or_impersonator} please stand up?'}} do + email = BaseMailer.with_subject_interpolations + assert_equal 'Will the real Slim Shady please stand up?', email.subject + end end test "translations are scoped properly" do - I18n.backend.store_translations('en', base_mailer: {email_with_translations: {greet_user: "Hello %{name}!"}}) - email = BaseMailer.email_with_translations - assert_equal 'Hello lifo!', email.body.encoded + with_translation 'en', base_mailer: {email_with_translations: {greet_user: "Hello %{name}!"}} do + email = BaseMailer.email_with_translations + assert_equal 'Hello lifo!', email.body.encoded + 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.message } + 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.message } + assert_match(/Can't add attachments after `mail` was called./, e.message) + end + + test "adding inline attachments while rendering mail works" do + class LateInlineAttachmentMailer < ActionMailer::Base + def on_render + mail from: "welcome@example.com", to: "to@example.com" + end + end + + mail = LateInlineAttachmentMailer.on_render + assert_nothing_raised { mail.message } + + assert_equal ["image/jpeg; filename=controller_attachments.jpg", + "image/jpeg; filename=attachments.jpg"], mail.attachments.inline.map {|a| a['Content-Type'].to_s } + 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.message } end # Implicit multipart @@ -284,10 +352,35 @@ class BaseTest < ActiveSupport::TestCase assert_equal("text/plain", email.parts[0].mime_type) assert_equal("Implicit with locale PL TEXT", email.parts[0].body.encoded) assert_equal("text/html", email.parts[1].mime_type) - assert_equal("Implicit with locale HTML", email.parts[1].body.encoded) + assert_equal("Implicit with locale EN HTML", email.parts[1].body.encoded) + end + end + + test "implicit multipart with fallback locale" do + fallback_backend = Class.new(I18n::Backend::Simple) do + include I18n::Backend::Fallbacks + end + + begin + backend = I18n.backend + I18n.backend = fallback_backend.new + I18n.fallbacks[:"de-AT"] = [:de] + + swap I18n, locale: 'de-AT' do + email = BaseMailer.implicit_with_locale + assert_equal(2, email.parts.size) + assert_equal("multipart/alternative", email.mime_type) + assert_equal("text/plain", email.parts[0].mime_type) + assert_equal("Implicit with locale DE-AT TEXT", email.parts[0].body.encoded) + assert_equal("text/html", email.parts[1].mime_type) + assert_equal("Implicit with locale DE HTML", email.parts[1].body.encoded) + end + ensure + I18n.backend = backend end end + test "implicit multipart with several view paths uses the first one with template" do old = BaseMailer.view_paths begin @@ -406,23 +499,19 @@ class BaseTest < ActiveSupport::TestCase end test "calling just the action should return the generated mail object" do - BaseMailer.deliveries.clear email = BaseMailer.welcome assert_equal(0, BaseMailer.deliveries.length) assert_equal('The first email on new API!', email.subject) end test "calling deliver on the action should deliver the mail object" do - BaseMailer.deliveries.clear BaseMailer.expects(:deliver_mail).once - mail = BaseMailer.welcome.deliver + mail = BaseMailer.welcome.deliver_now assert_equal 'The first email on new API!', mail.subject end test "calling deliver on the action should increment the deliveries collection if using the test mailer" do - BaseMailer.delivery_method = :test - BaseMailer.deliveries.clear - BaseMailer.welcome.deliver + BaseMailer.welcome.deliver_now assert_equal(1, BaseMailer.deliveries.length) end @@ -435,36 +524,35 @@ class BaseTest < ActiveSupport::TestCase # Rendering test "you can specify a different template for implicit render" do - mail = BaseMailer.implicit_different_template('implicit_multipart').deliver + mail = BaseMailer.implicit_different_template('implicit_multipart').deliver_now assert_equal("HTML Implicit Multipart", mail.html_part.body.decoded) assert_equal("TEXT Implicit Multipart", mail.text_part.body.decoded) end test "should raise if missing template in implicit render" do - BaseMailer.deliveries.clear assert_raises ActionView::MissingTemplate do - BaseMailer.implicit_different_template('missing_template').deliver + BaseMailer.implicit_different_template('missing_template').deliver_now end assert_equal(0, BaseMailer.deliveries.length) end test "you can specify a different template for explicit render" do - mail = BaseMailer.explicit_different_template('explicit_multipart_templates').deliver + mail = BaseMailer.explicit_different_template('explicit_multipart_templates').deliver_now assert_equal("HTML Explicit Multipart Templates", mail.html_part.body.decoded) assert_equal("TEXT Explicit Multipart Templates", mail.text_part.body.decoded) end test "you can specify a different layout" do - mail = BaseMailer.different_layout('different_layout').deliver + mail = BaseMailer.different_layout('different_layout').deliver_now assert_equal("HTML -- HTML", mail.html_part.body.decoded) assert_equal("PLAIN -- PLAIN", mail.text_part.body.decoded) end test "you can specify the template path for implicit lookup" do - mail = BaseMailer.welcome_from_another_path('another.path/base_mailer').deliver + mail = BaseMailer.welcome_from_another_path('another.path/base_mailer').deliver_now assert_equal("Welcome from another path", mail.body.encoded) - mail = BaseMailer.welcome_from_another_path(['unknown/invalid', 'another.path/base_mailer']).deliver + mail = BaseMailer.welcome_from_another_path(['unknown/invalid', 'another.path/base_mailer']).deliver_now assert_equal("Welcome from another path", mail.body.encoded) end @@ -474,34 +562,33 @@ class BaseTest < ActiveSupport::TestCase mail = AssetMailer.welcome - assert_equal(%{<img alt="Dummy" src="http://global.com/images/dummy.png" />}, mail.body.to_s.strip) + assert_dom_equal(%{<img alt="Dummy" src="http://global.com/images/dummy.png" />}, mail.body.to_s.strip) end test "assets tags should use a Mailer's asset_host settings when available" do - begin - ActionMailer::Base.config.asset_host = "http://global.com" - ActionMailer::Base.config.assets_dir = "global/" + ActionMailer::Base.config.asset_host = "http://global.com" + ActionMailer::Base.config.assets_dir = "global/" - AssetMailer.asset_host = "http://local.com" + TempAssetMailer = Class.new(AssetMailer) do + self.mailer_name = "asset_mailer" + self.asset_host = "http://local.com" + end - mail = AssetMailer.welcome + mail = TempAssetMailer.welcome - assert_equal(%{<img alt="Dummy" src="http://local.com/images/dummy.png" />}, mail.body.to_s.strip) - ensure - AssetMailer.asset_host = ActionMailer::Base.config.asset_host - end + assert_dom_equal(%{<img alt="Dummy" src="http://local.com/images/dummy.png" />}, mail.body.to_s.strip) end test 'the view is not rendered when mail was never called' do mail = BaseMailer.without_mail_call assert_equal('', mail.body.to_s.strip) - mail.deliver + mail.deliver_now end test 'the return value of mailer methods is not relevant' do mail = BaseMailer.with_nil_as_return_value assert_equal('Welcome', mail.body.to_s.strip) - mail.deliver + mail.deliver_now end # Before and After hooks @@ -517,57 +604,87 @@ class BaseTest < ActiveSupport::TestCase end test "you can register an observer to the mail object that gets informed on email delivery" do - ActionMailer::Base.register_observer(MyObserver) - mail = BaseMailer.welcome - MyObserver.expects(:delivered_email).with(mail) - mail.deliver + mail_side_effects do + ActionMailer::Base.register_observer(MyObserver) + mail = BaseMailer.welcome + MyObserver.expects(:delivered_email).with(mail) + mail.deliver_now + end end test "you can register an observer using its stringified name to the mail object that gets informed on email delivery" do - ActionMailer::Base.register_observer("BaseTest::MyObserver") - mail = BaseMailer.welcome - MyObserver.expects(:delivered_email).with(mail) - mail.deliver + mail_side_effects do + ActionMailer::Base.register_observer("BaseTest::MyObserver") + mail = BaseMailer.welcome + MyObserver.expects(:delivered_email).with(mail) + mail.deliver_now + end + end + + test "you can register an observer using its symbolized underscored name to the mail object that gets informed on email delivery" do + mail_side_effects do + ActionMailer::Base.register_observer(:"base_test/my_observer") + mail = BaseMailer.welcome + MyObserver.expects(:delivered_email).with(mail) + mail.deliver_now + end end test "you can register multiple observers to the mail object that both get informed on email delivery" do - ActionMailer::Base.register_observers("BaseTest::MyObserver", MySecondObserver) - mail = BaseMailer.welcome - MyObserver.expects(:delivered_email).with(mail) - MySecondObserver.expects(:delivered_email).with(mail) - mail.deliver + mail_side_effects do + ActionMailer::Base.register_observers("BaseTest::MyObserver", MySecondObserver) + mail = BaseMailer.welcome + MyObserver.expects(:delivered_email).with(mail) + MySecondObserver.expects(:delivered_email).with(mail) + mail.deliver_now + end end class MyInterceptor - def self.delivering_email(mail) - end + def self.delivering_email(mail); end + def self.previewing_email(mail); end end class MySecondInterceptor - def self.delivering_email(mail) - end + def self.delivering_email(mail); end + def self.previewing_email(mail); end end test "you can register an interceptor to the mail object that gets passed the mail object before delivery" do - ActionMailer::Base.register_interceptor(MyInterceptor) - mail = BaseMailer.welcome - MyInterceptor.expects(:delivering_email).with(mail) - mail.deliver + mail_side_effects do + ActionMailer::Base.register_interceptor(MyInterceptor) + mail = BaseMailer.welcome + MyInterceptor.expects(:delivering_email).with(mail) + mail.deliver_now + end end test "you can register an interceptor using its stringified name to the mail object that gets passed the mail object before delivery" do - ActionMailer::Base.register_interceptor("BaseTest::MyInterceptor") - mail = BaseMailer.welcome - MyInterceptor.expects(:delivering_email).with(mail) - mail.deliver + mail_side_effects do + ActionMailer::Base.register_interceptor("BaseTest::MyInterceptor") + mail = BaseMailer.welcome + MyInterceptor.expects(:delivering_email).with(mail) + mail.deliver_now + end + end + + test "you can register an interceptor using its symbolized underscored name to the mail object that gets passed the mail object before delivery" do + mail_side_effects do + ActionMailer::Base.register_interceptor(:"base_test/my_interceptor") + mail = BaseMailer.welcome + MyInterceptor.expects(:delivering_email).with(mail) + mail.deliver_now + end end test "you can register multiple interceptors to the mail object that both get passed the mail object before delivery" do - ActionMailer::Base.register_interceptors("BaseTest::MyInterceptor", MySecondInterceptor) - mail = BaseMailer.welcome - MyInterceptor.expects(:delivering_email).with(mail) - MySecondInterceptor.expects(:delivering_email).with(mail) - mail.deliver + mail_side_effects do + ActionMailer::Base.register_interceptors("BaseTest::MyInterceptor", MySecondInterceptor) + mail = BaseMailer.welcome + MyInterceptor.expects(:delivering_email).with(mail) + MySecondInterceptor.expects(:delivering_email).with(mail) + mail.deliver_now + end end test "being able to put proc's into the defaults hash and they get evaluated on mail sending" do @@ -671,6 +788,27 @@ class BaseTest < ActiveSupport::TestCase assert_equal ["robert.pankowecki@gmail.com"], DefaultFromMailer.welcome.from end + test "mail() without arguments serves as getter for the current mail message" do + class MailerWithCallback < ActionMailer::Base + after_action :a_callback + + def welcome + headers('X-Special-Header' => 'special indeed!') + mail subject: "subject", body: "hello world", to: ["joe@example.com"] + end + + def a_callback + mail.to << "jane@example.com" + end + end + + mail = MailerWithCallback.welcome + assert_equal "subject", mail.subject + assert_equal ["joe@example.com", "jane@example.com"], mail.to + assert_equal "hello world", mail.body.encoded.strip + assert_equal "special indeed!", mail["X-Special-Header"].to_s + end + protected # Execute the block setting the given values and restoring old values after @@ -695,4 +833,77 @@ class BaseTest < ActiveSupport::TestCase ensure klass.default_params = old end + + # A simple hack to restore the observers and interceptors for Mail, as it + # does not have an unregister API yet. + def mail_side_effects + old_observers = Mail.class_variable_get(:@@delivery_notification_observers) + old_delivery_interceptors = Mail.class_variable_get(:@@delivery_interceptors) + yield + ensure + Mail.class_variable_set(:@@delivery_notification_observers, old_observers) + Mail.class_variable_set(:@@delivery_interceptors, old_delivery_interceptors) + end + + def with_translation(locale, data) + I18n.backend.store_translations(locale, data) + yield + ensure + I18n.backend.reload! + end +end + +class BasePreviewInterceptorsTest < ActiveSupport::TestCase + teardown do + ActionMailer::Base.preview_interceptors.clear + end + + class BaseMailerPreview < ActionMailer::Preview + def welcome + BaseMailer.welcome + end + end + + class MyInterceptor + def self.delivering_email(mail); end + def self.previewing_email(mail); end + end + + class MySecondInterceptor + def self.delivering_email(mail); end + def self.previewing_email(mail); end + end + + test "you can register a preview interceptor to the mail object that gets passed the mail object before previewing" do + ActionMailer::Base.register_preview_interceptor(MyInterceptor) + mail = BaseMailer.welcome + BaseMailerPreview.any_instance.stubs(:welcome).returns(mail) + MyInterceptor.expects(:previewing_email).with(mail) + BaseMailerPreview.call(:welcome) + end + + test "you can register a preview interceptor using its stringified name to the mail object that gets passed the mail object before previewing" do + ActionMailer::Base.register_preview_interceptor("BasePreviewInterceptorsTest::MyInterceptor") + mail = BaseMailer.welcome + BaseMailerPreview.any_instance.stubs(:welcome).returns(mail) + MyInterceptor.expects(:previewing_email).with(mail) + BaseMailerPreview.call(:welcome) + end + + test "you can register an interceptor using its symbolized underscored name to the mail object that gets passed the mail object before previewing" do + ActionMailer::Base.register_preview_interceptor(:"base_preview_interceptors_test/my_interceptor") + mail = BaseMailer.welcome + BaseMailerPreview.any_instance.stubs(:welcome).returns(mail) + MyInterceptor.expects(:previewing_email).with(mail) + BaseMailerPreview.call(:welcome) + end + + test "you can register multiple preview interceptors to the mail object that both get passed the mail object before previewing" do + ActionMailer::Base.register_preview_interceptors("BasePreviewInterceptorsTest::MyInterceptor", MySecondInterceptor) + mail = BaseMailer.welcome + BaseMailerPreview.any_instance.stubs(:welcome).returns(mail) + MyInterceptor.expects(:previewing_email).with(mail) + MySecondInterceptor.expects(:previewing_email).with(mail) + BaseMailerPreview.call(:welcome) + end end diff --git a/actionmailer/test/delivery_methods_test.rb b/actionmailer/test/delivery_methods_test.rb index 61a037ea18..2e4e019bf7 100644 --- a/actionmailer/test/delivery_methods_test.rb +++ b/actionmailer/test/delivery_methods_test.rb @@ -38,19 +38,21 @@ class DefaultsDeliveryMethodsTest < ActiveSupport::TestCase end test "default sendmail settings" do - settings = {location: '/usr/sbin/sendmail', - arguments: '-i -t'} + settings = { + location: '/usr/sbin/sendmail', + arguments: '-i -t' + } assert_equal settings, ActionMailer::Base.sendmail_settings end end class CustomDeliveryMethodsTest < ActiveSupport::TestCase - def setup + setup do @old_delivery_method = ActionMailer::Base.delivery_method ActionMailer::Base.add_delivery_method :custom, MyCustomDelivery end - def teardown + teardown do ActionMailer::Base.delivery_method = @old_delivery_method new = ActionMailer::Base.delivery_methods.dup new.delete(:custom) @@ -91,34 +93,32 @@ class MailDeliveryTest < ActiveSupport::TestCase end end - def setup - ActionMailer::Base.delivery_method = :smtp + setup do + @old_delivery_method = DeliveryMailer.delivery_method end - def teardown - DeliveryMailer.delivery_method = :smtp - DeliveryMailer.perform_deliveries = true - DeliveryMailer.raise_delivery_errors = true + teardown do + DeliveryMailer.delivery_method = @old_delivery_method + DeliveryMailer.deliveries.clear end test "ActionMailer should be told when Mail gets delivered" do - DeliveryMailer.deliveries.clear DeliveryMailer.expects(:deliver_mail).once - DeliveryMailer.welcome.deliver + DeliveryMailer.welcome.deliver_now end test "delivery method can be customized per instance" do - email = DeliveryMailer.welcome.deliver + Mail::SMTP.any_instance.expects(:deliver!) + email = DeliveryMailer.welcome.deliver_now assert_instance_of Mail::SMTP, email.delivery_method - email = DeliveryMailer.welcome(delivery_method: :test).deliver + email = DeliveryMailer.welcome(delivery_method: :test).deliver_now assert_instance_of Mail::TestMailer, email.delivery_method end 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 + email = DeliveryMailer.welcome.deliver_now assert_instance_of Mail::TestMailer, email.delivery_method end @@ -138,13 +138,15 @@ class MailDeliveryTest < ActiveSupport::TestCase end test "default delivery options can be overridden per mail instance" do - settings = { address: "localhost", - port: 25, - domain: 'localhost.localdomain', - user_name: nil, - password: nil, - authentication: nil, - enable_starttls_auto: true } + 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 overridden_options = {user_name: "overridden", password: "somethingobtuse"} mail_instance = DeliveryMailer.welcome(delivery_method_options: overridden_options) @@ -152,60 +154,84 @@ class MailDeliveryTest < ActiveSupport::TestCase assert_equal "overridden", delivery_method_instance.settings[:user_name] assert_equal "somethingobtuse", delivery_method_instance.settings[:password] assert_equal delivery_method_instance.settings.merge(overridden_options), delivery_method_instance.settings + + # make sure that overriding delivery method options per mail instance doesn't affect the Base setting + assert_equal settings, ActionMailer::Base.smtp_settings end test "non registered delivery methods raises errors" do DeliveryMailer.delivery_method = :unknown assert_raise RuntimeError do - DeliveryMailer.welcome.deliver + DeliveryMailer.welcome.deliver_now + end + end + + test "undefined delivery methods raises errors" do + DeliveryMailer.delivery_method = nil + assert_raise RuntimeError do + DeliveryMailer.welcome.deliver_now end end test "does not perform deliveries if requested" do - DeliveryMailer.perform_deliveries = false - DeliveryMailer.deliveries.clear - Mail::Message.any_instance.expects(:deliver!).never - DeliveryMailer.welcome.deliver + old_perform_deliveries = DeliveryMailer.perform_deliveries + begin + DeliveryMailer.perform_deliveries = false + Mail::Message.any_instance.expects(:deliver!).never + DeliveryMailer.welcome.deliver_now + ensure + DeliveryMailer.perform_deliveries = old_perform_deliveries + end end test "does not append the deliveries collection if told not to perform the delivery" do - DeliveryMailer.perform_deliveries = false - DeliveryMailer.deliveries.clear - DeliveryMailer.welcome.deliver - assert_equal(0, DeliveryMailer.deliveries.length) + old_perform_deliveries = DeliveryMailer.perform_deliveries + begin + DeliveryMailer.perform_deliveries = false + DeliveryMailer.welcome.deliver_now + assert_equal [], DeliveryMailer.deliveries + ensure + DeliveryMailer.perform_deliveries = old_perform_deliveries + end end test "raise errors on bogus deliveries" do DeliveryMailer.delivery_method = BogusDelivery - DeliveryMailer.deliveries.clear assert_raise RuntimeError do - DeliveryMailer.welcome.deliver + DeliveryMailer.welcome.deliver_now end end test "does not increment the deliveries collection on error" do DeliveryMailer.delivery_method = BogusDelivery - DeliveryMailer.deliveries.clear assert_raise RuntimeError do - DeliveryMailer.welcome.deliver + DeliveryMailer.welcome.deliver_now end - assert_equal(0, DeliveryMailer.deliveries.length) + assert_equal [], DeliveryMailer.deliveries end test "does not raise errors on bogus deliveries if set" do - DeliveryMailer.delivery_method = BogusDelivery - DeliveryMailer.raise_delivery_errors = false - assert_nothing_raised do - DeliveryMailer.welcome.deliver + old_raise_delivery_errors = DeliveryMailer.raise_delivery_errors + begin + DeliveryMailer.delivery_method = BogusDelivery + DeliveryMailer.raise_delivery_errors = false + assert_nothing_raised do + DeliveryMailer.welcome.deliver_now + end + ensure + DeliveryMailer.raise_delivery_errors = old_raise_delivery_errors end end test "does not increment the deliveries collection on bogus deliveries" do - DeliveryMailer.delivery_method = BogusDelivery - DeliveryMailer.raise_delivery_errors = false - DeliveryMailer.deliveries.clear - DeliveryMailer.welcome.deliver - assert_equal(0, DeliveryMailer.deliveries.length) + old_raise_delivery_errors = DeliveryMailer.raise_delivery_errors + begin + DeliveryMailer.delivery_method = BogusDelivery + DeliveryMailer.raise_delivery_errors = false + DeliveryMailer.welcome.deliver_now + assert_equal [], DeliveryMailer.deliveries + ensure + DeliveryMailer.raise_delivery_errors = old_raise_delivery_errors + end end - end diff --git a/actionmailer/test/fixtures/base_mailer/email_with_translations.html.erb b/actionmailer/test/fixtures/base_mailer/email_with_translations.html.erb index 30466dd005..d676a6d2da 100644 --- a/actionmailer/test/fixtures/base_mailer/email_with_translations.html.erb +++ b/actionmailer/test/fixtures/base_mailer/email_with_translations.html.erb @@ -1 +1 @@ -<%= t('.greet_user', :name => 'lifo') %>
\ No newline at end of file +<%= t('.greet_user', name: 'lifo') %>
\ No newline at end of file diff --git a/actionmailer/test/fixtures/base_mailer/implicit_with_locale.de-AT.text.erb b/actionmailer/test/fixtures/base_mailer/implicit_with_locale.de-AT.text.erb new file mode 100644 index 0000000000..e97505fad9 --- /dev/null +++ b/actionmailer/test/fixtures/base_mailer/implicit_with_locale.de-AT.text.erb @@ -0,0 +1 @@ +Implicit with locale DE-AT TEXT
\ No newline at end of file diff --git a/actionmailer/test/fixtures/base_mailer/implicit_with_locale.de.html.erb b/actionmailer/test/fixtures/base_mailer/implicit_with_locale.de.html.erb new file mode 100644 index 0000000000..0536b5d3e2 --- /dev/null +++ b/actionmailer/test/fixtures/base_mailer/implicit_with_locale.de.html.erb @@ -0,0 +1 @@ +Implicit with locale DE HTML
\ No newline at end of file diff --git a/actionmailer/test/fixtures/base_test/late_inline_attachment_mailer/on_render.erb b/actionmailer/test/fixtures/base_test/late_inline_attachment_mailer/on_render.erb new file mode 100644 index 0000000000..6decd3bb31 --- /dev/null +++ b/actionmailer/test/fixtures/base_test/late_inline_attachment_mailer/on_render.erb @@ -0,0 +1,7 @@ +<h1>Adding an inline image while rendering</h1> + +<% controller.attachments.inline["controller_attachments.jpg"] = 'via controller.attachments.inline' %> +<%= image_tag attachments['controller_attachments.jpg'].url %> + +<% attachments.inline["attachments.jpg"] = 'via attachments.inline' %> +<%= image_tag attachments['attachments.jpg'].url %> diff --git a/actionmailer/test/fixtures/raw_email10 b/actionmailer/test/fixtures/raw_email10 deleted file mode 100644 index edad5ccff1..0000000000 --- a/actionmailer/test/fixtures/raw_email10 +++ /dev/null @@ -1,20 +0,0 @@ -Return-Path: <xxx@xxxx.xxx> -Received: from xxx.xxxx.xxx by xxx.xxxx.xxx with ESMTP id C1B953B4CB6 for <xxxxx@Exxx.xxxx.xxx>; Tue, 10 May 2005 15:27:05 -0500 -Received: from SMS-GTYxxx.xxxx.xxx by xxx.xxxx.xxx with ESMTP id ca for <xxxxx@Exxx.xxxx.xxx>; Tue, 10 May 2005 15:27:04 -0500 -Received: from xxx.xxxx.xxx by SMS-GTYxxx.xxxx.xxx with ESMTP id j4AKR3r23323 for <xxxxx@Exxx.xxxx.xxx>; Tue, 10 May 2005 15:27:03 -0500 -Date: Tue, 10 May 2005 15:27:03 -0500 -From: xxx@xxxx.xxx -Sender: xxx@xxxx.xxx -To: xxxxxxxxxxx@xxxx.xxxx.xxx -Message-Id: <xxx@xxxx.xxx> -X-Original-To: xxxxxxxxxxx@xxxx.xxxx.xxx -Delivered-To: xxx@xxxx.xxx -Importance: normal -Content-Type: text/plain; charset=X-UNKNOWN - -Test test. Hi. Waving. m - ----------------------------------------------------------------- -Sent via Bell Mobility's Text Messaging service. -Envoyé par le service de messagerie texte de Bell Mobilité. ----------------------------------------------------------------- diff --git a/actionmailer/test/fixtures/raw_email12 b/actionmailer/test/fixtures/raw_email12 deleted file mode 100644 index 2cd31720d3..0000000000 --- a/actionmailer/test/fixtures/raw_email12 +++ /dev/null @@ -1,32 +0,0 @@ -Mime-Version: 1.0 (Apple Message framework v730) -Content-Type: multipart/mixed; boundary=Apple-Mail-13-196941151 -Message-Id: <9169D984-4E0B-45EF-82D4-8F5E53AD7012@example.com> -From: foo@example.com -Subject: testing -Date: Mon, 6 Jun 2005 22:21:22 +0200 -To: blah@example.com - - ---Apple-Mail-13-196941151 -Content-Transfer-Encoding: quoted-printable -Content-Type: text/plain; - charset=ISO-8859-1; - delsp=yes; - format=flowed - -This is the first part. - ---Apple-Mail-13-196941151 -Content-Type: image/jpeg -Content-Transfer-Encoding: base64 -Content-Location: Photo25.jpg -Content-ID: <qbFGyPQAS8> -Content-Disposition: inline - -jamisSqGSIb3DQEHAqCAMIjamisxCzAJBgUrDgMCGgUAMIAGCSqGSjamisEHAQAAoIIFSjCCBUYw -ggQujamisQICBD++ukQwDQYJKojamisNAQEFBQAwMTELMAkGA1UEBhMCRjamisAKBgNVBAoTA1RE -QzEUMBIGjamisxMLVERDIE9DRVMgQ0jamisNMDQwMjI5MTE1OTAxWhcNMDYwMjamisIyOTAxWjCB -gDELMAkGA1UEjamisEsxKTAnBgNVBAoTIEjamisuIG9yZ2FuaXNhdG9yaXNrIHRpbjamisRuaW5= - ---Apple-Mail-13-196941151-- - diff --git a/actionmailer/test/fixtures/raw_email13 b/actionmailer/test/fixtures/raw_email13 deleted file mode 100644 index 7d9314e36a..0000000000 --- a/actionmailer/test/fixtures/raw_email13 +++ /dev/null @@ -1,29 +0,0 @@ -Mime-Version: 1.0 (Apple Message framework v730) -Content-Type: multipart/mixed; boundary=Apple-Mail-13-196941151 -Message-Id: <9169D984-4E0B-45EF-82D4-8F5E53AD7012@example.com> -From: foo@example.com -Subject: testing -Date: Mon, 6 Jun 2005 22:21:22 +0200 -To: blah@example.com - - ---Apple-Mail-13-196941151 -Content-Transfer-Encoding: quoted-printable -Content-Type: text/plain; - charset=ISO-8859-1; - delsp=yes; - format=flowed - -This is the first part. - ---Apple-Mail-13-196941151 -Content-Type: text/x-ruby-script; name="hello.rb" -Content-Transfer-Encoding: 7bit -Content-Disposition: attachment; - filename="api.rb" - -puts "Hello, world!" -gets - ---Apple-Mail-13-196941151-- - diff --git a/actionmailer/test/fixtures/raw_email2 b/actionmailer/test/fixtures/raw_email2 deleted file mode 100644 index 9f87bb2a98..0000000000 --- a/actionmailer/test/fixtures/raw_email2 +++ /dev/null @@ -1,114 +0,0 @@ -From xxxxxxxxx.xxxxxxx@gmail.com Sun May 8 19:07:09 2005 -Return-Path: <xxxxxxxxx.xxxxxxx@gmail.com> -X-Original-To: xxxxx@xxxxx.xxxxxxxxx.com -Delivered-To: xxxxx@xxxxx.xxxxxxxxx.com -Received: from localhost (localhost [127.0.0.1]) - by xxxxx.xxxxxxxxx.com (Postfix) with ESMTP id 06C9DA98D - for <xxxxx@xxxxx.xxxxxxxxx.com>; Sun, 8 May 2005 19:09:13 +0000 (GMT) -Received: from xxxxx.xxxxxxxxx.com ([127.0.0.1]) - by localhost (xxxxx.xxxxxxxxx.com [127.0.0.1]) (amavisd-new, port 10024) - with LMTP id 88783-08 for <xxxxx@xxxxx.xxxxxxxxx.com>; - Sun, 8 May 2005 19:09:12 +0000 (GMT) -Received: from xxxxxxx.xxxxxxxxx.com (xxxxxxx.xxxxxxxxx.com [69.36.39.150]) - by xxxxx.xxxxxxxxx.com (Postfix) with ESMTP id 10D8BA960 - for <xxxxx@xxxxxxxxx.org>; Sun, 8 May 2005 19:09:12 +0000 (GMT) -Received: from zproxy.gmail.com (zproxy.gmail.com [64.233.162.199]) - by xxxxxxx.xxxxxxxxx.com (Postfix) with ESMTP id 9EBC4148EAB - for <xxxxx@xxxxxxxxx.com>; Sun, 8 May 2005 14:09:11 -0500 (CDT) -Received: by zproxy.gmail.com with SMTP id 13so1233405nzp - for <xxxxx@xxxxxxxxx.com>; Sun, 08 May 2005 12:09:11 -0700 (PDT) -DomainKey-Signature: a=rsa-sha1; q=dns; c=nofws; - s=beta; d=gmail.com; - h=received:message-id:date:from:reply-to:to:subject:in-reply-to:mime-version:content-type:references; - b=cid1mzGEFa3gtRa06oSrrEYfKca2CTKu9sLMkWxjbvCsWMtp9RGEILjUz0L5RySdH5iO661LyNUoHRFQIa57bylAbXM3g2DTEIIKmuASDG3x3rIQ4sHAKpNxP7Pul+mgTaOKBv+spcH7af++QEJ36gHFXD2O/kx9RePs3JNf/K8= -Received: by 10.36.10.16 with SMTP id 16mr1012493nzj; - Sun, 08 May 2005 12:09:11 -0700 (PDT) -Received: by 10.36.5.10 with HTTP; Sun, 8 May 2005 12:09:11 -0700 (PDT) -Message-ID: <e85734b90505081209eaaa17b@mail.gmail.com> -Date: Sun, 8 May 2005 14:09:11 -0500 -From: xxxxxxxxx xxxxxxx <xxxxxxxxx.xxxxxxx@gmail.com> -Reply-To: xxxxxxxxx xxxxxxx <xxxxxxxxx.xxxxxxx@gmail.com> -To: xxxxx xxxx <xxxxx@xxxxxxxxx.com> -Subject: Fwd: Signed email causes file attachments -In-Reply-To: <F6E2D0B4-CC35-4A91-BA4C-C7C712B10C13@mac.com> -Mime-Version: 1.0 -Content-Type: multipart/mixed; - boundary="----=_Part_5028_7368284.1115579351471" -References: <F6E2D0B4-CC35-4A91-BA4C-C7C712B10C13@mac.com> - -------=_Part_5028_7368284.1115579351471 -Content-Type: text/plain; charset=ISO-8859-1 -Content-Transfer-Encoding: quoted-printable -Content-Disposition: inline - -We should not include these files or vcards as attachments. - ----------- Forwarded message ---------- -From: xxxxx xxxxxx <xxxxxxxx@xxx.com> -Date: May 8, 2005 1:17 PM -Subject: Signed email causes file attachments -To: xxxxxxx@xxxxxxxxxx.com - - -Hi, - -Just started to use my xxxxxxxx account (to set-up a GTD system, -natch) and noticed that when I send content via email the signature/ -certificate from my email account gets added as a file (e.g. -"smime.p7s"). - -Obviously I can uncheck the signature option in the Mail compose -window but how often will I remember to do that? - -Is there any way these kind of files could be ignored, e.g. via some -sort of exclusions list? - -------=_Part_5028_7368284.1115579351471 -Content-Type: application/pkcs7-signature; name=smime.p7s -Content-Transfer-Encoding: base64 -Content-Disposition: attachment; filename="smime.p7s" - -MIAGCSqGSIb3DQEHAqCAMIACAQExCzAJBgUrDgMCGgUAMIAGCSqGSIb3DQEHAQAAoIIGFDCCAs0w -ggI2oAMCAQICAw5c+TANBgkqhkiG9w0BAQQFADBiMQswCQYDVQQGEwJaQTElMCMGA1UEChMcVGhh -d3RlIENvbnN1bHRpbmcgKFB0eSkgTHRkLjEsMCoGA1UEAxMjVGhhd3RlIFBlcnNvbmFsIEZyZWVt -YWlsIElzc3VpbmcgQ0EwHhcNMDUwMzI5MDkzOTEwWhcNMDYwMzI5MDkzOTEwWjBCMR8wHQYDVQQD -ExZUaGF3dGUgRnJlZW1haWwgTWVtYmVyMR8wHQYJKoZIhvcNAQkBFhBzbWhhdW5jaEBtYWMuY29t -MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAn90dPsYS3LjfMY211OSYrDQLzwNYPlAL -7+/0XA+kdy8/rRnyEHFGwhNCDmg0B6pxC7z3xxJD/8GfCd+IYUUNUQV5m9MkxfP9pTVXZVIYLaBw -o8xS3A0a1LXealcmlEbJibmKkEaoXci3MhryLgpaa+Kk/sH02SNatDO1vS28bPsibZpcc6deFrla -hSYnL+PW54mDTGHIcCN2fbx/Y6qspzqmtKaXrv75NBtuy9cB6KzU4j2xXbTkAwz3pRSghJJaAwdp -+yIivAD3vr0kJE3p+Ez34HMh33EXEpFoWcN+MCEQZD9WnmFViMrvfvMXLGVFQfAAcC060eGFSRJ1 -ZQ9UVQIDAQABoy0wKzAbBgNVHREEFDASgRBzbWhhdW5jaEBtYWMuY29tMAwGA1UdEwEB/wQCMAAw -DQYJKoZIhvcNAQEEBQADgYEAQMrg1n2pXVWteP7BBj+Pk3UfYtbuHb42uHcLJjfjnRlH7AxnSwrd -L3HED205w3Cq8T7tzVxIjRRLO/ljq0GedSCFBky7eYo1PrXhztGHCTSBhsiWdiyLWxKlOxGAwJc/ -lMMnwqLOdrQcoF/YgbjeaUFOQbUh94w9VDNpWZYCZwcwggM/MIICqKADAgECAgENMA0GCSqGSIb3 -DQEBBQUAMIHRMQswCQYDVQQGEwJaQTEVMBMGA1UECBMMV2VzdGVybiBDYXBlMRIwEAYDVQQHEwlD -YXBlIFRvd24xGjAYBgNVBAoTEVRoYXd0ZSBDb25zdWx0aW5nMSgwJgYDVQQLEx9DZXJ0aWZpY2F0 -aW9uIFNlcnZpY2VzIERpdmlzaW9uMSQwIgYDVQQDExtUaGF3dGUgUGVyc29uYWwgRnJlZW1haWwg -Q0ExKzApBgkqhkiG9w0BCQEWHHBlcnNvbmFsLWZyZWVtYWlsQHRoYXd0ZS5jb20wHhcNMDMwNzE3 -MDAwMDAwWhcNMTMwNzE2MjM1OTU5WjBiMQswCQYDVQQGEwJaQTElMCMGA1UEChMcVGhhd3RlIENv -bnN1bHRpbmcgKFB0eSkgTHRkLjEsMCoGA1UEAxMjVGhhd3RlIFBlcnNvbmFsIEZyZWVtYWlsIElz -c3VpbmcgQ0EwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMSmPFVzVftOucqZWh5owHUEcJ3f -6f+jHuy9zfVb8hp2vX8MOmHyv1HOAdTlUAow1wJjWiyJFXCO3cnwK4Vaqj9xVsuvPAsH5/EfkTYk -KhPPK9Xzgnc9A74r/rsYPge/QIACZNenprufZdHFKlSFD0gEf6e20TxhBEAeZBlyYLf7AgMBAAGj -gZQwgZEwEgYDVR0TAQH/BAgwBgEB/wIBADBDBgNVHR8EPDA6MDigNqA0hjJodHRwOi8vY3JsLnRo -YXd0ZS5jb20vVGhhd3RlUGVyc29uYWxGcmVlbWFpbENBLmNybDALBgNVHQ8EBAMCAQYwKQYDVR0R -BCIwIKQeMBwxGjAYBgNVBAMTEVByaXZhdGVMYWJlbDItMTM4MA0GCSqGSIb3DQEBBQUAA4GBAEiM -0VCD6gsuzA2jZqxnD3+vrL7CF6FDlpSdf0whuPg2H6otnzYvwPQcUCCTcDz9reFhYsPZOhl+hLGZ -GwDFGguCdJ4lUJRix9sncVcljd2pnDmOjCBPZV+V2vf3h9bGCE6u9uo05RAaWzVNd+NWIXiC3CEZ -Nd4ksdMdRv9dX2VPMYIC5zCCAuMCAQEwaTBiMQswCQYDVQQGEwJaQTElMCMGA1UEChMcVGhhd3Rl -IENvbnN1bHRpbmcgKFB0eSkgTHRkLjEsMCoGA1UEAxMjVGhhd3RlIFBlcnNvbmFsIEZyZWVtYWls -IElzc3VpbmcgQ0ECAw5c+TAJBgUrDgMCGgUAoIIBUzAYBgkqhkiG9w0BCQMxCwYJKoZIhvcNAQcB -MBwGCSqGSIb3DQEJBTEPFw0wNTA1MDgxODE3NDZaMCMGCSqGSIb3DQEJBDEWBBQSkG9j6+hB0pKp -fV9tCi/iP59sNTB4BgkrBgEEAYI3EAQxazBpMGIxCzAJBgNVBAYTAlpBMSUwIwYDVQQKExxUaGF3 -dGUgQ29uc3VsdGluZyAoUHR5KSBMdGQuMSwwKgYDVQQDEyNUaGF3dGUgUGVyc29uYWwgRnJlZW1h -aWwgSXNzdWluZyBDQQIDDlz5MHoGCyqGSIb3DQEJEAILMWugaTBiMQswCQYDVQQGEwJaQTElMCMG -A1UEChMcVGhhd3RlIENvbnN1bHRpbmcgKFB0eSkgTHRkLjEsMCoGA1UEAxMjVGhhd3RlIFBlcnNv -bmFsIEZyZWVtYWlsIElzc3VpbmcgQ0ECAw5c+TANBgkqhkiG9w0BAQEFAASCAQAm1GeF7dWfMvrW -8yMPjkhE+R8D1DsiCoWSCp+5gAQm7lcK7V3KrZh5howfpI3TmCZUbbaMxOH+7aKRKpFemxoBY5Q8 -rnCkbpg/++/+MI01T69hF/rgMmrGcrv2fIYy8EaARLG0xUVFSZHSP+NQSYz0TTmh4cAESHMzY3JA -nHOoUkuPyl8RXrimY1zn0lceMXlweZRouiPGuPNl1hQKw8P+GhOC5oLlM71UtStnrlk3P9gqX5v7 -Tj7Hx057oVfY8FMevjxGwU3EK5TczHezHbWWgTyum9l2ZQbUQsDJxSniD3BM46C1VcbDLPaotAZ0 -fTYLZizQfm5hcWEbfYVzkSzLAAAAAAAA -------=_Part_5028_7368284.1115579351471-- - diff --git a/actionmailer/test/fixtures/raw_email3 b/actionmailer/test/fixtures/raw_email3 deleted file mode 100644 index 3a0927490a..0000000000 --- a/actionmailer/test/fixtures/raw_email3 +++ /dev/null @@ -1,70 +0,0 @@ -From xxxx@xxxx.com Tue May 10 11:28:07 2005 -Return-Path: <xxxx@xxxx.com> -X-Original-To: xxxx@xxxx.com -Delivered-To: xxxx@xxxx.com -Received: from localhost (localhost [127.0.0.1]) - by xxx.xxxxx.com (Postfix) with ESMTP id 50FD3A96F - for <xxxx@xxxx.com>; Tue, 10 May 2005 17:26:50 +0000 (GMT) -Received: from xxx.xxxxx.com ([127.0.0.1]) - by localhost (xxx.xxxxx.com [127.0.0.1]) (amavisd-new, port 10024) - with LMTP id 70060-03 for <xxxx@xxxx.com>; - Tue, 10 May 2005 17:26:49 +0000 (GMT) -Received: from xxx.xxxxx.com (xxx.xxxxx.com [69.36.39.150]) - by xxx.xxxxx.com (Postfix) with ESMTP id 8B957A94B - for <xxxx@xxxx.com>; Tue, 10 May 2005 17:26:48 +0000 (GMT) -Received: from xxx.xxxxx.com (xxx.xxxxx.com [64.233.184.203]) - by xxx.xxxxx.com (Postfix) with ESMTP id 9972514824C - for <xxxx@xxxx.com>; Tue, 10 May 2005 12:26:40 -0500 (CDT) -Received: by xxx.xxxxx.com with SMTP id 68so1694448wri - for <xxxx@xxxx.com>; Tue, 10 May 2005 10:26:40 -0700 (PDT) -DomainKey-Signature: a=rsa-sha1; q=dns; c=nofws; - s=beta; d=xxxxx.com; - h=received:message-id:date:from:reply-to:to:subject:mime-version:content-type; - b=g8ZO5ttS6GPEMAz9WxrRk9+9IXBUfQIYsZLL6T88+ECbsXqGIgfGtzJJFn6o9CE3/HMrrIGkN5AisxVFTGXWxWci5YA/7PTVWwPOhJff5BRYQDVNgRKqMl/SMttNrrRElsGJjnD1UyQ/5kQmcBxq2PuZI5Zc47u6CILcuoBcM+A= -Received: by 10.54.96.19 with SMTP id t19mr621017wrb; - Tue, 10 May 2005 10:26:39 -0700 (PDT) -Received: by 10.54.110.5 with HTTP; Tue, 10 May 2005 10:26:39 -0700 (PDT) -Message-ID: <xxxx@xxxx.com> -Date: Tue, 10 May 2005 11:26:39 -0600 -From: Test Tester <xxxx@xxxx.com> -Reply-To: Test Tester <xxxx@xxxx.com> -To: xxxx@xxxx.com, xxxx@xxxx.com -Subject: Another PDF -Mime-Version: 1.0 -Content-Type: multipart/mixed; - boundary="----=_Part_2192_32400445.1115745999735" -X-Virus-Scanned: amavisd-new at textdrive.com - -------=_Part_2192_32400445.1115745999735 -Content-Type: text/plain; charset=ISO-8859-1 -Content-Transfer-Encoding: quoted-printable -Content-Disposition: inline - -Just attaching another PDF, here, to see what the message looks like, -and to see if I can figure out what is going wrong here. - -------=_Part_2192_32400445.1115745999735 -Content-Type: application/pdf; name="broken.pdf" -Content-Transfer-Encoding: base64 -Content-Disposition: attachment; filename="broken.pdf" - -JVBERi0xLjQNCiXk9tzfDQoxIDAgb2JqDQo8PCAvTGVuZ3RoIDIgMCBSDQogICAvRmlsdGVyIC9G -bGF0ZURlY29kZQ0KPj4NCnN0cmVhbQ0KeJy9Wt2KJbkNvm/od6jrhZxYln9hWEh2p+8HBvICySaE -ycLuTV4/1ifJ9qnq09NpSBimu76yLUuy/qzqcPz7+em3Ixx/CDc6CsXxs3b5+fvfjr/8cPz6/BRu -rbfAx/n3739/fuJylJ5u5fjX81OuDr4deK4Bz3z/aDP+8fz0yw8g0Ofq7ktr1Mn+u28rvhy/jVeD -QSa+9YNKHP/pxjvDNfVAx/m3MFz54FhvTbaseaxiDoN2LeMVMw+yA7RbHSCDzxZuaYB2E1Yay7QU -x89vz0+tyFDKMlAHK5yqLmnjF+c4RjEiQIUeKwblXMe+AsZjN1J5yGQL5DHpDHksurM81rF6PKab -gK6zAarIDzIiUY23rJsN9iorAE816aIu6lsgAdQFsuhhkHOUFgVjp2GjMqSewITXNQ27jrMeamkg -1rPI3iLWG2CIaSBB+V1245YVRICGbbpYKHc2USFDl6M09acQVQYhlwIrkBNLISvXhGlF1wi5FHCw -wxZkoGNJlVeJCEsqKA+3YAV5AMb6KkeaqEJQmFKKQU8T1pRi2ihE1Y4CDrqoYFFXYjJJOatsyzuI -8SIlykuxKTMibWK8H1PgEvqYgs4GmQSrEjJAalgGirIhik+p4ZQN9E3ETFPAHE1b8pp1l/0Rc1gl -fQs0ABWvyoZZzU8VnPXwVVcO9BEsyjEJaO6eBoZRyKGlrKoYoOygA8BGIzgwN3RQ15ouigG5idZQ -fx2U4Db2CqiLO0WHAZoylGiCAqhniNQjFjQPSkmjwfNTgQ6M1Ih+eWo36wFmjIxDJZiGUBiWsAyR -xX3EekGOizkGI96Ol9zVZTAivikURhRsHh2E3JhWMpSTZCnnonrLhMCodgrNcgo4uyJUJc6qnVss -nrGd1Ptr0YwisCOYyIbUwVjV4xBUNLbguSO2YHujonAMJkMdSI7bIw91Akq2AUlMUWGFTMAOamjU -OvZQCxIkY2pCpMFo/IwLdVLHs6nddwTRrgoVbvLU9eB0G4EMndV0TNoxHbt3JBWwK6hhv3iHfDtF -yokB302IpEBTnWICde4uYc/1khDbSIkQopO6lcqamGBu1OSE3N5IPSsZX00CkSHRiiyx6HQIShsS -HSVNswdVsaOUSAWq9aYhDtGDaoG5a3lBGkYt/lFlBFt1UqrYnzVtUpUQnLiZeouKgf1KhRBViRRk -ExepJCzTwEmFDalIRbLEGtw0gfpESOpIAF/NnpPzcVCG86s0g2DuSyd41uhNGbEgaSrWEXORErbw -------=_Part_2192_32400445.1115745999735-- - diff --git a/actionmailer/test/fixtures/raw_email4 b/actionmailer/test/fixtures/raw_email4 deleted file mode 100644 index 639ad40e49..0000000000 --- a/actionmailer/test/fixtures/raw_email4 +++ /dev/null @@ -1,59 +0,0 @@ -Return-Path: <xxx@xxxx.xxx> -Received: from xxx.xxxx.xxx by xxx.xxxx.xxx with ESMTP id 6AAEE3B4D23 for <xxx@xxxx.xxx>; Sun, 8 May 2005 12:30:23 -0500 -Received: from xxx.xxxx.xxx by xxx.xxxx.xxx with ESMTP id j48HUC213279 for <xxx@xxxx.xxx>; Sun, 8 May 2005 12:30:13 -0500 -Received: from conversion-xxx.xxxx.xxx.net by xxx.xxxx.xxx id <0IG600901LQ64I@xxx.xxxx.xxx> for <xxx@xxxx.xxx>; Sun, 8 May 2005 12:30:12 -0500 -Received: from agw1 by xxx.xxxx.xxx with ESMTP id <0IG600JFYLYCAxxx@xxxx.xxx> for <xxx@xxxx.xxx>; Sun, 8 May 2005 12:30:12 -0500 -Date: Sun, 8 May 2005 12:30:08 -0500 -From: xxx@xxxx.xxx -To: xxx@xxxx.xxx -Message-Id: <7864245.1115573412626.JavaMxxx@xxxx.xxx> -Subject: Filth -Mime-Version: 1.0 -Content-Type: multipart/mixed; boundary=mimepart_427e4cb4ca329_133ae40413c81ef -X-Mms-Priority: 1 -X-Mms-Transaction-Id: 3198421808-0 -X-Mms-Message-Type: 0 -X-Mms-Sender-Visibility: 1 -X-Mms-Read-Reply: 1 -X-Original-To: xxx@xxxx.xxx -X-Mms-Message-Class: 0 -X-Mms-Delivery-Report: 0 -X-Mms-Mms-Version: 16 -Delivered-To: xxx@xxxx.xxx -X-Nokia-Ag-Version: 2.0 - -This is a multi-part message in MIME format. - ---mimepart_427e4cb4ca329_133ae40413c81ef -Content-Type: multipart/mixed; boundary=mimepart_427e4cb4cbd97_133ae40413c8217 - - - ---mimepart_427e4cb4cbd97_133ae40413c8217 -Content-Type: text/plain; charset=utf-8 -Content-Transfer-Encoding: 7bit -Content-Disposition: inline -Content-Location: text.txt - -Some text - ---mimepart_427e4cb4cbd97_133ae40413c8217-- - ---mimepart_427e4cb4ca329_133ae40413c81ef -Content-Type: text/plain; charset=us-ascii -Content-Transfer-Encoding: 7bit - - --- -This Orange Multi Media Message was sent wirefree from an Orange -MMS phone. If you would like to reply, please text or phone the -sender directly by using the phone number listed in the sender's -address. To learn more about Orange's Multi Media Messaging -Service, find us on the Web at xxx.xxxx.xxx.uk/mms - - ---mimepart_427e4cb4ca329_133ae40413c81ef - - ---mimepart_427e4cb4ca329_133ae40413c81ef- - diff --git a/actionmailer/test/fixtures/raw_email5 b/actionmailer/test/fixtures/raw_email5 deleted file mode 100644 index bbe31bcdc5..0000000000 --- a/actionmailer/test/fixtures/raw_email5 +++ /dev/null @@ -1,19 +0,0 @@ -Return-Path: <xxx@xxxx.xxx> -Received: from xxx.xxxx.xxx by xxx.xxxx.xxx with ESMTP id C1B953B4CB6 for <xxxxx@Exxx.xxxx.xxx>; Tue, 10 May 2005 15:27:05 -0500 -Received: from SMS-GTYxxx.xxxx.xxx by xxx.xxxx.xxx with ESMTP id ca for <xxxxx@Exxx.xxxx.xxx>; Tue, 10 May 2005 15:27:04 -0500 -Received: from xxx.xxxx.xxx by SMS-GTYxxx.xxxx.xxx with ESMTP id j4AKR3r23323 for <xxxxx@Exxx.xxxx.xxx>; Tue, 10 May 2005 15:27:03 -0500 -Date: Tue, 10 May 2005 15:27:03 -0500 -From: xxx@xxxx.xxx -Sender: xxx@xxxx.xxx -To: xxxxxxxxxxx@xxxx.xxxx.xxx -Message-Id: <xxx@xxxx.xxx> -X-Original-To: xxxxxxxxxxx@xxxx.xxxx.xxx -Delivered-To: xxx@xxxx.xxx -Importance: normal - -Test test. Hi. Waving. m - ----------------------------------------------------------------- -Sent via Bell Mobility's Text Messaging service. -Envoyé par le service de messagerie texte de Bell Mobilité. ----------------------------------------------------------------- diff --git a/actionmailer/test/fixtures/raw_email6 b/actionmailer/test/fixtures/raw_email6 deleted file mode 100644 index 8e37bd7392..0000000000 --- a/actionmailer/test/fixtures/raw_email6 +++ /dev/null @@ -1,20 +0,0 @@ -Return-Path: <xxx@xxxx.xxx> -Received: from xxx.xxxx.xxx by xxx.xxxx.xxx with ESMTP id C1B953B4CB6 for <xxxxx@Exxx.xxxx.xxx>; Tue, 10 May 2005 15:27:05 -0500 -Received: from SMS-GTYxxx.xxxx.xxx by xxx.xxxx.xxx with ESMTP id ca for <xxxxx@Exxx.xxxx.xxx>; Tue, 10 May 2005 15:27:04 -0500 -Received: from xxx.xxxx.xxx by SMS-GTYxxx.xxxx.xxx with ESMTP id j4AKR3r23323 for <xxxxx@Exxx.xxxx.xxx>; Tue, 10 May 2005 15:27:03 -0500 -Date: Tue, 10 May 2005 15:27:03 -0500 -From: xxx@xxxx.xxx -Sender: xxx@xxxx.xxx -To: xxxxxxxxxxx@xxxx.xxxx.xxx -Message-Id: <xxx@xxxx.xxx> -X-Original-To: xxxxxxxxxxx@xxxx.xxxx.xxx -Delivered-To: xxx@xxxx.xxx -Importance: normal -Content-Type: text/plain; charset=us-ascii - -Test test. Hi. Waving. m - ----------------------------------------------------------------- -Sent via Bell Mobility's Text Messaging service. -Envoyé par le service de messagerie texte de Bell Mobilité. ----------------------------------------------------------------- diff --git a/actionmailer/test/fixtures/raw_email7 b/actionmailer/test/fixtures/raw_email7 deleted file mode 100644 index da64ada8a5..0000000000 --- a/actionmailer/test/fixtures/raw_email7 +++ /dev/null @@ -1,66 +0,0 @@ -Mime-Version: 1.0 (Apple Message framework v730) -Content-Type: multipart/mixed; boundary=Apple-Mail-13-196941151 -Message-Id: <9169D984-4E0B-45EF-82D4-8F5E53AD7012@example.com> -From: foo@example.com -Subject: testing -Date: Mon, 6 Jun 2005 22:21:22 +0200 -To: blah@example.com - - ---Apple-Mail-13-196941151 -Content-Type: multipart/mixed; - boundary=Apple-Mail-12-196940926 - - ---Apple-Mail-12-196940926 -Content-Transfer-Encoding: quoted-printable -Content-Type: text/plain; - charset=ISO-8859-1; - delsp=yes; - format=flowed - -This is the first part. - ---Apple-Mail-12-196940926 -Content-Transfer-Encoding: 7bit -Content-Type: text/x-ruby-script; - x-unix-mode=0666; - name="test.rb" -Content-Disposition: attachment; - filename=test.rb - -puts "testing, testing" - ---Apple-Mail-12-196940926 -Content-Transfer-Encoding: base64 -Content-Type: application/pdf; - x-unix-mode=0666; - name="test.pdf" -Content-Disposition: inline; - filename=test.pdf - -YmxhaCBibGFoIGJsYWg= - ---Apple-Mail-12-196940926 -Content-Transfer-Encoding: 7bit -Content-Type: text/plain; - charset=US-ASCII; - format=flowed - - - ---Apple-Mail-12-196940926-- - ---Apple-Mail-13-196941151 -Content-Transfer-Encoding: base64 -Content-Type: application/pkcs7-signature; - name=smime.p7s -Content-Disposition: attachment; - filename=smime.p7s - -jamisSqGSIb3DQEHAqCAMIjamisxCzAJBgUrDgMCGgUAMIAGCSqGSjamisEHAQAAoIIFSjCCBUYw -ggQujamisQICBD++ukQwDQYJKojamisNAQEFBQAwMTELMAkGA1UEBhMCRjamisAKBgNVBAoTA1RE -QzEUMBIGjamisxMLVERDIE9DRVMgQ0jamisNMDQwMjI5MTE1OTAxWhcNMDYwMjamisIyOTAxWjCB -gDELMAkGA1UEjamisEsxKTAnBgNVBAoTIEjamisuIG9yZ2FuaXNhdG9yaXNrIHRpbjamisRuaW5= - ---Apple-Mail-13-196941151-- diff --git a/actionmailer/test/fixtures/raw_email8 b/actionmailer/test/fixtures/raw_email8 deleted file mode 100644 index 79996365b3..0000000000 --- a/actionmailer/test/fixtures/raw_email8 +++ /dev/null @@ -1,47 +0,0 @@ -From xxxxxxxxx.xxxxxxx@gmail.com Sun May 8 19:07:09 2005 -Return-Path: <xxxxxxxxx.xxxxxxx@gmail.com> -Message-ID: <e85734b90505081209eaaa17b@mail.gmail.com> -Date: Sun, 8 May 2005 14:09:11 -0500 -From: xxxxxxxxx xxxxxxx <xxxxxxxxx.xxxxxxx@gmail.com> -Reply-To: xxxxxxxxx xxxxxxx <xxxxxxxxx.xxxxxxx@gmail.com> -To: xxxxx xxxx <xxxxx@xxxxxxxxx.com> -Subject: Fwd: Signed email causes file attachments -In-Reply-To: <F6E2D0B4-CC35-4A91-BA4C-C7C712B10C13@mac.com> -Mime-Version: 1.0 -Content-Type: multipart/mixed; - boundary="----=_Part_5028_7368284.1115579351471" -References: <F6E2D0B4-CC35-4A91-BA4C-C7C712B10C13@mac.com> - -------=_Part_5028_7368284.1115579351471 -Content-Type: text/plain; charset=ISO-8859-1 -Content-Transfer-Encoding: quoted-printable -Content-Disposition: inline - -We should not include these files or vcards as attachments. - ----------- Forwarded message ---------- -From: xxxxx xxxxxx <xxxxxxxx@xxx.com> -Date: May 8, 2005 1:17 PM -Subject: Signed email causes file attachments -To: xxxxxxx@xxxxxxxxxx.com - - -Hi, - -Test attachments oddly encoded with japanese charset. - - -------=_Part_5028_7368284.1115579351471 -Content-Type: application/octet-stream; name*=iso-2022-jp'ja'01%20Quien%20Te%20Dij%8aat.%20Pitbull.mp3 -Content-Transfer-Encoding: base64 -Content-Disposition: attachment - -MIAGCSqGSIb3DQEHAqCAMIACAQExCzAJBgUrDgMCGgUAMIAGCSqGSIb3DQEHAQAAoIIGFDCCAs0w -ggI2oAMCAQICAw5c+TANBgkqhkiG9w0BAQQFADBiMQswCQYDVQQGEwJaQTElMCMGA1UEChMcVGhh -d3RlIENvbnN1bHRpbmcgKFB0eSkgTHRkLjEsMCoGA1UEAxMjVGhhd3RlIFBlcnNvbmFsIEZyZWVt -YWlsIElzc3VpbmcgQ0EwHhcNMDUwMzI5MDkzOTEwWhcNMDYwMzI5MDkzOTEwWjBCMR8wHQYDVQQD -ExZUaGF3dGUgRnJlZW1haWwgTWVtYmVyMR8wHQYJKoZIhvcNAQkBFhBzbWhhdW5jaEBtYWMuY29t -MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAn90dPsYS3LjfMY211OSYrDQLzwNYPlAL -7+/0XA+kdy8/rRnyEHFGwhNCDmg0B6pxC7z3xxJD/8GfCd+IYUUNUQV5m9MkxfP9pTVXZVIYLaBw -------=_Part_5028_7368284.1115579351471-- - diff --git a/actionmailer/test/fixtures/raw_email9 b/actionmailer/test/fixtures/raw_email9 deleted file mode 100644 index 02ea0b05c5..0000000000 --- a/actionmailer/test/fixtures/raw_email9 +++ /dev/null @@ -1,28 +0,0 @@ -Received: from xxx.xxx.xxx ([xxx.xxx.xxx.xxx] verified) - by xxx.com (CommuniGate Pro SMTP 4.2.8) - with SMTP id 2532598 for xxx@xxx.com; Wed, 23 Feb 2005 17:51:49 -0500 -Received-SPF: softfail - receiver=xxx.com; client-ip=xxx.xxx.xxx.xxx; envelope-from=xxx@xxx.xxx -quite Delivered-To: xxx@xxx.xxx -Received: by xxx.xxx.xxx (Wostfix, from userid xxx) - id 0F87F333; Wed, 23 Feb 2005 16:16:17 -0600 -Date: Wed, 23 Feb 2005 18:20:17 -0400 -From: "xxx xxx" <xxx@xxx.xxx> -Message-ID: <4D6AA7EB.6490534@xxx.xxx> -To: xxx@xxx.com -Subject: Stop adware/spyware once and for all. -X-Scanned-By: MIMEDefang 2.11 (www dot roaringpenguin dot com slash mimedefang) - -You are infected with: -Ad Ware and Spy Ware - -Get your free scan and removal download now, -before it gets any worse. - -http://xxx.xxx.info?aid=3D13&?stat=3D4327kdzt - - - - -no more? (you will still be infected) -http://xxx.xxx.info/discon/?xxx@xxx.com diff --git a/actionmailer/test/fixtures/raw_email_quoted_with_0d0a b/actionmailer/test/fixtures/raw_email_quoted_with_0d0a deleted file mode 100644 index 8a2c25a5dd..0000000000 --- a/actionmailer/test/fixtures/raw_email_quoted_with_0d0a +++ /dev/null @@ -1,14 +0,0 @@ -Mime-Version: 1.0 (Apple Message framework v730)
-Message-Id: <9169D984-4E0B-45EF-82D4-8F5E53AD7012@example.com>
-From: foo@example.com
-Subject: testing
-Date: Mon, 6 Jun 2005 22:21:22 +0200
-To: blah@example.com
-Content-Transfer-Encoding: quoted-printable
-Content-Type: text/plain
-
-A fax has arrived from remote ID ''.=0D=0A-----------------------=
--------------------------------------=0D=0ATime: 3/9/2006 3:50:52=
- PM=0D=0AReceived from remote ID: =0D=0AInbound user ID XXXXXXXXXX, r=
-outing code XXXXXXXXX=0D=0AResult: (0/352;0/0) Successful Send=0D=0AP=
-age record: 1 - 1=0D=0AElapsed time: 00:58 on channel 11=0D=0A
diff --git a/actionmailer/test/fixtures/raw_email_with_invalid_characters_in_content_type b/actionmailer/test/fixtures/raw_email_with_invalid_characters_in_content_type deleted file mode 100644 index a8ff7ed4cb..0000000000 --- a/actionmailer/test/fixtures/raw_email_with_invalid_characters_in_content_type +++ /dev/null @@ -1,104 +0,0 @@ -Return-Path: <mikel.other@baci> -Received: from some.isp.com by baci with ESMTP id 632BD5758 for <mikel.lindsaar@baci>; Sun, 21 Oct 2007 19:38:21 +1000 -Date: Sun, 21 Oct 2007 19:38:13 +1000 -From: Mikel Lindsaar <mikel.other@baci> -Reply-To: Mikel Lindsaar <mikel.other@baci> -To: mikel.lindsaar@baci -Message-Id: <009601c813c6$19df3510$0437d30a@mikel091a> -Subject: Testing outlook -Mime-Version: 1.0 -Content-Type: multipart/alternative; boundary=----=_NextPart_000_0093_01C81419.EB75E850 -Delivered-To: mikel.lindsaar@baci -X-Mimeole: Produced By Microsoft MimeOLE V6.00.2900.3138 -X-Msmail-Priority: Normal - -This is a multi-part message in MIME format. - - -------=_NextPart_000_0093_01C81419.EB75E850 -Content-Type: text/plain; charset=iso-8859-1 -Content-Transfer-Encoding: Quoted-printable - -Hello -This is an outlook test - -So there. - -Me. - -------=_NextPart_000_0093_01C81419.EB75E850 -Content-Type: text/html; charset=iso-8859-1 -Content-Transfer-Encoding: Quoted-printable - -<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> -<HTML><HEAD> -<META http-equiv=3DContent-Type content=3D"text/html; = -charset=3Diso-8859-1"> -<META content=3D"MSHTML 6.00.6000.16525" name=3DGENERATOR> -<STYLE></STYLE> -</HEAD> -<BODY bgColor=3D#ffffff> -<DIV><FONT face=3DArial size=3D2>Hello</FONT></DIV> -<DIV><FONT face=3DArial size=3D2><STRONG>This is an outlook=20 -test</STRONG></FONT></DIV> -<DIV><FONT face=3DArial size=3D2><STRONG></STRONG></FONT> </DIV> -<DIV><FONT face=3DArial size=3D2><STRONG>So there.</STRONG></FONT></DIV> -<DIV><FONT face=3DArial size=3D2></FONT> </DIV> -<DIV><FONT face=3DArial size=3D2>Me.</FONT></DIV></BODY></HTML> - - -------=_NextPart_000_0093_01C81419.EB75E850-- - - -Return-Path: <mikel.other@baci> -Received: from some.isp.com by baci with ESMTP id 632BD5758 for <mikel.lindsaar@baci>; Sun, 21 Oct 2007 19:38:21 +1000 -Date: Sun, 21 Oct 2007 19:38:13 +1000 -From: Mikel Lindsaar <mikel.other@baci> -Reply-To: Mikel Lindsaar <mikel.other@baci> -To: mikel.lindsaar@baci -Message-Id: <009601c813c6$19df3510$0437d30a@mikel091a> -Subject: Testing outlook -Mime-Version: 1.0 -Content-Type: multipart/alternative; boundary=----=_NextPart_000_0093_01C81419.EB75E850 -Delivered-To: mikel.lindsaar@baci -X-Mimeole: Produced By Microsoft MimeOLE V6.00.2900.3138 -X-Msmail-Priority: Normal - -This is a multi-part message in MIME format. - - -------=_NextPart_000_0093_01C81419.EB75E850 -Content-Type: text/plain; charset=iso-8859-1 -Content-Transfer-Encoding: Quoted-printable - -Hello -This is an outlook test - -So there. - -Me. - -------=_NextPart_000_0093_01C81419.EB75E850 -Content-Type: text/html; charset=iso-8859-1 -Content-Transfer-Encoding: Quoted-printable - -<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> -<HTML><HEAD> -<META http-equiv=3DContent-Type content=3D"text/html; = -charset=3Diso-8859-1"> -<META content=3D"MSHTML 6.00.6000.16525" name=3DGENERATOR> -<STYLE></STYLE> -</HEAD> -<BODY bgColor=3D#ffffff> -<DIV><FONT face=3DArial size=3D2>Hello</FONT></DIV> -<DIV><FONT face=3DArial size=3D2><STRONG>This is an outlook=20 -test</STRONG></FONT></DIV> -<DIV><FONT face=3DArial size=3D2><STRONG></STRONG></FONT> </DIV> -<DIV><FONT face=3DArial size=3D2><STRONG>So there.</STRONG></FONT></DIV> -<DIV><FONT face=3DArial size=3D2></FONT> </DIV> -<DIV><FONT face=3DArial size=3D2>Me.</FONT></DIV></BODY></HTML> - - -------=_NextPart_000_0093_01C81419.EB75E850-- - - diff --git a/actionmailer/test/fixtures/raw_email_with_nested_attachment b/actionmailer/test/fixtures/raw_email_with_nested_attachment deleted file mode 100644 index 429c408c5d..0000000000 --- a/actionmailer/test/fixtures/raw_email_with_nested_attachment +++ /dev/null @@ -1,100 +0,0 @@ -From jamis@37signals.com Thu Feb 22 11:20:31 2007 -Mime-Version: 1.0 (Apple Message framework v752.3) -Message-Id: <2CCE0408-10C7-4045-9B16-A1C11C31469B@37signals.com> -Content-Type: multipart/signed; - micalg=sha1; - boundary=Apple-Mail-42-587703407; - protocol="application/pkcs7-signature" -To: Jamis Buck <jamis@jamisbuck.org> -Subject: Testing attachments -From: Jamis Buck <jamis@37signals.com> -Date: Thu, 22 Feb 2007 11:20:31 -0700 - - ---Apple-Mail-42-587703407 -Content-Type: multipart/mixed; - boundary=Apple-Mail-41-587703287 - - ---Apple-Mail-41-587703287 -Content-Transfer-Encoding: 7bit -Content-Type: text/plain; - charset=US-ASCII; - format=flowed - -Here is a test of an attachment via email. - -- Jamis - - ---Apple-Mail-41-587703287 -Content-Transfer-Encoding: base64 -Content-Type: image/png; - x-unix-mode=0644; - name=byo-ror-cover.png -Content-Disposition: inline; - filename=truncated.png - -iVBORw0KGgoAAAANSUhEUgAAAKUAAADXCAYAAAB7wZEQAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz -AAALEgAACxIB0t1+/AAAABd0RVh0Q3JlYXRpb24gVGltZQAxLzI1LzIwMDeD9CJVAAAAGHRFWHRT -b2Z0d2FyZQBBZG9iZSBGaXJld29ya3NPsx9OAAAyBWlUWHRYTUw6Y29tLmFkb2JlLnhtcDw/eHBh -Y2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+Cjx4OnhtcG1l -dGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDQuMS1j -MDIwIDEuMjU1NzE2LCBUdWUgT2N0IDEwIDIwMDYgMjM6MTY6MzQiPgogICA8cmRmOlJERiB4bWxu -czpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPgogICAg -ICA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIgogICAgICAgICAgICB4bWxuczp4YXA9Imh0 -dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iPgogICAgICAgICA8eGFwOkNyZWF0b3JUb29sPkFk -b2JlIEZpcmV3b3JrcyBDUzM8L3hhcDpDcmVhdG9yVG9vbD4KICAgICAgICAgPHhhcDpDcmVhdGVE -YXRlPjIwMDctMDEtMjVUMDU6Mjg6MjFaPC94YXA6Q3JlYXRlRGF0ZT4KICAgICAgICAgPHhhcDpN -b2RpZnlEYXRlPjIwMDctMDEtMjVUMDU6Mjg6MjFaPC94YXA6TW9kaWZ5RGF0ZT4KICAgICAgPC9y -ZGY6RGVzY3JpcHRpb24+CiAgICAgIDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiCiAgICAg -ICAgICAgIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyI+CiAgICAg -ICAgIDxkYzpmb3JtYXQ+aW1hZ2UvcG5nPC9kYzpmb3JtYXQ+CiAgICAgIDwvcmRmOkRlc2NyaXB0 -hhojpmnJMfaYFmSkXWg5PGCmHXVj/c9At0hSK2xGdd8F3muk0VFjb4f5Ue0ksQ8qAcq0delaXhdb -DjKNnF+3B3t9kObZYmk7AZgWYqO9anpR3wpM9sQ5XslB9a+kWyTtNb0fOmudzGHfPFBQDKesyycm -DBL7Cw5bXjIEuci+SSOm/LYnXDZu6iuPEj8lYBb+OU8xx1f9m+e5rhJiYKqjo5vHfiZp+VUkW9xc -Ufd6JHNWc47PkQqb9ie3SLEZB/ZqyAssiqURY+G35iOMZUrHbasHnb80QAPv9FHtAbJIyro7bi5b -ai2TEAKen5+LJNWrglZjm3UbZvt7KryA2J5b5J1jZF8kL6GzvG1Zqx54Y1y7J7n20wMOt9frG2sW -uwGP07kNz3732vf6bfvAvLldfS+9fts2euXY37D+R29FGZdlnhzV4TTFmPJduBP2RbNNua4rTqcT -Qt7Xy1KUB0AHSdP5AZQYvHZg7WD1XvYeMO1A9HhZPqMX5KXbMBrn2efxns/ee21674efxz4Tp/fq -2HZ648dgYaC1i3Vq1IbNPq3PvDTPezY9FaRISjvnzWqdgcWN8EJgjnNq+Z7ktOm9l2Nfth28EZi4 -bG/we5JwxM+Tql47/D/X6b38I8/RyxvxPJrX6zvQbo3h9jyJx+C0ALX327QETHl5eYlaYCT5rPTb -+5/rAq26t3lKIxV/p88hq6ptngdgCzoPjJqndiLfc/6y5A14WeDFGNPct4iUsJBV2bYzLEV7m83s -6Rp63VPhHKC/g/LzaU9qexJRr56043JWinqAtfZqsSm1sjoznthl54dtCqv+uL4nIY+oYWuc3+nH -kGfn8b0HQpvOYLQAZUDanbJs3jQhITZEgdarZK+cO6ySlL13rut5nFaN23s7u3Snz6eRPTkCoc2/ -Vp1zHfZVFpZ87FiMVLV1iqyK5rlzfji2GzjfDsodlD+Weo5UD4h6PwKqzQMqID0tq2VjjFVSMpis -ZLRAs7sePZBZAHI+gIanB8I7MD+femAceeUe2Kxa5jS950kZ1p5eNEdeX1+jFmSpZ+1EdWCsDcne -NPNgUHNw3aYpnzv9PGTX0uo94EtN9qq1rOdxe3kc79T8ukeHJJ8Fnxej6qlylbLLsjQLOy6Xy2a1 -kefs/N+nM7+S7IG5/E5Yc7F003pWErLjbH0O5cGadiMptSB/DZ5U5DI9yeg5MFYyMj8lC/Y7/Xjq -OZlWcnpg9aQfXz2HRq+Wn5xOp6gN8tWq8R44e2pfyzLYemEgprst+XXk2Zj2nXlbsG05BprndTMv -C3QRaXczshhVsHnMgfYn80Y2g5JureA6wBasPeP7LkE/jvZMJAaf/g/U2RelHsisvan5FqweIAHg -Pwc7L68GxvVDAAAAAElFTkSuQmCC - ---Apple-Mail-41-587703287-- - ---Apple-Mail-42-587703407 -Content-Transfer-Encoding: base64 -Content-Type: application/pkcs7-signature; - name=smime.p7s -Content-Disposition: attachment; - filename=smime.p7s - -MIAGCSqGSIb3DQEHAqCAMIACAQExCzAJBgUrDgMCGgUAMIAGCSqGSIb3DQEHAQAAoIIGJzCCAuAw -ggJJoAMCAQICEFjnFNYXwDEZRWY5EkfzopUwDQYJKoZIhvcNAQEFBQAwYjELMAkGA1UEBhMCWkEx -JTAjBgNVBAoTHFRoYXd0ZSBDb25zdWx0aW5nIChQdHkpIEx0ZC4xLDAqBgNVBAMTI1RoYXd0ZSBQ -ZXJzb25hbCBGcmVlbWFpbCBJc3N1aW5nIENBMB4XDTA2MDkxMjE3MDExMloXDTA3MDkxMjE3MDEx -MlowRTEfMB0GA1UEAxMWVGhhd3RlIEZyZWVtYWlsIE1lbWJlcjEiMCAGCSqGSIb3DQEJARYTamFt -aXNAMzdzaWduYWxzLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAO2A9JeOFIFJ -G6z8pTcAldrZ2nMe+Xb1tNrbHgoVzN/QhHXM4qst2Ml93cmFLjMmwG7P9RJeU4oNx+jTqVoBB7NV -Ne1/o56Do0KhfMZ9iUDQdPLbkZMq4EEpFMdm6PyM3muRKwPhj66iAWe/osCb8DowUK2f66vaRx0Z -Y0MQHIIrXE02Ta4IfAhIfPqBLkZ4WgTYBHN9vMdYea1jF0GO4gqGk1wqwb3yxv2QMYMbwJ6SI+k/ -ZjkSR/OilTCBhwYLKoZIhvcNAQkQAgsxeKB2MGIxCzAJBgNVBAYTAlpBMSUwIwYDVQQKExxUaGF3 -dGUgQ29uc3VsdGluZyAoUHR5KSBMdGQuMSwwKgYDVQQDEyNUaGF3dGUgUGVyc29uYWwgRnJlZW1h -aWwgSXNzdWluZyBDQQIQWOcU1hfAMRlFZjkSR/OilTANBgkqhkiG9w0BAQEFAASCAQCfwQiC3v6/ -yleRDGv3bJ4nQYQ+c3mz3+mn3Xi6uU35n3piwxZZaWRdmLyiXPvU+QReHpSf3l2qsEZM3sdE0XF9 -eRul/+QTFJcDNXOEAxG1zC2Gpz+6c6RrX4Ou12Pwkp+pNrZWTSY/mZgdqcArupOBcZi7qBjoWcy5 -wb54dfvSSjrjmqLbkH/E8ww/6gGQuU/xXpAUZgUrTmQHrNKeIdSh5oDkOxFaFWvnmb8Z/2ixKqW/ -Ux6WqamyvBtTs/5YBEtnpZOk+uVoscYEUBhU+DVJ2OSvTdXSivMtBdXmGTsG22k+P1NGUHi/A7ev -xPaO0uk4V8xyjNlN4HPuGpkrlXwPAAAAAAAA - ---Apple-Mail-42-587703407-- diff --git a/actionmailer/test/fixtures/raw_email_with_partially_quoted_subject b/actionmailer/test/fixtures/raw_email_with_partially_quoted_subject deleted file mode 100644 index e86108da1e..0000000000 --- a/actionmailer/test/fixtures/raw_email_with_partially_quoted_subject +++ /dev/null @@ -1,14 +0,0 @@ -From jamis@37signals.com Mon May 2 16:07:05 2005 -Mime-Version: 1.0 (Apple Message framework v622) -Content-Transfer-Encoding: base64 -Message-Id: <d3b8cf8e49f04480850c28713a1f473e@37signals.com> -Content-Type: text/plain; - charset=EUC-KR; - format=flowed -To: jamis@37signals.com -From: Jamis Buck <jamis@37signals.com> -Subject: Re: Test: =?UTF-8?B?Iua8ouWtlyI=?= mid =?UTF-8?B?Iua8ouWtlyI=?= tail -Date: Mon, 2 May 2005 16:07:05 -0600 - -tOu6zrrQwMcguLbC+bChwfa3ziwgv+y4rrTCIMfPs6q01MC7ILnPvcC0z7TZLg0KDQrBpiDAzLin -wLogSmFtaXPA1LTPtNku 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/fixtures/test_mailer/included_subtemplate.text.erb b/actionmailer/test/fixtures/test_mailer/included_subtemplate.text.erb index a93c30ea1a..ae3cfa77e7 100644 --- a/actionmailer/test/fixtures/test_mailer/included_subtemplate.text.erb +++ b/actionmailer/test/fixtures/test_mailer/included_subtemplate.text.erb @@ -1 +1 @@ -Hey Ho, <%= render :partial => "subtemplate" %>
\ No newline at end of file +Hey Ho, <%= render partial: "subtemplate" %>
\ No newline at end of file diff --git a/actionmailer/test/fixtures/url_test_mailer/exercise_url_for.erb b/actionmailer/test/fixtures/url_test_mailer/exercise_url_for.erb new file mode 100644 index 0000000000..0322c1191e --- /dev/null +++ b/actionmailer/test/fixtures/url_test_mailer/exercise_url_for.erb @@ -0,0 +1 @@ +<%= url_for(@options) %> <%= @url %> diff --git a/actionmailer/test/i18n_with_controller_test.rb b/actionmailer/test/i18n_with_controller_test.rb index ab5eaaa9d5..010e44d045 100644 --- a/actionmailer/test/i18n_with_controller_test.rb +++ b/actionmailer/test/i18n_with_controller_test.rb @@ -10,18 +10,15 @@ class I18nTestMailer < ActionMailer::Base def mail_with_i18n_subject(recipient) @recipient = recipient I18n.locale = :de - mail(to: recipient, subject: "#{I18n.t :email_subject} #{recipient}", + mail(to: recipient, subject: I18n.t(:email_subject), from: "system@loudthinking.com", date: Time.local(2004, 12, 12)) end end -# Emulate AV railtie -ActionController::Base.superclass.send(:include, ActionView::Layouts) - class TestController < ActionController::Base def send_mail - I18nTestMailer.mail_with_i18n_subject("test@localhost").deliver - render text: 'Mail sent' + email = I18nTestMailer.mail_with_i18n_subject("test@localhost").deliver_now + render text: "Mail sent - Subject: #{email.subject}" end end @@ -31,20 +28,43 @@ class ActionMailerI18nWithControllerTest < ActionDispatch::IntegrationTest get ':controller(/:action(/:id))' end - def app - Routes + 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 - def setup - I18n.backend.store_translations('de', email_subject: '[Signed up] Welcome') + APP = RoutedRackApp.new(Routes) + + def app + APP end - def teardown - I18n.locale = :en + teardown do + I18n.locale = I18n.default_locale end def test_send_mail - get '/test/send_mail' - assert_equal "Mail sent", @response.body + 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 + end + end + + protected + + def with_translation(locale, data) + I18n.backend.store_translations(locale, data) + yield + ensure + I18n.backend.reload! end end diff --git a/actionmailer/test/log_subscriber_test.rb b/actionmailer/test/log_subscriber_test.rb index 5f52a1bd69..3871b16840 100644 --- a/actionmailer/test/log_subscriber_test.rb +++ b/actionmailer/test/log_subscriber_test.rb @@ -1,7 +1,7 @@ -require "abstract_unit" +require 'abstract_unit' require 'mailers/base_mailer' -require "active_support/log_subscriber/test_helper" -require "action_mailer/log_subscriber" +require 'active_support/log_subscriber/test_helper' +require 'action_mailer/log_subscriber' class AMLogSubscriberTest < ActionMailer::TestCase include ActiveSupport::LogSubscriber::TestHelper @@ -22,12 +22,17 @@ class AMLogSubscriberTest < ActionMailer::TestCase end def test_deliver_is_notified - BaseMailer.welcome.deliver + BaseMailer.welcome.deliver_now wait + assert_equal(1, @logger.logged(:info).size) assert_match(/Sent mail to system@test.lindsaar.net/, @logger.logged(:info).first) - assert_equal(1, @logger.logged(:debug).size) - assert_match(/Welcome/, @logger.logged(:debug).first) + + assert_equal(2, @logger.logged(:debug).size) + assert_match(/BaseMailer#welcome: processed outbound mail in [\d.]+ms/, @logger.logged(:debug).first) + assert_match(/Welcome/, @logger.logged(:debug).second) + ensure + BaseMailer.deliveries.clear end def test_receive_is_notified @@ -39,4 +44,4 @@ class AMLogSubscriberTest < ActionMailer::TestCase assert_equal(1, @logger.logged(:debug).size) assert_match(/Jamis/, @logger.logged(:debug).first) end -end
\ No newline at end of file +end diff --git a/actionmailer/test/mail_layout_test.rb b/actionmailer/test/mail_layout_test.rb index 7f959282cb..166dd096d4 100644 --- a/actionmailer/test/mail_layout_test.rb +++ b/actionmailer/test/mail_layout_test.rb @@ -44,16 +44,6 @@ class ExplicitLayoutMailer < ActionMailer::Base end class LayoutMailerTest < ActiveSupport::TestCase - def setup - set_delivery_method :test - ActionMailer::Base.perform_deliveries = true - ActionMailer::Base.deliveries.clear - end - - def teardown - restore_delivery_method - end - def test_should_pickup_default_layout mail = AutoLayoutMailer.hello assert_equal "Hello from layout Inside", mail.body.to_s.strip diff --git a/actionmailer/test/mailers/base_mailer.rb b/actionmailer/test/mailers/base_mailer.rb index 6584bf5195..bd991e209e 100644 --- a/actionmailer/test/mailers/base_mailer.rb +++ b/actionmailer/test/mailers/base_mailer.rb @@ -120,7 +120,7 @@ class BaseMailer < ActionMailer::Base end def with_nil_as_return_value - mail(:template_name => "welcome") + mail(template_name: "welcome") nil end diff --git a/actionmailer/test/mailers/delayed_mailer.rb b/actionmailer/test/mailers/delayed_mailer.rb new file mode 100644 index 0000000000..62d4baa434 --- /dev/null +++ b/actionmailer/test/mailers/delayed_mailer.rb @@ -0,0 +1,6 @@ +class DelayedMailer < ActionMailer::Base + + def test_message(*) + mail(from: 'test-sender@test.com', to: 'test-receiver@test.com', subject: 'Test Subject', body: 'Test Body') + end +end diff --git a/actionmailer/test/message_delivery_test.rb b/actionmailer/test/message_delivery_test.rb new file mode 100644 index 0000000000..e4dd269494 --- /dev/null +++ b/actionmailer/test/message_delivery_test.rb @@ -0,0 +1,84 @@ +require 'abstract_unit' +require 'active_job' +require 'minitest/mock' +require 'mailers/delayed_mailer' +require 'active_support/core_ext/numeric/time' + +class MessageDeliveryTest < ActiveSupport::TestCase + include ActiveJob::TestHelper + + setup do + @previous_logger = ActiveJob::Base.logger + @previous_delivery_method = ActionMailer::Base.delivery_method + ActionMailer::Base.delivery_method = :test + ActiveJob::Base.logger = Logger.new(nil) + @mail = DelayedMailer.test_message(1, 2, 3) + ActionMailer::Base.deliveries.clear + ActiveJob::Base.queue_adapter.perform_enqueued_at_jobs = true + ActiveJob::Base.queue_adapter.perform_enqueued_jobs = true + end + + teardown do + ActiveJob::Base.logger = @previous_logger + ActionMailer::Base.delivery_method = @previous_delivery_method + end + + test 'should have a message' do + assert @mail.message + end + + test 'its message should be a Mail::Message' do + assert_equal Mail::Message , @mail.message.class + end + + test 'should respond to .deliver_later' do + assert_respond_to @mail, :deliver_later + end + + test 'should respond to .deliver_later!' do + assert_respond_to @mail, :deliver_later! + end + + test 'should respond to .deliver_now' do + assert_respond_to @mail, :deliver_now + end + + test 'should respond to .deliver_now!' do + assert_respond_to @mail, :deliver_now! + end + + def test_should_enqueue_and_run_correctly_in_activejob + @mail.deliver_later! + assert_equal 1, ActionMailer::Base.deliveries.size + ensure + ActionMailer::Base.deliveries.clear + end + + test 'should enqueue the email with :deliver_now delivery method' do + assert_performed_with(job: ActionMailer::DeliveryJob, args: ['DelayedMailer', 'test_message', 'deliver_now', 1, 2, 3]) do + @mail.deliver_later + end + end + + test 'should enqueue the email with :deliver_now! delivery method' do + assert_performed_with(job: ActionMailer::DeliveryJob, args: ['DelayedMailer', 'test_message', 'deliver_now!', 1, 2, 3]) do + @mail.deliver_later! + end + end + + test 'should enqueue a delivery with a delay' do + travel_to Time.new(2004, 11, 24, 01, 04, 44) do + assert_performed_with(job: ActionMailer::DeliveryJob, at: Time.current.to_f+600.seconds, args: ['DelayedMailer', 'test_message', 'deliver_now', 1, 2, 3]) do + @mail.deliver_later wait: 600.seconds + end + end + end + + test 'should enqueue a delivery at a specific time' do + later_time = Time.now.to_f + 3600 + assert_performed_with(job: ActionMailer::DeliveryJob, at: later_time, args: ['DelayedMailer', 'test_message', 'deliver_now', 1, 2, 3]) do + @mail.deliver_later wait_until: later_time + end + end + +end diff --git a/actionmailer/test/test_test.rb b/actionmailer/test/test_case_test.rb index 86fd37bea6..86fd37bea6 100644 --- a/actionmailer/test/test_test.rb +++ b/actionmailer/test/test_case_test.rb diff --git a/actionmailer/test/test_helper_test.rb b/actionmailer/test/test_helper_test.rb index 7c7f0b6fdc..089933e245 100644 --- a/actionmailer/test/test_helper_test.rb +++ b/actionmailer/test/test_helper_test.rb @@ -1,4 +1,5 @@ require 'abstract_unit' +require 'active_support/testing/stream' class TestHelperMailer < ActionMailer::Base def test @@ -10,6 +11,8 @@ class TestHelperMailer < ActionMailer::Base end class TestHelperMailerTest < ActionMailer::TestCase + include ActiveSupport::Testing::Stream + def test_setup_sets_right_action_mailer_options assert_equal :test, ActionMailer::Base.delivery_method assert ActionMailer::Base.perform_deliveries @@ -36,10 +39,18 @@ 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 - TestHelperMailer.test.deliver + TestHelperMailer.test.deliver_now end end end @@ -47,27 +58,27 @@ class TestHelperMailerTest < ActionMailer::TestCase def test_repeated_assert_emails_calls assert_nothing_raised do assert_emails 1 do - TestHelperMailer.test.deliver + TestHelperMailer.test.deliver_now end end assert_nothing_raised do assert_emails 2 do - TestHelperMailer.test.deliver - TestHelperMailer.test.deliver + TestHelperMailer.test.deliver_now + TestHelperMailer.test.deliver_now end end end def test_assert_emails_with_no_block assert_nothing_raised do - TestHelperMailer.test.deliver + TestHelperMailer.test.deliver_now assert_emails 1 end assert_nothing_raised do - TestHelperMailer.test.deliver - TestHelperMailer.test.deliver + TestHelperMailer.test.deliver_now + TestHelperMailer.test.deliver_now assert_emails 3 end end @@ -83,7 +94,7 @@ class TestHelperMailerTest < ActionMailer::TestCase def test_assert_emails_too_few_sent error = assert_raise ActiveSupport::TestCase::Assertion do assert_emails 2 do - TestHelperMailer.test.deliver + TestHelperMailer.test.deliver_now end end @@ -93,8 +104,8 @@ class TestHelperMailerTest < ActionMailer::TestCase def test_assert_emails_too_many_sent error = assert_raise ActiveSupport::TestCase::Assertion do assert_emails 1 do - TestHelperMailer.test.deliver - TestHelperMailer.test.deliver + TestHelperMailer.test.deliver_now + TestHelperMailer.test.deliver_now end end @@ -104,7 +115,62 @@ class TestHelperMailerTest < ActionMailer::TestCase def test_assert_no_emails_failure error = assert_raise ActiveSupport::TestCase::Assertion do assert_no_emails do - TestHelperMailer.test.deliver + TestHelperMailer.test.deliver_now + end + end + + assert_match(/0 .* but 1/, error.message) + end + + def test_assert_enqueued_emails + assert_nothing_raised do + assert_enqueued_emails 1 do + silence_stream($stdout) do + TestHelperMailer.test.deliver_later + end + end + end + end + + def test_assert_enqueued_emails_too_few_sent + error = assert_raise ActiveSupport::TestCase::Assertion do + assert_enqueued_emails 2 do + silence_stream($stdout) do + TestHelperMailer.test.deliver_later + end + end + end + + assert_match(/2 .* but 1/, error.message) + end + + def test_assert_enqueued_emails_too_many_sent + error = assert_raise ActiveSupport::TestCase::Assertion do + assert_enqueued_emails 1 do + silence_stream($stdout) do + TestHelperMailer.test.deliver_later + TestHelperMailer.test.deliver_later + end + end + end + + assert_match(/1 .* but 2/, error.message) + end + + def test_assert_no_enqueued_emails + assert_nothing_raised do + assert_no_enqueued_emails do + TestHelperMailer.test.deliver_now + end + end + end + + def test_assert_no_enqueued_emails_failure + error = assert_raise ActiveSupport::TestCase::Assertion do + assert_no_enqueued_emails do + silence_stream($stdout) do + TestHelperMailer.test.deliver_later + end end end diff --git a/actionmailer/test/url_test.rb b/actionmailer/test/url_test.rb index 589944fa69..7928fe9542 100644 --- a/actionmailer/test/url_test.rb +++ b/actionmailer/test/url_test.rb @@ -23,9 +23,32 @@ class UrlTestMailer < ActionMailer::Base mail(to: recipient, subject: "[Signed up] Welcome #{recipient}", from: "system@loudthinking.com", date: Time.local(2004, 12, 12)) end + + def exercise_url_for(options) + @options = options + @url = url_for(@options) + mail(from: 'from@example.com', to: 'to@example.com', subject: 'subject') + end end class ActionMailerUrlTest < ActionMailer::TestCase + class DummyModel + def self.model_name + OpenStruct.new(route_key: 'dummy_model') + end + + def persisted? + false + end + + def model_name + self.class.model_name + end + + def to_model + self + end + end def encode( text, charset="UTF-8" ) quoted_printable( text, charset ) @@ -40,10 +63,47 @@ class ActionMailerUrlTest < ActionMailer::TestCase mail end + def assert_url_for(expected, options, relative = false) + expected = "http://www.basecamphq.com#{expected}" if expected.start_with?('/') && !relative + urls = UrlTestMailer.exercise_url_for(options).body.to_s.chomp.split + + assert_equal expected, urls.first + assert_equal expected, urls.second + end + def setup @recipient = 'test@localhost' end + def test_url_for + UrlTestMailer.delivery_method = :test + + AppRoutes.draw do + get ':controller(/:action(/:id))' + get '/welcome' => 'foo#bar', as: 'welcome' + get '/dummy_model' => 'foo#baz', as: 'dummy_model' + end + + # string + assert_url_for 'http://foo/', 'http://foo/' + + # symbol + assert_url_for '/welcome', :welcome + + # hash + assert_url_for '/a/b/c', controller: 'a', action: 'b', id: 'c' + assert_url_for '/a/b/c', {controller: 'a', action: 'b', id: 'c', only_path: true}, true + + # model + assert_url_for '/dummy_model', DummyModel.new + + # class + assert_url_for '/dummy_model', DummyModel + + # array + assert_url_for '/dummy_model' , [DummyModel] + end + def test_signed_up_with_url UrlTestMailer.delivery_method = :test @@ -66,13 +126,13 @@ class ActionMailerUrlTest < ActionMailer::TestCase expected.message_id = '<123@456>' created.message_id = '<123@456>' - assert_equal expected.encoded, created.encoded + assert_dom_equal expected.encoded, created.encoded - assert_nothing_raised { UrlTestMailer.signed_up_with_url(@recipient).deliver } + assert_nothing_raised { UrlTestMailer.signed_up_with_url(@recipient).deliver_now } assert_not_nil ActionMailer::Base.deliveries.first delivered = ActionMailer::Base.deliveries.first delivered.message_id = '<123@456>' - assert_equal expected.encoded, delivered.encoded + assert_dom_equal expected.encoded, delivered.encoded end end |