This blog is part of our Rails 5.2 series.
Rails allows sending emails asynchronously via Active Job.
1Notifier.welcome(User.first).deliver_later
It uses ActionMailer::DeliveryJob as the default job class to send emails. This class is defined internally by Rails.
The DeliveryJob defines handle_exception_with_mailer_class method to handle exception and to do some housekeeping work.
1def handle_exception_with_mailer_class(exception) 2 if klass = mailer_class 3 klass.handle_exception exception 4 else 5 raise exception 6 end 7end
One might need more control on the job class to retry the job under certain conditions or add more logging around exceptions.
Before Rails 5.2, it was not possible to use a custom job class for this purpose.
Rails 5.2 has added a feature to configure the job class per mailer.
1class CustomNotifier < ApplicationMailer 2 self.delivery_job = CustomNotifierDeliveryJob 3end
By default, Rails will use the internal DeliveryJob class if the delivery_job configuration is not present in the mailer class.
Now, Rails will use CustomNotifierDeliveryJob for sending emails for CustomNotifier mailer.
1CustomNotifier.welcome(User.first).deliver_later
As mentioned above CustomNotifierDeliveryJob can be further configured for logging, exception handling and reporting.
By default, deliver_later will pass following arguments to the perform method of the CustomNotifierDeliveryJob.
- mailer class name
- mailer method name
- mail delivery method
- original arguments with which the mail is to be sent
1class CustomNotifierDeliveryJob < ApplicationJob 2 3 rescue_from StandardError, with: :handle_exception_with_mailer_class 4 5 retry_on CustomNotifierException 6 7 discard_on ActiveJob::DeserializationError 8 9 def perform(mailer, mail_method, delivery_method, *args) 10 logger.log "Mail delivery started" 11 klass = mailer.constantize 12 klass.public_send(mail_method, *args).send(delivery_method) 13 logger.log "Mail delivery completed" 14 end 15 16 def handle_exception_with_mailer_class(exception) 17 if klass = mailer_class 18 klass.handle_exception exception 19 else 20 raise exception 21 end 22 end 23end
We can also simply inherit from the ActionMailer::DeliveryJob and override the retry logic.
1class CustomNotifierDeliveryJob < ActionMailer::DeliveryJob 2 retry_on CustomNotifierException 3end