Rails Action Mailer with deliver_later on AWS - ruby-on-rails

I have my production app running on AWS but am having issues with the active job - deliver_later on certain mailers. I am successfully sending all emails with deliver_later in development but there is something different in production. Certain mailers work with deliver_later but not my welcome mailer (welcomes new users). So I have to set deliver_now on this welcome mailer to have it actually send the email.
//doesn't work, email is not sent
UserMailer.welcome_email(self).deliver_later
//works
UserMailer.welcome_email(self).deliver_now
The log file from the server show this and nothing more when I use deliver_later:
[ActiveJob] Enqueued ActionMailer::DeliveryJob (Job ID:
d7114-464e-4a90-9721-126650) to Async(mailers) with arguments:
"UserMailer", "welcome_email", "deliver_now", #>
Any help would be appreciated. Thanks.

deliver_now Delivers an email at a time.
If you use deliver_later you have to use ActiveJob runner like Sidekiq you can see this gist Sending emails with ActionMailer and Sidekiq also see this for basic Sidekiq email sent.
Enqueues the email to be delivered through Active Job. When the job runs it will send the email using deliver_now.
UserMailer.welcome_email(self).deliver_later(wait: 1.hour)
method-i-deliver_later
Basically, deliver_later is asynchronous. When you use this method, the email is not sent at the moment, but rather is pushed into a job's queue. If the job is not running, the email will not be sent. deliver_now will send the email at the moment, no matter what is the job's state. Here you can see the documentation for delivery methods.

What ActiveJob backend are you using?
ActiveJob to provide asynchronous execution but does not provide asynchronicity itself.
You need to use some asynchronous backend like sidekiq, delayed_job or something else.

This is because you haven't set the time and rails picking up default time. and in log file also it shows that the deliver_later method is not being called yet.
Try using:
UserMailer.welcome_email(self).deliver_later(wait: 1.minute)
Then check the log after one min.

If you are using delayed_job, you have to run rake jobs:work
https://www.youtube.com/watch?v=AoGPaWEasxs

Related

Testing Mails queued with Sidekiq

Because we need to have the ability to schedule email delivery, we have migrated to using Sidekiq to send emails with the deliver_later method. Under the old regime that used deliver_now, our testing could use
ActionMailer::Base.deliveries[index]
to inspect the recipient, subject, body, attachments, etc...
For testing purposes, is there an equivalent mechanism to inspect the contents of queued email when using Sidekiq and deliver_later?
For testing contents of the email, you have to render the email template for which the job needs to be executed. I suggest you should separate unit tests:
Job spec to check if email is getting enqueued with correct parameters.
Email spec to check the email contents.
If you want to go the end-to-end style, use Sidekiq::Testing.inline! to execute the job and then use ActionMailer::Base.deliveries[index] like before.
The solution turned out to be to execute perform_enqueued_jobs after all emails were queued. After this, all of the existing testing mechanisms worked.
See https://api.rubyonrails.org/v7.0.4/classes/ActiveJob/TestHelper.html for additional information.

Scheduling emails with Action Mailer on heroku

I am trying to schedule an email to be sent with a delay after an action is triggered. I'm using Action Mailer with the deliver_later functionality :
UserMailer.email_form(params[:session][:email]).deliver_later(wait: 2.minute)
It works fine locally and on heroku, except if I restart the server/deploy again while an email is scheduled but hasn't been sent. How do I get around this?
I think the problem is: deliver_later uses ActiveJob (a part/framework of Rails) under the hood to send emails in background. Rails by default comes with an async queue implementation that runs jobs with an in-process thread pool. Jobs will run asynchronously, but any jobs in the queue will be dropped upon restart or process crashes, because they are only in RAM (memory), but not in a persistent backend (DB, Redis).
You should switch to a different adapter (Sidekiq, Resque, Delayed Job, ...) if you want your jobs to be persisted.
You can find more details here.

Sending Devise mail via ActiveJob

in one of our apps we have a running ActiveJob / Sidekiq / ActionMailer setup which is working fine. As it's a booking app we send confirmations to users successfully through this setupo.
We're experiencing difficulties trying to get Devise sending mails on user actions (registration, password_reset, etc.) via ActiveJob.
I've did override the default behavior of notification sending within my User model like so:
def send_devise_notification(notification, *args)
devise_mailer.send(notification, self, *args).deliver_later
end
Update
I've come a step closer. I added a queue Devise pushed it's job to which was missing (XXX_default_mailer_queue) inconfig/sidekiq.yml`. Now Devise successfully pushes jobs to the Sidekiq queue. But unfortunately still no mails become sent, Job execution times are far below 1s:
ActionMailer::DeliveryJob JID-fa4bccc79be489f098c7f5ef INFO: done: 0.415
If i switch to devise_mailer.send(notification, self, *args).deliver_now the proper email gets rendered but not sent either.
As I said, our Mail setup is working apart from Devise which is why I assume it to be a Devise specific problem somewhere
What does Devise do here? How can I debug the process? Normally I would jump somewhere in my job or mailer classes but there are none...
best, Andi

Rails 4.2.5 - ActiveJob using deliver_now even after specifying deliver_later

I plan to send mails asynchronously in Rails 4.2.5 using ActionMailer#deliver_later.
The AppMailer file uses 'mail' to send across the mail & I am using deliver_later as follows:
AppMailer.project_created_support_mail(#project).deliver_later
However, logs show that the argument passed still is 'deliver_now'
[ActiveJob] [ActionMailer::DeliveryJob] [b341ea8c-ca96-4a4e-8079-572925864352] Performing ActionMailer::DeliveryJob from Inline(mailers) with arguments: "AppMailer", "project_created_support_mail", "deliver_now"
I am assuming there isn't an explicit need to attach a queue like Sidekiq or Resque.
Can someone please help in understanding what I am missing here?
EDIT: The original problem I am facing is that the action to send mail takes ~5 seconds with or without deliver_later. In an attempt to debug the issue, I found out that the argument is still 'deliver_now' (logs above). As pointed out by #torrocus below, 'deliver_now' is called inside the queue. However, the issue that deliver_later takes ~5 seconds still remains.
When you call #deliver_later method you put the job into the queue Active Job. Inside the queue it calls #deliver_now.
deliver_later (ActionMailer::MessageDelivery)
In development I propose to use gem mailcatcher

How to keep current_locale when sending email with ActiveJob and Sidekiq?

I am using Active_job and sidekiq to send emails asynchronously. But my current_locale is lost when performing the email sending. I set the I18n.locale by the url patterns of every request.
I used to use Sidekiq, which provide a plugin to store the current_locale, and use it when sending.
But I am now upgrading to Rails 4.2.1, ActiveJob seems it doesn't provide a solution like this.
Any thought?
One way I know is to pass the current_locale as an argument to mailer, then use I18n.with_locale {... }, but this would change many places...

Resources