Ruby on Rails
HowToSendEmailsWithActionMailer

Note: This page may be out of date with current API
but the initial setup and example have been modified to reflect the use of methods versus instance variables.

My updated tutorial for sending emails, tested with 2.0
How to send email with Ruby on Rails

ActionMailer is a Rails service-layer package for creating email messages.

Generate a mailer

Create a stub file using the generator:

ruby script/generate mailer Notifier

A file is created in your app/models directory named notifier.rb:

class Notifier < ActionMailer::Base
end

A few points to keep in mind

There are a few confusing things to learn with Action Mailer that took a while to figure out.

An Example

The scenario

Let’s assume we’re sending an email to a new user to our website to thank them for signing up, and that user is an object coming from an Active Record that has already been created.

Notifier

Add the following method to your Notifier:

def signup_thanks( user )
  # Email header info MUST be added here
  recipients user.email
  from  "accounts@mywebsite.com"
  subject “Thank you for registering with our website” 

  # Email body substitutions go here
  body :user=> user
end

Notice that it is recipients even if you are only sending to one user.

Controller

And the following snippet to the controller in your application that needs to send an email:

def show_page_after_account_creation
...
  Notifier.deliver_signup_thanks(user)
...
end

This threw me for awhile: Make sure you notice the “deliver_” prefix to the method defined in the Notifier model.

View

The body of the email comes from a .rhtml file in app/views/notifier – In this example; app/views/notifier/signup_thanks.rhtml:
(Note: You might have to end the name with _en.rhtml, i.e.signup_thanks_en.rhtml, if you use localization)

Dear <%= @user.first_name %> <%= @user.last_name %>,

Thanks for signing up with My Website!

Your account will allow you to do blah, blah, blah.

It is possible to use helpers to your email templates simply by adding



helper :application


to your mailer model. (read the article)

Configuration

The mail configuration should be set in your environment. See the API documentation for configuration options. To have your configuration available for all server environments put it in /config/environment.rb, otherwise place it in config/environments/production.rb or config/environments/development.rb.

Make sure ActionMailer is removed from this line in environment.rb:

config.frameworks -= [ :action_web_service, :action_mailer ]

The default method for sending mail is SMTP. ActionMailer can also use sendmail, and for initial testing and development you probably want to switch to that. Stick this in your environment.rb: (After the Rails::Initializer.run do |config| block)

ActionMailer::Base.delivery_method = :sendmail

You may also turn exception raising on and off. The documentation does not state which is the default, so just to be sure, you can turn on exceptions like so:

ActionMailer::Base.raise_delivery_errors = true

A sample configuration setting using the default smtp delivery method would look something like this:

# Include your app's configuration here:
ActionMailer::Base.smtp_settings = {
  :address  => "smtp.postoffice.net",
  :port  => 25, 
  :domain  => "www.mywebsite.com",
  :user_name  => "me@postoffice.net",
  :password  => “mypass”,
  :authentication  => :login
    } 

:domain is the name sent to the SMTP server during the handshake. It will be used to form the first “Received:” header, which spam filters usually check.

If your SMTP server uses “pop before smtp” authentication, check PopBeforeSMTPForActionMailer

You need to restart WEBrick or Apache to reload changes to to your environment.

Note for TextDrive users: On TextDrive, the default settings work, so no explicit configuration is needed. Leave the server_settings as their defaults (ie. don’t set anything).

Attachments

Instead of calling deliver_XX_mail (whatever your method is called) call create_XX_mail... it returns a TMail object

mail = Mailer.create_my_mail(params)

after that, you can set the mime type and append attachments:

mail.set_content_type('multipart', blah blah)
mail.parts << my_attachment
(
  Excuse me, but what is 'blah blah' supposed to be? 
mail.set_content_type(‘multipart’, ‘mixed’) ?
(And is my_attachment just _any_ binary file, 
  or is there some missing encoding process 
  involved?)

then call

Mailer.deliver(mail)

where Mailer is the name of your class that extends ActionMailer::base.

Gem rails added attachment handling


    # attachments
    def signup_notification(recipient)
      recipients      recipient.email_address_with_name
      subject         "New account information" 
      from            "system@example.com"

attachment :content_type => "image/jpeg",
           :filename     => "another-image.jpg" 
           :body         => File.read("an-image.jpg")
end
attachment "application/pdf" do |a|
  a.body = generate_your_pdf_here()
end

You will probably want to specify the filename of the attachment, and also send it along with a text message:


def new_user(user)
    @recipients = user.email
    @from = <a href="mailto:info@mysite.com">info@mysite.com</a>
    @subject = "Welcome to My Site" 

    body = {}
    body['first_name'] = user.first_name
    part :content_type => "text/plain",
         :body => render_message('new_user', body)

    attachment "application/pdf" do |a|
        a.disposition = "attachment" 
        a.filename= "myfilenamethatmightbedifferent.pdf" 
        a.body = File.read(RAILS_ROOT + "/path/to/myfile.pdf")
    end
end

I don’t know if this is the simplest or latest way to do this, but it works for me. Also note that the ‘body’ variable in the example is not the usual ’@body’ instance variable; it is a hash passed to render_message() function. I use this variable in the example to demonstrate the relationship to the standard way of sending an email.

Sending emails with TLS and/or authentication-only SMTP servers

If you encounter a smtp server that requires TLS, then you cannot send emails directly using ActionMailer. But you can still send emails by using a lightweight substitute for sendmail such as msmtp to act as mediatory between ActionMailer and the SMTP server. Here is what I did to get ActionMailer up and running:

  1. Download and install msmtp
  2. obtain server info (example for gmail):
    msmtp—serverinfo—host=smtp.gmail.com—tls=on—port=587—tls-certcheck=off
  3. this may specify the certificate issuer as “Thawte Premium Server CA”
  4. Download the Thawte certificates and put ThawtePremiumServerCA_b64.txt in a convenient directory
  5. Configure it by putting the following in your $HOME/.msmtprc. Make sure that you set the correct permissions. The file must be owned by the user that will invoke msmtp, and must have 600 as its permission.
    
    account provider
    host <smtp.your-host.com>
    auth on
    port <port_num>
    user <username>
    password <password>
    tls on
    *tls_trust_file <directory>ThawtePremiumServerCA_b64.txt*
    tls_starttls on
    auto_from on
    
    account default : provider
    
    
  6. Then put the following in your environment.rb towards the end. Be sure to replace /usr/local/bin/msmtp with the correct path where your msmtp is installed.
    
    ActionMailer::Base.delivery_method = :msmtp
    
    module ActionMailer
      class Base
        def perform_delivery_msmtp(mail)
          IO.popen("/usr/local/bin/msmtp -t -C /path/to/your/.msmtprc -a provider --", "w") do |sm|
            sm.puts(mail.encoded.gsub(/\r/, ''))
            sm.flush
          end
          if $? != 0
            # why >> 8? because this is posix and exit code is in bits 8-16
            logger.error("failed to send mail errno #{$? >> 8}")
          end
        end
      end
    end
    
    
  7. You are done. You should be able to send emails using ActionMailer through a TLS and/or authentication only SMTP server without any problems.

Another way to do this is outlined http://stephenchu.blogspot.com/2006/06/how-to-use-gmail-smtp-server-to-send.html

Along the same lines is http://blog.pomozov.info/posts/how-to-send-actionmailer-mails-to-gmailcom.html but it seems a little easier to follow. Be sure to scroll down to the updated version.

Tips

class AdminMailer < ActionMailer::Base
  def message(recipient, subject, body)
    @from = "admin@expresstrans.com"
    @recipients, @subject, @body = recipient, subject, body
  end
end

Mass mailing
When you want to send a mail to a large number of recipients, you shouldn’t do it purely with ActiveMailer as it opens an SMTP connection for each mail sent. You can find a script to do just that at Mass mailing with ActiveMailer,

Questions

*Can someone give more info for mass mailing? The link is not very helpful as far as a step by step process.. (do you HAVE to send mails from the command line? What if you want to send mails from a form on your site? How does that work?)

Hi All I am getting error code 69 while using msmtp please help me to come out of this my email id is aashutosh.tiwari@in.v2solutions.com

can somebody help me by telling how to get a smtp server

Screencast:
How to send emails with pdf attachments in Rails2.0