Use ar_mailer for future mail delivery

This little howto describes, how to use ar_mailer to schedule emails for future delivery.

Sorry for the bad formatting. Might change it someday…
1) Migrate emails table and add needed fields

  add_column :emails, :various, :string #holds classname and id of any object you want to
  add_column :emails, :type, :string #type of email
  add_column :emails, :date_to_send, :date #date to send that mail

2) Override “def find” in email.rb

  def self.find(*args)
    with_scope(:find=>{ :conditions=>["(date_to_send IS NULL OR date_to_send <= ?)", Date.today] }) do
      super(*args)
    end
  end

3) Create DelayedEmail class, inherting Email

  class DelayedEmail < Email
    before_save :set_due_date
    before_save :set_various_field
    @@days_before_sending = 21 #default is 3 weeks after creation of various object
    @@various_class = nil

    def set_due_date
      self.date_to_send = Date.today + @@days_before_sending
    end

    def set_various_field
      name = @@various_class.class.to_s + "_" rescue "NOCLASS_"
      id = @@various_class.id.to_s rescue "0"
      self.various = name + id
    end

    #tell email to which object it belongs. might be important for future deletion of unsent mails
    def self.set_various_class(c)
      @@various_class = c
    end

    #tell email how many days shall pass by before sending email
    def self.set_days(days)
      @@days_before_sending = days
    end
  end

4) Modify ar_mailer standard emailer class in controller before delivery and set it back afterwards

  DelayedEmail.set_days(10)
  DelayedEmail.set_various_class(SOMEOBJECT)
  ActionMailer::ARMailer.email_class=DelayedEmail
  #Let any mailer send an email through this class
  #eg. Mailer.deliver_mymail(...)
  ActionMailer::ARMailer.email_class=Email