July 17th 2023
Send mail on Rails 7 with Gmail
How to send mail with your gmail address from your Ruby on Rails application using ActiveMailer.
I was trying to implement Rails' ActiveMailer to send mail from a project of mine with my gmail address and I was surprised how what should have been a simple task ended up being a pain in the ass just because I couldn't find a recent and detailed enough guide on how to enable SMTP mailing with Rails.
I've figured it all out since and I've been asked a couple times to explain the process already so I thought I might as well get all of that into a blog that'd be easier to share in the future.
In this guide we'll enable Gmail to be able to send mail from your app with your gmail address. We'll configure Rails to be able to use this gmail address and we'll create a test mailer to make sure everything works.
At the end of the guide I'll also go over how to use an alias with your gmail address like the redirect address that comes from any Namecheap domain you buy for example.
Enabling Gmail to be used from your Rails app
The first thing is gonna be to create an app password in our gmail account to be able to log in from our website to send mail.
We need to go to that account and access our account settings by clicking on our avatar in the top right corner then on Manage your Google Account
It is a requirement so let's verify that 2-Step Verification is enabled; From the account management home page click on Security
in the navigation bar on the left of the screen. Then under "How to sign in to Google" make sure "2-Step Verification" is enabled and if not, enable it.
We'll then need to access the app password page for our account. From the "Security" tab, under "How to sign in to Google", click on 2-Step Verification
. Once there scroll at the bottom of the page and you'll find a App passwords
button.
Click it.
When prompted to select an app, choose Other (Custom name)
and enter your app's name or any other name you wanna use that'll make it easy for you to remember what this is for.
Then click on generate
and we'll be given a password of 16 characters. Copy it and keep it somwehere for a minute. We'll need this when setting up our Rails application.
That's all for gmail settings, now we can go over to Rails
Storing our Google credentials safely
The second step will be to store your Gmail credentials in your Rails application.
You can use dotenv variables for that but I recommend using Rails credentials
instead.
Rails credentials is an encrypted file that exist in your config folder. The file can only be opened from the terminal and requires the presence of the correct master.key
file in your project (If you have one already you'll find it inside your config
directory).
The master.key must not be pushed to git or github, just like you wouldn't push the .env
file, that means that if you share this project with other people you'll need to give them the master.key so that they can access these encrypted credentials.
The config/credentials.yml.enc
can and should be pushed to git and github on the other hand. It is encrypted so it's perfectly fine to share.
The reasons I prefer this over dotenv variables is that everytime you add a new variable to your .env
file you have to send it to your team, whereas in the case of Rails credentials you only share the master.key
once and because all the credentials are pushed to github inside the encrypted file it means they'll automatically have access to the new ones as long as they update their master branch.
Rails credentials is also a built in Rails tool whereas dotenv relies on a third party gem and in my opinion that's another benefit.
It also relies on a yml file to store the crendentials which allows for a way better file organization with comments, indentation etc if you need it.
Finally, but I have no proof of that so that might be more of a placebo, I suspect that encrypted credentials are safer than dotenv variables.
There are multiple way to open this encrypted file but I find the more convient method to be relying on VSCode's decryption interface. Here's a breakdown of how to add credentials to your Rails encrypted file using that method :
Open a terminal for your current repository.
Run the command EDITOR="code --wait" rails credentials:edit
.
This will open a yml
file in VSCode where you should see at least a secret_key_base
key and its value.
In there add your email address and the gmail app password that you just generated like so
gmail:
address: YOUR_GMAIL_ADDRESS
password: YOUR_APP_PASSWORD
Once that's done you can close the file and it'll save automatically.
You can now access these key from your code by writting Rails.application.credentials.gmail.address
or Rails.application.credentials.gmail.password
Configuring ActionMailer
Finally to configure Rails with SMTP, we have to go inside our config/environments
directory and add a configuration to each files.
config.action_mailer.delivery_method = :smtp
config.action_mailer.default_url_options = { host: YOUR_WEBSITE_URL }
# SMTP settings for Gmail
config.action_mailer.smtp_settings = {
address: "smtp.gmail.com",
port: 587,
user_name: Rails.application.credentials.gmail.address,
password: Rails.application.credentials.gmail.password,
authentication: "plain",
enable_starttls_auto: true
}
config.action_mailer.delivery_method = :smtp
config.action_mailer.default_url_options = { host: "localhost:3000", protocol: "http" }
# SMTP settings for Gmail
config.action_mailer.smtp_settings = {
address: "smtp.gmail.com",
port: 587,
user_name: Rails.application.credentials.gmail.address,
password: Rails.application.credentials.gmail.password,
authentication: "plain",
enable_starttls_auto: true
}
config.action_mailer.delivery_method = :test
config.action_mailer.default_url_options = { host: "localhost:3000", protocol: "http" }
If you don't want to keep sending real mail from your dev environment you can change the config.action_mailer.delivery_method
value from :smtp
to :test
anytime. Just make sure everything works fine beforehand.
The last configuration we need to do before testing it is to go to our app/mailer/application_mailer.rb
file and change the default from:
value to something like this
class ApplicationMailer < ActionMailer::Base
default from: "Louis <contact@louisramos.dev>"
layout "mailer"
end
What the default from mean is that now the email received from your Rails application will be named as "Louis" instead of the raw gmail address. If you want to use your company's name that's perfectly alright too of course. Whatever you wanna address yourself as.
Testing our Rails application
We'll create a new Mailer to test that everything works proprelly.
First, generate a new mailer that we'll call test with the Rails' generator
bin/rails generate mailer example
This will generate a few files. The first one we'll look at is the mailer itself that you'll find in app/mailers/example_mailer.rb
.
We'll create a simple method inside this currently blank mailer to send a "Hello World" to the email of your choice.
class ExampleMailer < ApplicationMailer
def hello_world(contact)
@contact = contact
mail(to: @contact, subject: 'This is an example mail')
# The subject will be the subject of the email being sent
end
end
Next we'll create a template for this action in the mailer directory that was generated in app/views/example_mailer
.
Create a hello_word.html.erb
file in there (the name has to be same as your mailer's action) and add a little templating inside of it. Notice that because we initialized an instance variable inside our ExampleMailer#hello_world
action we are now able to access it from the template
<h1>Hello World</h1>
<p>This email was sent to <%= @contact %>
You can preview this email by going to the test/mailers/previews/example_mailer_preview.rb
file and add a method in it that calls your mailer's action
class ExampleMailerPreview < ActionMailer::Preview
def hello_world
ExampleMailer.hello_world("user@example.com")
end
end
Then follow the url at the top of this file which will probably be http://localhost:3000/rails/mailers/example_mailer
and you'll have a preview of this mail's template.
Now for the actual test open your Rails' console and use the ExempleMailer action we created
bin/rails console
...
Loading development environment (Rails 7.0.4.2)
irb(main):001:1> ExampleMailer.hello_world(YOUR_CHOSEN_EMAIL_ADDRESS).deliver_now
And once you press enter, the email address you entered should receive the hello world email.
That's it, your Rails application can now send mail with your gmail account.
There are two things that can be done from now.
The first one is to set up a asynchronous workflow to your app to be able to deliver emails as background jobs instead of forcing the users to wait until their mail have been sent. With a very small website this wouldn't really matter but with websites like Twitter for example, they send thousands of emails per day so it would be unreasonable for people to wait in a queue until theirs is proprelly sent.
I won't tackle background jobs in this guide but if you wanna do that you can look into Sidekiq
or Good_Job
which are two gems that can do that. Once set up you can send your email asynchronously by using #deliver_later
instead of #deliver_now
.
The second thing we can do is use your redirect address as an alias to your gmail address so that people receive mail from your alias and can send mail to your alias instead of the original name of your address.
Changing Gmail's alias
Once you have a working redirect address, navigate to your gmail address and click on the settings
button that looks like a gear in the top right corner then select See all settings
.
Click on the Accounts and Imports
tab at the top and you'll see a Send mail as
field.
Click on Add another email address
, enter the name you want your mail to be sent as (That could be your company's name for example) and your redirect email address.
Tick the Treat as an alias
checkbox and click on Next Step
You'll then be asked to enter a SMTP Server, your username and your password. The SMTP Server field should already be completed with aspmx2.googlemail.com
and Port: 587
, they are Gmail's default and you can leave them like this.
Use your redirect email address as the username and use the App Password you created for your website (which should be inside your Rails credentials if you followed along my guide) and click on Add Count
.
If it worked you'll now have 2 email addresses in your "Send mail as section". You can then change the default to use the new alias and from now on people will be able to send mail to your redirect address wich you will receive on your gmail account, and when you send mail with that gmail account people will receive them addressed as the name and address you chose for this alias.
That's it for this guide. You've now managed to setup your Rails application to use ActionMailer with your gmail account. You've also seen how to create a new mailer action and its template. Finally you've also tried this template by previewing it in your dev environment.
Cheers.