Action Mailer
Action Mailer is the part of Rails that allows you to send emails.
Mailers go in app/mailers
. They are similar to controllers and uses views in app/views
.
For more info:
Action Mailer is the part of Rails that allows you to send emails.
Mailers go in app/mailers
. They are similar to controllers and uses views in app/views
.
For more info:
We are going to use mailers to implement a basic welcome email feature for our site.
$ rails g mailer UserMailer welcome
You can execute this mailer in the rails console like this:
$ rails c
Loading development environment (Rails 4.1.0)
>> UserMailer.welcome.deliver
You will see the email message printed out in the console, but this isn't a very good way to preview email. Let's install mailcatcher to make this better.
Mail Catcher is a server that runs on your machine that receives email and then allows you to preview those messages. This is useful for development and testing because it doesn't matter who these emails are from or to, they all end up in mail catcher.
Mail Catcher is packaged as a gem, so to install it, you simply install the gem:
$ gem install mailcatcher
Then, you have to start up mail catcher:
$ mailcatcher
Starting MailCatcher
==> smtp://127.0.0.1:1025
==> http://127.0.0.1:1080
*** MailCatcher runs as a daemon by default. Go to the web interface to quit.
If you restart your computer, it will stop running, so you may have to do this again. It's ok if you try to start it again, you will just get this message:
$ mailcatcher
Starting MailCatcher
~~> ERROR: Something's using port 1025. Are you already running MailCatcher?
Before we can use this, we need to configure Rails to use it.
The documentation at http://mailcatcher.me actually has instructions on how to do this, but all you need to do is add these two lines before the end of the configure block in config/environments/development.rb
:
config.action_mailer.delivery_method = :smtp
config.action_mailer.smtp_settings = { :address => "localhost", :port => 1025 }
Now start a new rails console and send the welcome
message again:
$ rails c
Loading development environment (Rails 4.1.0)
>> UserMailer.welcome.deliver
Rendered user_mailer/welcome.text.erb (1.8ms)
Open http://localhost:1080 in another tab
You should see something like this:
Rails 4.1 has a new feature that allows you to preview emails without having to use Mailcatcher. Go to this URL:
http://localhost:3000/rails/mailers
You will be able to click though the links to see your welcome email.
When you generate links in emails, they need to be a full URL including the domain name of your site, not just a relative link. In order to do that, Rails needs to know what domain name to use. In config/environments/development.rb
, use this setting:
config.action_mailer.default_url_options = { host: "localhost", port: 3000 }
In config/environments/production.rb
, it will look something like this:
config.action_mailer.default_url_options = {
host: "serene-thicket-5859.herokuapp.com"
}
Now in the email ERB templates, use the same code, but be sure to use the _url
version of the route methods instead of _path
, like this:
<%= link_to "Log In", admin_login_url %>
Right now our mailer has a hard-coded to address, an incorrect from address and no dynamic content, so let's fix all that. First, modify the mailer to use a from address that matches you app, like this:
default from: "support@serene-thicket-5859.herokuapp.com"
In a real app, you should switch this to your real domain name. Next, change the welcome
mailer method to look like this:
def welcome(user)
@name = user.email.split('@').first
mail to: user.email
end
The method now takes an argument, which will be an active record user object. We use that object to first set an instance variable that we will later use in the view. Then we change the to
to be the email address of the user. Change the view to use that instance variable:
<h1>Welcome, <%= @name %></h1>
If you try to preview this mailer now, you will get an error, because we need to modify the preview, so let's do that next.
When we generated the mailer, a file test/mailers/previews/user_mailer_preview.rb
was generated to allow us to preview the mailer. When the mailer accepts no arguments, it works fine, but if you need to pass arguments to the mailer, as we do with the user record, then modify the preview code to do that. Modify the welcome
method to look like this:
def welcome
UserMailer.welcome(User.last)
end
Now if you preview that mailer, it should work.
In production, we will need a provider to handle mail delivery. A good one to use is Mailgun. Add it to your app like this:
$ heroku addons:add mailgun
Adding mailgun on serene-thicket-5859... done, v12 (free)
Then update config/environments/production.rb
with the following configuration:
config.action_mailer.smtp_settings = {
port: ENV['MAILGUN_SMTP_PORT'],
address: ENV['MAILGUN_SMTP_SERVER'],
user_name: ENV['MAILGUN_SMTP_LOGIN'],
password: ENV['MAILGUN_SMTP_PASSWORD'],
domain: 'serene-thicket-5859.herokuapp.com',
authentication: :plain,
}
config.action_mailer.delivery_method = :smtp
Commit the changes and push them to Heroku as normal with git push heroku master
. Once you have, to test that it working, run heroku run rails c
to get a rails console at Heroku, then run this code to send an email to yourself:
UserMailer.welcome(User.first).deliver
This assumes that the first user in your database at Heroku has an email address that matches yours. If it does not, either change it or create a user that does have your email address and use that.
Create User Mailer, get it working locally first and then deploy it to Heroku
Create a sign up form that allows anyone who visits your site to create a customer.
When someone signs up and creates a customer, make it so there is a timestamp column called verified_at
that is initially null. When a customer is created, send them a welcome email with a link in it to verify that they own that email address. When they click the link, have it set the value for verified_at
to the current time, unless it is already set.
Hint: Use the new Rails 4.1 Application Message Verifier to secure the link by using generate
to put the customer id in the URL that they click on and then using verify
to get the value back out in the action that the URL goes to