New ActionMailer API in Rails 3.0

26 January 2010

Action Mailer has long been the black sheep of the Rails family. Somehow, through many arguments, you get it doing exactly what you want. But it takes work! Well, we just fixed that.

Action Mailer now has a new API.

But why? Well, I had an itch to scratch, I am the maintainer for TMail, but found it very hard to use well, so I sat down and wrote a really Ruby Mail library, called, imaginatively enough, Mail

But Action Mailer was still using TMail, so then I replaced out TMail with Mail in Action Mailer

And now, with all the flexibility that Mail gives us, we all thought it would be a good idea to re-write the Action Mailer DSL. So with a lot of ideas thrown about between David, Yehuda and myself, we came up with a great DSL.

I then grabbed José Valim to pair program together (with him in Poland to me in Sydney!) on ripping out the guts of Action Mailer and replacing it with a lean, mean mailing machine.

This was merged today.

So what does this all mean? Well, code speaks louder than words, so:

Creating Email Messages:

Instead of this:

 class Notifier < ActionMailer::Base
   def signup_notification(recipient)
     recipients      recipient.email_address_with_name
     subject         "New account information"
     from            ""
     content_type    "multipart/alternative"
     body            :account => recipient

     part :content_type => "text/html",
       :data => render_message("signup-as-html")

     part "text/plain" do |p|
       p.body = render_message("signup-as-plain")
       p.content_transfer_encoding = "base64"

     attachment "application/pdf" do |a|
       a.body = generate_your_pdf_here()

     attachment :content_type => "image/jpeg",
       :body =>"an-image.jpg")


You can do this:

class Notifier < ActionMailer::Base
  default :from => ""

  def signup_notification(recipient)
    @account = recipient

    attachments[''] ="an-image.jpg")
    attachments['terms.pdf'] = {:content => generate_your_pdf_here() }

    mail(:to => recipient.email_address_with_name,
         :subject => "New account information")

Which I like a lot more :)

Any instance variables you define in the method become available in the email templates, just like it does with Action Controller, so all of the templates will have access to the \@account instance var which has the recipient in it.

The mail method above also accepts a block so that you can do something like this:

def hello_email
  mail(:to => recipient.email_address_with_name) do |format|
    format.text { render :text => "This is text!" }
    format.html { render :text => "<h1>This is HTML</h1>" }

In the same style that a respond_to block works in Action Controller.

Sending Email Messages:

Additionally, sending messages has been simplified as well. A Mail::Message object knows how to deliver itself, so all of the delivery code in Action Mailer was simply removed and responsibility given to the Mail::Message.

Instead of having magic methods called deliver* and create* we just call the method which returns a Mail::Message object, and you just call deliver on that:

So this:


Becomes this:


And this:

message = Notifier.create_signup_notification(recipient)

Becomes this:

message = Notifier.signup_notification(recipient)

You still have access to all the usual types of delivery agents though, :smtp, :sendmail, :file and :test, these all work as they did with the prior version of ActionMailer.

Receiving Emails

This has not changed, except now you get a Mail::Message object instead of a TMail object.

Mail::Message will be getting a :reply method soon which will automatically map the Reply related fields properly. Once this is done, we will re-vamp receiving emails as well to simplify.


And… of course, if you still “like the old way”, the new Action Mailer still supports the old API and all the old tests still pass. We have moved everything relating to the old API into deprecated_api.rb and this will be removed in a future release of Rails.


With Mail and this refactor, Action Mailer has now finally become just a DSL wrapper between Mail and Action Controller.



results matching ""

    No results matching ""