Writing a Daily Mailer in Rails
Here’s the scoop;
I had a need to send emails to users at a specific interval in a time period based on two simple conditions:
- Is it the right day?
- Does this user want emails? (Did they opt out yet?)
I elected to run a cron every day at a specific time (using the whenever gem). When it runs, the date is compared to is_nag_time
. If true, every user is looped through checking the latter condition. Let’s get to some code
def get_date_diff
# Get the difference in weeks or months
if self.weekly?
return (Date.today.cweek - self.start_date.cweek).weeks
elsif self.monthly?
return (Date.today.year - self.start_date.year) * 12 + Date.today.month - self.start_date.month - (Date.today.day >= self.start_date.day ? 0 : 1).months
end
end
def current_survey_date
return self.start_date + (self.get_date_diff - 1).days
end
def is_nag_time
return self.current_survey_date + (Date.today.end_of_month.day * 0.75).round.days
end
def current_survey
return self.surveys.find_by_position(self.get_date_diff.to_i)
end
# Determine the current iteration date (current_step_date)
# Add Time percentage to it based on the iteration (weekly or monthly)
def self.do_the_nag
if program.is_nag_time == Date.today
time_to_nag = Time.now
counter = 1
# Loop through users
program.users
.where(:email_opt_in => true)
.each do |user|
if counter > 50
counter = 1
time_to_nag = time_to_nag + 1.minute
end
NagMailer.delay(:run_at => time_to_nag).next_survey_reminder(user, program)
end
end
end
# schedule.rb
every 1.day, :at => '10am' do
runner 'Program.do_the_nag'
end
I think the code is fairly straight forward. I choose to run it on a daily basis, instead of just scheduling the emails in the future, because the dates may change at any given time. I believe this accomidates for most, if not all, situations.