action_mailer_basics.md 24.0 KB
Newer Older
1 2
Action Mailer Basics
====================
3

F
Fiona Tay 已提交
4
This guide provides you with all you need to get started in sending and
5 6
receiving emails from and to your application, and many internals of Action
Mailer. It also covers how to test your mailers.
7

8 9
After reading this guide, you will know:

10 11 12 13
* How to send and receive email within a Rails application.
* How to generate and edit an Action Mailer class and mailer view.
* How to configure Action Mailer for your environment.
* How to test your Action Mailer classes.
14

15
--------------------------------------------------------------------------------
16

17 18
Introduction
------------
19

20 21 22 23
Action Mailer allows you to send emails from your application using mailer classes
and views. Mailers work very similarly to controllers. They inherit from
`ActionMailer::Base` and live in `app/mailers`, and they have associated views
that appear in `app/views`.
24

25 26
Sending Emails
--------------
27

28 29
This section will provide a step-by-step guide to creating a mailer and its
views.
30

31
### Walkthrough to Generating a Mailer
32

33
#### Create the Mailer
34

P
Prem Sichanugrist 已提交
35
```bash
36
$ bin/rails generate mailer UserMailer
37 38 39 40
create  app/mailers/user_mailer.rb
invoke  erb
create    app/views/user_mailer
invoke  test_unit
M
Mike Moore 已提交
41
create    test/mailers/user_mailer_test.rb
42
```
43

44 45 46 47 48 49 50 51 52 53 54
As you can see, you can generate mailers just like you use other generators with
Rails. Mailers are conceptually similar to controllers, and so we get a mailer,
a directory for views, and a test.

If you didn't want to use a generator, you could create your own file inside of
app/mailers, just make sure that it inherits from `ActionMailer::Base`:

```ruby
class MyMailer < ActionMailer::Base
end
```
55

56
#### Edit the Mailer
57

58 59 60 61 62
Mailers are very similar to Rails controllers. They also have methods called
"actions" and use views to structure the content. Where a controller generates
content like HTML to send back to the client, a Mailer creates a message to be
delivered via email.

63
`app/mailers/user_mailer.rb` contains an empty mailer:
64

65
```ruby
66
class UserMailer < ActionMailer::Base
67
  default from: 'from@example.com'
68
end
69
```
70

71 72
Let's add a method called `welcome_email`, that will send an email to the user's
registered email address:
73

74
```ruby
75
class UserMailer < ActionMailer::Base
76
  default from: 'notifications@example.com'
77

78
  def welcome_email(user)
79
    @user = user
80
    @url  = 'http://example.com/login'
81
    mail(to: @user.email, subject: 'Welcome to My Awesome Site')
82 83
  end
end
84
```
85

86 87 88
Here is a quick explanation of the items presented in the preceding method. For
a full list of all available options, please have a look further down at the
Complete List of Action Mailer user-settable attributes section.
89

90 91 92 93 94
* `default Hash` - This is a hash of default values for any email you send from
this mailer. In this case we are setting the `:from` header to a value for all
messages in this class. This can be overridden on a per-email basis.
* `mail` - The actual email message, we are passing the `:to` and `:subject`
headers in.
95

96 97
Just like controllers, any instance variables we define in the method become
available for use in the views.
98

99
#### Create a Mailer View
100

101 102
Create a file called `welcome_email.html.erb` in `app/views/user_mailer/`. This
will be the template used for the email, formatted in HTML:
103

104
```html+erb
105
<!DOCTYPE html>
106 107
<html>
  <head>
108
    <meta content='text/html; charset=UTF-8' http-equiv='Content-Type' />
109 110
  </head>
  <body>
111
    <h1>Welcome to example.com, <%= @user.name %></h1>
112
    <p>
113
      You have successfully signed up to example.com,
114
      your username is: <%= @user.login %>.<br>
115 116
    </p>
    <p>
117
      To login to the site, just follow this link: <%= @url %>.
118 119 120 121
    </p>
    <p>Thanks for joining and have a great day!</p>
  </body>
</html>
122
```
123

124 125 126
Let's also make a text part for this email. Not all clients prefer HTML emails,
and so sending both is best practice. To do this, create a file called
`welcome_email.text.erb` in `app/views/user_mailer/`:
127

128
```erb
129 130 131
Welcome to example.com, <%= @user.name %>
===============================================

132 133
You have successfully signed up to example.com,
your username is: <%= @user.login %>.
134 135 136 137

To login to the site, just follow this link: <%= @url %>.

Thanks for joining and have a great day!
138
```
139

140 141
When you call the `mail` method now, Action Mailer will detect the two templates
(text and HTML) and automatically generate a `multipart/alternative` email.
P
Pratik Naik 已提交
142

143
#### Calling the Mailer
144

145 146
Mailers are really just another way to render a view. Instead of rendering a
view and sending out the HTTP protocol, they are just sending it out through the
147
email protocols instead. Due to this, it makes sense to just have your
148
controller tell the Mailer to send an email when a user is successfully created.
149

150
Setting this up is painfully simple.
151

152
First, let's create a simple `User` scaffold:
153

P
Prem Sichanugrist 已提交
154
```bash
155 156
$ bin/rails generate scaffold user name email login
$ bin/rake db:migrate
157
```
158

159
Now that we have a user model to play with, we will just edit the
160
`app/controllers/users_controller.rb` make it instruct the `UserMailer` to deliver
161 162
an email to the newly created user by editing the create action and inserting a
call to `UserMailer.welcome_email` right after the user is successfully saved:
163

164
```ruby
165 166
class UsersController < ApplicationController
  # POST /users
167
  # POST /users.json
168 169 170 171 172
  def create
    @user = User.new(params[:user])

    respond_to do |format|
      if @user.save
173
        # Tell the UserMailer to send a welcome email after save
174 175
        UserMailer.welcome_email(@user).deliver

176 177
        format.html { redirect_to(@user, notice: 'User was successfully created.') }
        format.json { render json: @user, status: :created, location: @user }
178
      else
179 180
        format.html { render action: 'new' }
        format.json { render json: @user.errors, status: :unprocessable_entity }
181 182
      end
    end
183
  end
184
end
185
```
186

187 188
The method `welcome_email` returns a `Mail::Message` object which can then just
be told `deliver` to send itself out.
189

190
### Auto encoding header values
191

192 193
Action Mailer handles the auto encoding of multibyte characters inside of
headers and bodies.
194

195 196 197
For more complex examples such as defining alternate character sets or
self-encoding text first, please refer to the
[Mail](https://github.com/mikel/mail) library.
198

199
### Complete List of Action Mailer Methods
200

201 202
There are just three methods that you need to send pretty much any email
message:
203

204 205 206 207 208 209 210 211
* `headers` - Specifies any header on the email you want. You can pass a hash of
  header field names and value pairs, or you can call `headers[:field_name] =
  'value'`.
* `attachments` - Allows you to add attachments to your email. For example,
  `attachments['file-name.jpg'] = File.read('file-name.jpg')`.
* `mail` - Sends the actual email itself. You can pass in headers as a hash to
  the mail method as a parameter, mail will then create an email, either plain
  text, or multipart, depending on what email templates you have defined.
212

213
#### Adding Attachments
214

215
Action Mailer makes it very easy to add attachments.
216

217 218 219
* Pass the file name and content and Action Mailer and the
  [Mail gem](https://github.com/mikel/mail) will automatically guess the
  mime_type, set the encoding and create the attachment.
220

221 222 223
    ```ruby
    attachments['filename.jpg'] = File.read('/path/to/filename.jpg')
    ```
224

225 226 227 228 229
  When the `mail` method will be triggered, it will send a multipart email with
  an attachment, properly nested with the top level being `multipart/mixed` and
  the first part being a `multipart/alternative` containing the plain text and
  HTML email messages.

230 231 232
NOTE: Mail will automatically Base64 encode an attachment. If you want something
different, encode your content and pass in the encoded content and encoding in a
`Hash` to the `attachments` method.
233

234 235
* Pass the file name and specify headers and content and Action Mailer and Mail
  will use the settings you pass in.
236

237 238
    ```ruby
    encoded_content = SpecialEncode(File.read('/path/to/filename.jpg'))
239 240 241 242 243
    attachments['filename.jpg'] = {
      mime_type: 'application/x-gzip',
      encoding: 'SpecialEncoding',
      content: encoded_content
    }
244
    ```
245

246 247
NOTE: If you specify an encoding, Mail will assume that your content is already
encoded and not try to Base64 encode it.
248

249
#### Making Inline Attachments
250

251
Action Mailer 3.0 makes inline attachments, which involved a lot of hacking in pre 3.0 versions, much simpler and trivial as they should be.
252

253
* First, to tell Mail to turn an attachment into an inline attachment, you just call `#inline` on the attachments method within your Mailer:
254

255 256 257 258 259
    ```ruby
    def welcome
      attachments.inline['image.jpg'] = File.read('/path/to/image.jpg')
    end
    ```
260

261 262 263
* Then in your view, you can just reference `attachments` as a hash and specify
  which attachment you want to show, calling `url` on it and then passing the
  result into the `image_tag` method:
264

265 266
    ```html+erb
    <p>Hello there, this is our image</p>
267

268 269
    <%= image_tag attachments['image.jpg'].url %>
    ```
270

271 272
* As this is a standard call to `image_tag` you can pass in an options hash
  after the attachment URL as you could for any other image:
273

274 275
    ```html+erb
    <p>Hello there, this is our image</p>
276

277 278
    <%= image_tag attachments['image.jpg'].url, alt: 'My Photo',
                                                class: 'photos' %>
279
    ```
280

281
#### Sending Email To Multiple Recipients
282

283 284 285 286
It is possible to send email to one or more recipients in one email (e.g.,
informing all admins of a new signup) by setting the list of emails to the `:to`
key. The list of emails can be an array of email addresses or a single string
with the addresses separated by commas.
287

288
```ruby
289
class AdminMailer < ActionMailer::Base
290 291
  default to: Proc.new { Admin.pluck(:email) },
          from: 'notification@example.com'
V
Vijay Dev 已提交
292

293 294
  def new_registration(user)
    @user = user
295
    mail(subject: "New User Signup: #{@user.email}")
296
  end
297
end
298
```
299

300 301
The same format can be used to set carbon copy (Cc:) and blind carbon copy
(Bcc:) recipients, by using the `:cc` and `:bcc` keys respectively.
302

303
#### Sending Email With Name
304

305 306
Sometimes you wish to show the name of the person instead of just their email
address when they receive the email. The trick to doing that is to format the
307
email address in the format `"Full Name <email>"`.
308

309
```ruby
310 311 312
def welcome_email(user)
  @user = user
  email_with_name = "#{@user.name} <#{@user.email}>"
313
  mail(to: email_with_name, subject: 'Welcome to My Awesome Site')
314
end
315
```
316

317
### Mailer Views
318

319 320 321 322 323
Mailer views are located in the `app/views/name_of_mailer_class` directory. The
specific mailer view is known to the class because its name is the same as the
mailer method. In our example from above, our mailer view for the
`welcome_email` method will be in `app/views/user_mailer/welcome_email.html.erb`
for the HTML version and `welcome_email.text.erb` for the plain text version.
324 325 326

To change the default mailer view for your action you do something like:

327
```ruby
328
class UserMailer < ActionMailer::Base
329
  default from: 'notifications@example.com'
330 331 332

  def welcome_email(user)
    @user = user
333
    @url  = 'http://example.com/login'
334
    mail(to: @user.email,
335 336 337
         subject: 'Welcome to My Awesome Site',
         template_path: 'notifications',
         template_name: 'another')
338 339
  end
end
340
```
341

342 343 344
In this case it will look for templates at `app/views/notifications` with name
`another`.  You can also specify an array of paths for `template_path`, and they
will be searched in order.
345

346 347
If you want more flexibility you can also pass a block and render specific
templates or even render inline or text without using a template file:
348

349
```ruby
350
class UserMailer < ActionMailer::Base
351
  default from: 'notifications@example.com'
352

353
  def welcome_email(user)
354
    @user = user
355
    @url  = 'http://example.com/login'
356
    mail(to: @user.email,
357
         subject: 'Welcome to My Awesome Site') do |format|
358
      format.html { render 'another_template' }
359
      format.text { render text: 'Render text' }
360
    end
P
Pratik Naik 已提交
361
  end
362
end
363
```
364

365 366 367 368
This will render the template 'another_template.html.erb' for the HTML part and
use the rendered text for the text part. The render command is the same one used
inside of Action Controller, so you can use all the same options, such as
`:text`, `:inline` etc.
369

370
### Action Mailer Layouts
371

372 373 374 375
Just like controller views, you can also have mailer layouts. The layout name
needs to be the same as your mailer, such as `user_mailer.html.erb` and
`user_mailer.text.erb` to be automatically recognized by your mailer as a
layout.
376

377
In order to use a different file, call `layout` in your mailer:
378

379
```ruby
380
class UserMailer < ActionMailer::Base
381
  layout 'awesome' # use awesome.(html|text).erb as the layout
382
end
383
```
384

385 386
Just like with controller views, use `yield` to render the view inside the
layout.
387

388
You can also pass in a `layout: 'layout_name'` option to the render call inside
389
the format block to specify different layouts for different formats:
390

391
```ruby
392 393
class UserMailer < ActionMailer::Base
  def welcome_email(user)
394 395
    mail(to: user.email) do |format|
      format.html { render layout: 'my_layout' }
396 397 398 399
      format.text
    end
  end
end
400
```
401

402 403
Will render the HTML part using the `my_layout.html.erb` file and the text part
with the usual `user_mailer.text.erb` file if it exists.
404

405
### Generating URLs in Action Mailer Views
406

407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431
Unlike controllers, the mailer instance doesn't have any context about the
incoming request so you'll need to provide the `:host` parameter yourself.

As the `:host` usually is consistent across the application you can configure it
globally in `config/application.rb`:

```ruby
config.action_mailer.default_url_options = { host: 'example.com' }
```

#### generating URLs with `url_for`

You need to pass the `only_path: false` option when using `url_for`. This will
ensure that absolute URLs are generated because the `url_for` view helper will,
by default, generate relative URLs when a `:host` option isn't explicitly
provided.

```erb
<%= url_for(controller: 'welcome',
            action: 'greeting',
            only_path: false) %>
```

If you did not configure the `:host` option globally make sure to pass it to
`url_for`.
432

433

434
```erb
435 436 437
<%= url_for(host: 'example.com',
            controller: 'welcome',
            action: 'greeting') %>
438
```
439

440 441
NOTE: When you explicitly pass the `:host` Rails will always generate absolute
URLs, so there is no need to pass `only_path: false`.
442

443
#### generating URLs with named routes
444

445 446 447
Email clients have no web context and so paths have no base URL to form complete
web addresses. Thus, you should always use the "_url" variant of named route
helpers.
448

449 450
If you did not configure the `:host` option globally make sure to pass it to the
url helper.
451

452 453
```erb
<%= user_url(@user, host: 'example.com') %>
454
```
455

456
### Sending Multipart Emails
457

458 459 460 461 462
Action Mailer will automatically send multipart emails if you have different
templates for the same action. So, for our UserMailer example, if you have
`welcome_email.text.erb` and `welcome_email.html.erb` in
`app/views/user_mailer`, Action Mailer will automatically send a multipart email
with the HTML and text versions setup as different parts.
463

464 465
The order of the parts getting inserted is determined by the `:parts_order`
inside of the `ActionMailer::Base.default` method.
466

467
### Sending Emails with Dynamic Delivery Options
468

469 470 471
If you wish to override the default delivery options (e.g. SMTP credentials)
while delivering emails, you can do this using `delivery_method_options` in the
mailer action.
472

473
```ruby
474
class UserMailer < ActionMailer::Base
V
Vijay Dev 已提交
475
  def welcome_email(user, company)
476 477
    @user = user
    @url  = user_url(@user)
478 479 480 481 482 483
    delivery_options = { user_name: company.smtp_user,
                         password: company.smtp_password,
                         address: company.smtp_host }
    mail(to: @user.email,
         subject: "Please see the Terms and Conditions attached",
         delivery_method_options: delivery_options)
484 485
  end
end
486
```
487

488 489
### Sending Emails without Template Rendering

490 491
There may be cases in which you want to skip the template rendering step and
supply the email body as a string. You can achieve this using the `:body`
492
option. In such cases don't forget to add the `:content_type` option. Rails
493
will default to `text/plain` otherwise.
494 495 496

```ruby
class UserMailer < ActionMailer::Base
V
Vijay Dev 已提交
497
  def welcome_email(user, email_body)
498 499 500 501
    mail(to: user.email,
         body: email_body,
         content_type: "text/html",
         subject: "Already rendered!")
502 503 504 505
  end
end
```

506 507
Receiving Emails
----------------
508

509 510 511 512
Receiving and parsing emails with Action Mailer can be a rather complex
endeavor. Before your email reaches your Rails app, you would have had to
configure your system to somehow forward emails to your app, which needs to be
listening for that. So, to receive emails in your Rails app you'll need to:
513

514
* Implement a `receive` method in your mailer.
515

516 517 518
* Configure your email server to forward emails from the address(es) you would
  like your app to receive to `/path/to/app/bin/rails runner
  'UserMailer.receive(STDIN.read)'`.
519

520 521 522 523
Once a method called `receive` is defined in any mailer, Action Mailer will
parse the raw incoming email into an email object, decode it, instantiate a new
mailer, and pass the email object to the mailer `receive` instance
method. Here's an example:
524

525
```ruby
526 527
class UserMailer < ActionMailer::Base
  def receive(email)
528
    page = Page.find_by(address: email.to.first)
529
    page.emails.create(
530 531
      subject: email.subject,
      body: email.body
532 533 534
    )

    if email.has_attachments?
535
      email.attachments.each do |attachment|
536
        page.attachments.create({
537 538
          file: attachment,
          description: email.subject
539 540 541 542 543
        })
      end
    end
  end
end
544
```
545

546 547 548
Action Mailer Callbacks
---------------------------

549 550
Action Mailer allows for you to specify a `before_action`, `after_action` and
`around_action`.
551

552 553
* Filters can be specified with a block or a symbol to a method in the mailer
  class similar to controllers.
554

555 556
* You could use a `before_action` to populate the mail object with defaults,
  delivery_method_options or insert default headers and attachments.
557

558 559
* You could use an `after_action` to do similar setup as a `before_action` but
  using instance variables set in your mailer action.
560 561 562

```ruby
class UserMailer < ActionMailer::Base
563 564 565
  after_action :set_delivery_options,
               :prevent_delivery_to_guests,
               :set_business_headers
566 567 568 569 570 571 572 573 574 575 576 577 578 579

  def feedback_message(business, user)
    @business = business
    @user = user
    mail
  end

  def campaign_message(business, user)
    @business = business
    @user = user
  end

  private

580 581 582 583 584 585
    def set_delivery_options
      # You have access to the mail instance,
      # @business and @user instance variables here
      if @business && @business.has_smtp_settings?
        mail.delivery_method.settings.merge!(@business.smtp_settings)
      end
586 587
    end

588 589 590 591
    def prevent_delivery_to_guests
      if @user && @user.guest?
        mail.perform_deliveries = false
      end
592 593
    end

594 595 596 597
    def set_business_headers
      if @business
        headers["X-SMTPAPI-CATEGORY"] = @business.code
      end
598 599 600 601 602 603
    end
end
```

* Mailer Filters abort further processing if body is set to a non-nil value.

604 605
Using Action Mailer Helpers
---------------------------
606

607 608
Action Mailer now just inherits from `AbstractController`, so you have access to
the same generic helpers as you do in Action Controller.
609

610 611
Action Mailer Configuration
---------------------------
612

613 614
The following configuration options are best made in one of the environment
files (environment.rb, production.rb, etc...)
615

616 617
| Configuration | Description |
|---------------|-------------|
618
|`logger`|Generates information on the mailing run if available. Can be set to `nil` for no logging. Compatible with both Ruby's own `Logger` and `Log4r` loggers.|
619
|`smtp_settings`|Allows detailed configuration for `:smtp` delivery method:<ul><li>`:address` - Allows you to use a remote mail server. Just change it from its default `"localhost"` setting.</li><li>`:port` - On the off chance that your mail server doesn't run on port 25, you can change it.</li><li>`:domain` - If you need to specify a HELO domain, you can do it here.</li><li>`:user_name` - If your mail server requires authentication, set the username in this setting.</li><li>`:password` - If your mail server requires authentication, set the password in this setting.</li><li>`:authentication` - If your mail server requires authentication, you need to specify the authentication type here. This is a symbol and one of `:plain`, `:login`, `:cram_md5`.</li><li>`:enable_starttls_auto` - Set this to `false` if there is a problem with your server certificate that you cannot resolve.</li></ul>|
620
|`sendmail_settings`|Allows you to override options for the `:sendmail` delivery method.<ul><li>`:location` - The location of the sendmail executable. Defaults to `/usr/sbin/sendmail`.</li><li>`:arguments` - The command line arguments to be passed to sendmail. Defaults to `-i -t`.</li></ul>|
621
|`raise_delivery_errors`|Whether or not errors should be raised if the email fails to be delivered. This only works if the external email server is configured for immediate delivery.|
622
|`delivery_method`|Defines a delivery method. Possible values are:<ul><li>`:smtp` (default), can be configured by using `config.action_mailer.smtp_settings`.</li><li>`:sendmail`, can be configured by using `config.action_mailer.sendmail_settings`.</li><li>`:file`: save emails to files; can be configured by using `config.action_mailer.file_settings`.</li><li>`:test`: save emails to `ActionMailer::Base.deliveries` array.</li></ul>See [API docs](http://api.rubyonrails.org/classes/ActionMailer/Base.html) for more info.|
623 624 625
|`perform_deliveries`|Determines whether deliveries are actually carried out when the `deliver` method is invoked on the Mail message. By default they are, but this can be turned off to help functional testing.|
|`deliveries`|Keeps an array of all the emails sent out through the Action Mailer with delivery_method :test. Most useful for unit and functional testing.|
|`default_options`|Allows you to set default values for the `mail` method options (`:from`, `:reply_to`, etc.).|
626

627
For a complete writeup of possible configurations see the
628
[Configuring Action Mailer](configuring.html#configuring-action-mailer) in
629 630
our Configuring Rails Applications guide.

631
### Example Action Mailer Configuration
632

633 634
An example would be adding the following to your appropriate
`config/environments/$RAILS_ENV.rb` file:
635

636
```ruby
637 638 639
config.action_mailer.delivery_method = :sendmail
# Defaults to:
# config.action_mailer.sendmail_settings = {
640 641
#   location: '/usr/sbin/sendmail',
#   arguments: '-i -t'
642 643 644
# }
config.action_mailer.perform_deliveries = true
config.action_mailer.raise_delivery_errors = true
645
config.action_mailer.default_options = {from: 'no-reply@example.com'}
646
```
647

648
### Action Mailer Configuration for Gmail
649

650 651
As Action Mailer now uses the [Mail gem](https://github.com/mikel/mail), this
becomes as simple as adding to your `config/environments/$RAILS_ENV.rb` file:
652

653
```ruby
654 655
config.action_mailer.delivery_method = :smtp
config.action_mailer.smtp_settings = {
656 657
  address:              'smtp.gmail.com',
  port:                 587,
658
  domain:               'example.com',
659 660 661 662
  user_name:            '<username>',
  password:             '<password>',
  authentication:       'plain',
  enable_starttls_auto: true  }
663
```
664

665 666
Mailer Testing
--------------
667

668
You can find detailed instructions on how to test your mailers in the
669
[testing guide](testing.html#testing-your-mailers).
670

671 672
Intercepting Emails
-------------------
673

674 675 676 677
There are situations where you need to edit an email before it's
delivered. Fortunately Action Mailer provides hooks to intercept every
email. You can register an interceptor to make modifications to mail messages
right before they are handed to the delivery agents.
678 679 680 681 682 683 684 685 686

```ruby
class SandboxEmailInterceptor
  def self.delivering_email(message)
    message.to = ['sandbox@example.com']
  end
end
```

687 688 689
Before the interceptor can do its job you need to register it with the Action
Mailer framework. You can do this in an initializer file
`config/initializers/sandbox_email_interceptor.rb`
690 691 692 693 694

```ruby
ActionMailer::Base.register_interceptor(SandboxEmailInterceptor) if Rails.env.staging?
```

695 696
NOTE: The example above uses a custom environment called "staging" for a
production like server but for testing purposes. You can read
697
[Creating Rails environments](configuring.html#creating-rails-environments)
698
for more information about custom Rails environments.