Problem
You want to send emails from a Ruby on Rails application, when there is a specific condition on a database table. If the database table gets modified by another application outside Rails you cannot use an observer model.
Solution
We already assume that:
- You are using a database
- You have a model named voicemail (id, number_id, audio, created_at, updated_at)
- You have a model named number (id, voicemail_email_set, voicemail_email, ….)
- A mail server to use (smtp in our case)
- Another application (voice application) populates the voicemail table but with empty updated_at values
So the steps we have to follow are:
- Change the settings in your config/environment.rb file to use the settings for your mail server, and make sure you restart your application after the changes:
ActionMailer::Base.smtp_settings = { :address => "yourmailserver.com", :port => 25, :domain => "your.domain.com", :authentication => :login, :user_name => "your_smtp_username", :password => "your_smtp_password", :raise_delivery_errors => true}
- Create your mailer model (ie voicemail_mailer.rb), in app/models:
class VoicemailMailer < ActionMailer::Base # We need the open-uri to be able to open url *** if the file to attach is in an http location *** require 'open-uri' def sent(email_to,email_from,email_subject,email_body,voicemail_to_send) # Check to see if we have a file for the email body message @subject = email_subject @body = email_body @recipients = email_to @from = email_from @sent_on = Time.now # Split the file in directory and filename file_path = File.split(voicemail_to_send) file_dir = file_path[0] file_name = file_path[1] # Get the file tmp_file = open(voicemail_to_send).read part( :content_type => "application/wav", :disposition => "attachment; filename=#{file_name}", :transfer_encoding => "base64") do |attachment| attachment.body = tmp_file end end end
- Create your email scheduler in file lib/email_scheduler.rb:
#!/usr/bin/env /path_to_your_app/script/runner # get all the voicemails that have not been sent yet voicemails_to_email = VoiceMail.find(:all, :conditions => 'updated_at is null') # For all the voicemails we have, send them and update the field date_sent for vm2email in voicemails_to_email do # Get the number for the voicemail number = Number.find(vm2email.number_id) # check to see if the send to email is set for the number if number.voicemail_email_set # Get number details (email_to,email_from etc) email_to = number.voicemail_email voicemail_to_send = vm2email.audio # Set other details email_from = 'Service@yourdomain.com' email_subject = 'Please find attached your voicemail message' email_body = "Received on: #{Time.now} \n for number: #{number.phone_no}" # Now send the email VoicemailMailer.deliver_sent(email_to,email_from,email_subject,email_body,voicemail_to_send) # And update the record's date_sent field vm2email.updated_at = Time.now vm2email.save end end
- Create a task in your crontab that runs the scheduler (every five minutes):
0,5,10,15,20,25,30,35,40,45,50,55 * * * * path_to_your_ror_app/lib/email_scheduler.rb