ActionMailer::Base
- and the best way to do that is use Rails to generate it:ruby script/generate mailer MyMailer send_book
This also creates some default views (in this case just one, send_book) and tests, but we will discuss that later. Let us suppose we want to send an e-mail with a record from a table called books. In a moment, we will set up a method called send_book in
MyMailer
, but first, let us look at how we will invoke the mailer. In books_controller
, to send the mail, you need to invoke a class method that starts deliver_
.MyMailer.deliver_send_book(:user => current_user, :data => find_book)
Somewhere in
ActionMailer::Base
, there is a method_missing
method that handles your request. It creates an instance of MyMailer
, does some setting up that we do not have to worry about, then invokes the method send_book
. This is where we assign values specific to this e-mail. It might look like this:def send_book(options)
@recipients = "#{options[:user].email}"
@from = "book-database@mydomain.com"
@subject = "Record from book database"
@sent_on = Time.now
@content_type = 'text/html'
@body[:user] = options[:user]
@body[:book] = options[:data]
end
Note that this will send the message in HTML format; it will default to plain text if there is no
@content_type
.Next the
method_missing
method creates the text of the e-mail. It does this in the normal Rails manner, i.e., from a file in the views folder. In this case it will use views/my_mail/send_book.html.erb
. When you create views/my_mail/send_book.erb
, you have access to any variable you assign to the @body
hash, so in the example above, I could use @user
and @book
, just as in a normal view. Similarly, you can use partials from other models/controllers in the normal way.Finally
ActionMailer
sends the e-mail. It needs to know your your mail settings, which it will collect from a file mail.rb
in config/initializers
. This might look something like this:# Email settings
ActionMailer::Base.delivery_method = :smtp
ActionMailer::Base.smtp_settings = {
:address => "smtp.mydomain.com",
:port => 25,
:domain => "mydomain.com",
:authentication => :login,
:user_name => "rails",
:password => "secret"
}
You can use your helper files in your mail views just like your normal views, just remember to declare them at the top of MyMailer:
helper :application
The one slight difference is that you cannot do
helper :all
. I imagine an oversight in Rails.Attachments can be added easily:
attachment "application/rtf" do |a|
a.body = File.read 'some_file.rtf'
a.filename = 'samples.rtf'
end
Testing
You can test your mailer. Rails will have generated a default unit test (no functional testing as there is no controller for a mailer).
require 'test_helper'
class MyMailerTest < ActionMailer::TestCase
tests MyMailer
def test_send_book
@expected.subject = 'MyMailer#send_book'
@expected.body = read_fixture('send_book')
@expected.date = Time.now
assert_equal @expected.encoded,
MyMailer.create_send_book(@expected.date).encoded
end
end
NB: The generated unit test includes a statement
tests MyMailer
. This seems to just invoke write_inheritable_attribute
, which appears to make a copy of the class variables in te superclass in the subclass.Struggling with Ruby: Contents Page
2 comments:
Well put together article. Just one thing that I normally do instead of using the initializer is put the information in the environment config files. It lets you set environment-specific settings which comes in handy at my work place. It looks a little different:
config.action_mailer.delivery_method = :smtp
"The one slight difference is that you cannot do helper :all. I imagine an oversight in Rails."
Actually, they've just decided that it's not necessary (https://rails.lighthouseapp.com/projects/8994/tickets/1119-helper-all-for-actionmailer)... strange.
Post a Comment