DEV Community

jhalfman
jhalfman

Posted on

Action Mailer in Ruby on Rails (and how to deploy with Gmail)

Active Mailer

If you've ever wondered how to get your rails server to send out emails, Ruby on Rails has fortunately provided just the tool. Action Mailer is a class that inherits from ActionMailer::Base, which inherits from AbstractController::Base. This means that Action Mailer functions a lot like an Action Controller, but they are kept in app/mailers instead of app/controllers. Just like with a controller, we can send a mailer different params and craft what is sent by the mailer actions. Once we have the mailer set up, we can call it from inside our other controllers!

Set up

Mailers can be generated just like other resources using rails generate mailer <mailer name>, where <mailer name> is what you want to call your mailer. This will generate a file called application_mailer.rb (if it doesn't already exist), along with the mailer with the name you specified. The ApplicationMailer class is set to inherit from ActionMailer::Base, while your specified mailer inherits from ApplicationMailer.
Image description In this example, we're creating a UserMailer to handle emails involved with user actions, like signing up for a web service.
Image descriptionThe default method is used to set the default values for each mailer, and here the default :from value is being set to specify which email address this mailer sends from. The ApplicationMailer default can be overridden within the individual mailers with their own default values, and the mailers' default values can be overridden per individual email.

Mailer methods

As with a controller, we can define methods inside our mailers to help craft and send our emails. For example, we can create a method to be called when a user creates a new account. The mailer has access to the params hash, so we can send valuable information, such as an email address or username, to the mailer to be utilized in the email creation.
Image descriptionThe mail action is what creates the email to be sent. Inside mail, we can declare the :to value as the recipient's email address, and the :subject value with our email subject. As seen above, we can utilize variables within our mail action to help specify these values.

Layouts and Views

When we generated our mailer, we should also have created some files in our views folder. /app/views/layouts/mailer.html.erb and /app/views/layouts/mailer.text.erb are utilized as the general email layout declared by layout 'mailer' in our ApplicationMailer. When we have both an HTML and a text template, Action Mailer will automatically combine the templates into a multipart email. To make a template specific to our new mailer method, we will name it accordingly and place it in the appropriate view folder, /app/views/user_mailer/new_user_email.html.erb and /app/views/user_mailer/new_user_email.text.erb. Then we will create the email we want to send when the corresponding method is called.Image descriptionImage descriptionNow, when our #new_user_email method is called from our UserMailer, rails knows to utilize the view in the views/user_mailer folder that is called new_user_email.html.erb and new_user_email.text.erb.

Calling the Mailer

Now that we have our mailer, a mailer method, and a mailer view for that method, all we have to do is call the mailer. We can do this from inside any controller, and for our #new_user_email method, we'll call it from inside the #create method used to make a new user.Image descriptionIn order for our mailer to have access to user variables, we pass them down as params using #with. Since our #new_user_email method utilizes the @firstname and @email attributes, we must pass them through params. Then, we specify which method we'd like to call from our UserMailer, in this case #new_user_email. Finally, we can utilize #deliver_now or #deliver_later to declare when we want the mailer method to be called. When a new user is created with the #create method, the mailer will be called with the relevant attributes being passed down, and an email will be sent using that method's view. Notice we can even utilize the variables inside the view if we receive them as instance variables from the controller. This helps customize each email with whatever unique information gets passed through the params hash.
For a more detailed list of everything offered by the Action Mailer, including how to set attachments and other ways to configure your mailer settings, https://guides.rubyonrails.org/action_mailer_basics.html#complete-list-of-action-mailer-methods

Action Mailer for Gmail

In order to get Action Mailer correctly configured for your specified :from email address, there are various settings that can be adjusted to make the mailer work. Here I will provide configuration settings for a personal gmail account. The settings are accessed using config.action_mailer, and configuration settings are best placed in your config/environments folder.

Configuration settings

For gmail,

  config.action_mailer.delivery_method = :smtp
  host = 'localhost:3000'
  config.action_mailer.default_url_options = { :host => 'localhost:3000', protocol: 'http' }
  config.action_mailer.smtp_settings = {
    address:              'smtp.gmail.com',
    port:                 587,
    user_name:            `<gmail_username>`,
    password:             `<gmail_password>`,
    authentication:       'plain',
    enable_starttls_auto: true
  }
Enter fullscreen mode Exit fullscreen mode

First, the delivery method must be specified as :smtp. The port does not need to be adjusted, and you can set your host server to your local machine if that's what you're using. Most importantly, you need to provide a username and password for the email account. If your email uses two-factor authentication, go to gmail -> manage your google account -> security -> 2-step verification -> app passwords, and select a new app and device and click "generate" to create a password to bypass the two-factor authentication. Your username will still be the email address you want to use, but the password will be this newly generated string.

Safety

If you don't want to end up the victim of a password scraper when you accidentally push up your credentials to git, allowing your personal email to be hijacked into a german spam bot (speaking from experience), you need to implement some precautions to your code. First, I recommend testing with a new email address, just in case. Second, we need to save our credentials within environment files so they aren't plain to read. To do this, place the following in your application.rb file:

config.before_configuration do
   env_file = File.join(Rails.root, 'config', 'local_env.yml')
   YAML.load(File.open(env_file)).each do |key, value|
     ENV[key.to_s] = value
   end if File.exists?(env_file)
end
Enter fullscreen mode Exit fullscreen mode

This allows variables to be accessed from another file, in this case 'local_env.yml'. Now, create that file, and inside you can save your credentials.
Image descriptionNow we can access these new key/value pairs else-where in our set up files. To access our variables, we'll utilize ENV[key] in our credentials object:

config.action_mailer.smtp_settings = {
    address:              'smtp.gmail.com',
    port:                 587,
    user_name:            ENV["EMAIL"],
    password:             ENV["EMAILPASSWORD"],
    authentication:       'plain',
    enable_starttls_auto: true
  }
Enter fullscreen mode Exit fullscreen mode

Finally, in order to keep the identities of these variables hidden, we will add /config/local_env.yml to our .gitignore file. When we push our project up to git, no one will be able to access our email and password!

Conclusion

I hope this was helpful in getting your Action Mailer up and running. There are many uses for this tool, and it can really add some extra interactivity into a web app or other project. Don't forget to keep any credentials/passwords safe and hidden.

Top comments (0)