How to send SMTP mail in Ruby using ActionMailer (outside Rails)
Like most bits of Rails, ActionMailer has an elegant and coder friendly interface. With a bit of set up, it’s remarkably quick and easy to get running from vanilla Ruby outside of Rails.
Recently I’ve needed to bulk email a bunch of files to an internal server for testing purposes. I’ve used ActionMailer inside Rails in the past, and wondered how hard it would actually be to get it up and running standalone. Sure, there are a stack of other mail gems and libraries in Ruby to do this, but they expose a lot of the internals of STMP and can be a pain to use. Definitely overkill when all you want to do is quickly fire off some mails from a script. (ActionMailer is actually built on top of a lot of those libraries, and acts like a coder friendly wrapper).
My requirements were pretty simple: Iterate over a bunch of files, and attach each one to a separate email and send to some address.
Here’s what the code looks like for the ActionMailer class:
require 'action_mailer' ActionMailer::Base.smtp_settings = {:address => 'smtp.example.com', :domain => 'example.com'} class FileMailer < ActionMailer::Base def file(to, sender, file_name, content_type, strip_ext = true) # strip any directory fluff subj = file_name.gsub(/.*\//,'') #remove the file extension if required subj = subj.gsub(/\.\w*/,'') if strip_ext #standard ActionMailer message setup recipients to from sender subject subj #setting the body explicitly means we don't have to provide a separate template file body '' #set up the attachment attachment :content_type => content_type, :body => File.read(file_name), :filename => file_name.gsub(/.*\//,'') end end
The only thing different from Rails, is that you need to explicitly configure the SMTP details via ActionMailer::Base#smtp_settings.
It’s worth noting that you don’t actually need to create a .rhtml view file if you specify the body attribute of your message. I ran into a few blogs claiming there was no way to turn off the .rhtml requirement - a quick inspection of the ActionMailer source code proves otherwise. I’m sure it violates good MVC design, but if you’re just throwing together a quick script, who cares. I’ve left the body in the example as an empty string (the server at the other end was only interested in the attachement), but you can specify whatever string you want there.
To use the mailer class, you just call it in the normal Rails ActionMailer manner. With ActionMailer you don’t call the mail action method you implemented, but a generated method prefixed with deliver_. So in our example, even though we implemented a method file, we actually call deliver_file (passing it the same parameters).
FileMailer.deliver_file('recipient@example.com','julian@example.com','my_file.csv','text/csv')