Sending emails based on intervals using Ruby on Rails
I would like to be able to send a string of emails at a determined interval to different recipients.
I assign to each Contact this series of Emails called a Campaign, where Campaign has Email1, Email2, etc. Each Contact has a Contact.start_date. Each Email has email.days which stores the number of days since a Contact's start-date to send the email.
For example: Email1.days=5, Email2.days=7, Email3.days=11
Contact1.start_date = 4/10/2010; contact2.start_date = 4/08开发者_Go百科/2010
IF today is 4/15, then Contact1 receives Email 1 (4/15-4/10 = 5 days) IF today is 4/15, then Contact2 received Email 2 (4/15 - 4/8 = 7 days).
What's a good action to run every day using a cron job that would then follow these rules to send out emails using ActionMailer?
NOTE: The question isn't about using ActionMailer. It is about doing the "math" as well as the execution. Which email to send to whom? I am guessing it has to do with some version of Date - Contact[x].start_date and then compare against email[x].days but I'm not exactly clear how. Thanks.
I'd like guidance on whether to use date.today
versus time.now
as well.
Note: the intent is that an individual person may need to schedule individual follow-up on a consistent basis. Rather than having to remember when to follow up which email with whom, it would just follow a pre-determined campaign and send for that person.
So it's not a "bulk mail" -- it's really automating the follow-up for individual correspondence.
I would use DelayedJob for this ( assuming you are not sending large number of emails emails a day, i.e. 100's of thousands per day etc.)
class Email < ActiveRecord::Base
belongs_to :campaign
after_create :schedule_email_dispatch
def schedule_email_dispatch
send_at(campaign.created_at + self.days.days, :send_email)
end
def send_email
end
end
Run the workers using the rake task:
rake jobs:work
Every time a new Email object is created a delayed job item is added to the queue. At the correct interval the email will be sent by the worker.
@campaign = Compaign.new(...)
@campaign.emails.build(:days => 1)
@campaign.emails.build(:days => 2)
@campaign.save # now the delay
In the example above, two delayed job entries will be created after saving the campaign. They are executed 1 and 2 days after the creation date of the campaign.
This solution ensures emails are sent approximately around the expected schedule times. In a cron job based solution, disptaching happens at the cron intervals. There can be several hours delay between the intended dispatch time and the actual dispatch time.
If you want to use the cron approach do the following:
class Email < ActiveRecord::Base
def self.dispatch_emails
# find the emails due for dispatch
Email.all(:conditions => ["created_at <= DATE_SUB(?, INTERVAL days DAY)",
Time.now]).each do |email|
email.send_email
end
end
end
In this solution, most of the processing is done by the DB.
Add email.rake
file in lib/tasks
directory:
task :dispatch_emails => :environment do
Email.dispatch_emails
end
Configure the cron to execute rake dispatch_emails
at regular intervals( in your case < 24 hours)
I would create a rake task in RAILS_ROOT/lib/tasks/email.rake
namespace :email do
desc "send emails to contacts"
task :send do
Email.all.each do |email|
# if start_date is a datetime or timestamp column
contacts = Contact.all(:conditions => ["DATE(start_date) = ?", email.days.days.ago.to_date])
# if start_date is a date column
contacts = Contact.all(:conditions => { :start_date => email.days.days.ago.to_date })
contacts.each do |contact|
#code to send the email
end
end
end
end
Then I would use a cronjob to call this rake task every day at 3 a.m.:
0 3 * * * app_user cd RAILS_APP_FOLDER && RAILS_ENV=production rake email:send
I think it would be much easier and more secure (you don't have to worry on authentication and so on) to create a rake task to send the emails. Also you don't have to worry about a possibly very long running request. Just create a file RAILS_ROOT/lib/tasks/email.rake
namespace :email do
desc "Sends scheduled emails"
task :send_scheduled => :enviroment do
Email.send_scheduled_emails
end
end
and in RAILS_ROOT/app/email.rb
class Email < ActiveRecord::Base
# ...
def self.send_scheduled_emails
#send your emails ...
end
end
Then create a cron job
0 0 * * * user cd /your/rails/app/ && RAILS_ENV=production rake emais:send_scheduled
to send the emails every night at 12:00.
I am using rufus-scheduler for scheduled email and twitter updates. You should check it.
I use ar_mailer gem
http://seattlerb.rubyforge.org/ar_mailer/
http://github.com/adzap/ar_mailer
http://blog.segment7.net/articles/2006/08/15/ar_mailer
精彩评论