Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sending Email with Delayed_Job

I have what I think is a working setup to send emails via Delayed_Job. However, I haven't received my test email and it isn't practical to wait for more to happen with a delay of days. I need to figure out:

  1. What's wrong that's causing the email not to send.
  2. How to test it without waiting days at a time.

I'm new to Delayed_Job, so pardon the newbie mistakes.

Here's the model that includes the send_reminder_emails method. They were fully functional without the .delay(run_at: self.mail_date) bit, so at least I know that much works:

class Reminder < ActiveRecord::Base
  belongs_to :user
  before_save :create_mail_date
  after_save :send_reminder_emails
  extend FriendlyId
  friendly_id :name, use: [:slugged, :finders]

  def create_mail_date
    @schedule = IceCube::Schedule.new(self.date)
    case self.repeating
    when "Weekly"
        @schedule.add_recurrence_rule(
            IceCube::Rule.weekly
        )
    when "Monthly"
        @schedule.add_recurrence_rule(
            IceCube::Rule.monthly.day_of_month(self.date.mon)
        )
    when "Yearly"
        @schedule.add_recurrence_rule(
            IceCube::Rule.yearly.day_of_year(self.date.yday)
        )
    end
    if self.repeating
        self.date = @schedule.next_occurrence(Time.now)
    end
    self.mail_date = self.date - 7.days
  end

  private

  def send_reminder_emails
      if self.reminder
         ReminderMailer.delay(run_at: self.mail_date).reminder_send(self.user, self).deliver_now
         self.create_mail_date
     end
  end
  handle_asynchronously :send_reminder_emails

end

The references to schedule are via the Ice_Cube gem and all of the date stuff has been tested via my console and is working. Here is my reminder_mailer.rb:

class ReminderMailer < ApplicationMailer
  default from: "[email protected]"

  def reminder_send(user, reminder)
    @user = user
    @reminder = reminder

    mail(to: user.email, subject: "Reminder! #{reminder.name} is fast approaching!")
  end
end

I installed Delayed_Job step by step from their readme for Rails 4. Any help getting the delayed part of this mailer ironed out is appreciated!

like image 487
Liz Avatar asked Oct 13 '16 17:10

Liz


2 Answers

You can use Active Job for sending mails by scheduling the job at a particular time.

Active Job is a framework for declaring jobs and making them run on a variety of queuing backends. These jobs can be everything from regularly scheduled clean-ups, to billing charges, to mailings. Anything that can be chopped up into small units of work and run in parallel, really.

For enqueuing and executing jobs in production you need to set up a queuing backend, that is to say you need to decide for a 3rd-party queuing library that Rails should use. Rails itself only provides an in-process queuing system, which only keeps the jobs in RAM. If the process crashes or the machine is reset, then all outstanding jobs are lost with the default async back-end. This may be fine for smaller apps or non-critical jobs, but most production apps will need to pick a persistent backend.

Active Job has built-in adapters for multiple queuing backends (Sidekiq, Resque, Delayed Job and others). To get an up-to-date list of the adapters see the API Documentation for ActiveJob::QueueAdapters.

Once after configuring the queuing adapters, then create Job for sending mails

class RemainderMailerJob < ApplicationJob
  queue_as :default

  def perform(user, remainder)
   ReminderMailer.reminder_send(user, reminder).deliver
  end
end

For sending the mail on a specific time you need to enqueue the job and make it perform at a specific time. If you need to send mail 7 days from now then call this piece of code where ever you need.

RemainderMailerJob.set(wait: 1.week).perform_later(user, remainder)

Now this Job will execute after 1 week, which in turn calls the mailer at that time, so your mails will be sent on the specific day.

IF you knew the specific Date Time then you can use

RemainderMailerJob.set(wait_untill: <Specific date>).perform_later(user, remainder)

If you have any doubts regarding the active job kindly refer Active Job Basics

like image 109
Bala Karthik Avatar answered Oct 22 '22 10:10

Bala Karthik


When you send mails using delayed job, there is no need to add 'deliver' or 'deliver_now' when initializing the delayed_job for mailer. So

ReminderMailer.delay(run_at: self.mail_date).reminder_send(self.user, self)

will itself work.

Convert your 'self.mail_date' to also include the time at which you want to send the mail. Passing only date will not work. Basically the run_at should specify both date and time.

Please check the 'delayed_job' github link under the heading "Rails 3 Mailers" https://github.com/collectiveidea/delayed_job

like image 4
Shabini Rajadas Avatar answered Oct 22 '22 08:10

Shabini Rajadas