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:
12345678ActionMailer::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:
123456789101112131415161718192021222324252627class 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 filenamefile_path = File.split(voicemail_to_send)file_dir = file_path[0]file_name = file_path[1]# Get the filetmp_file = open(voicemail_to_send).readpart( :content_type => "application/wav",:disposition => "attachment; filename=#{file_name}",:transfer_encoding => "base64") do |attachment|attachment.body = tmp_fileendendend - Create your email scheduler in file lib/email_scheduler.rb:
12345678910111213141516171819202122232425262728293031#!/usr/bin/env /path_to_your_app/script/runner# get all the voicemails that have not been sent yetvoicemails_to_email = VoiceMail.find(:all, :conditions => 'updated_at is null')# For all the voicemails we have, send them and update the field date_sentfor vm2email in voicemails_to_email do# Get the number for the voicemailnumber = Number.find(vm2email.number_id)# check to see if the send to email is set for the numberif number.voicemail_email_set# Get number details (email_to,email_from etc)email_to = number.voicemail_emailvoicemail_to_send = vm2email.audio# Set other detailsemail_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 emailVoicemailMailer.deliver_sent(email_to,email_from,email_subject,email_body,voicemail_to_send)# And update the record's date_sent fieldvm2email.updated_at = Time.nowvm2email.saveendend</li><li>Create a task in your crontab that runs the scheduler (every five minutes):<pre class="code">0,5,10,15,20,25,30,35,40,45,50,55 * * * * path_to_your_ror_app/lib/email_scheduler.rb