Setting Up Email in a Rails 4 app with Action Mailer in development and SendGrid in production using Heroku

Here is a demo of how I created an email w/ user-mailer in rails

First off, from the Rails Guide generate a UserMailer

Screen Shot 2013-12-21 at 7.34.47 PM

Then in the user_mailer.rb create a function that sends the email

Pretty simple right?  Now we need to create the view.  This is where you can design the email and whatever text you want to put in it. Create a file in the app/views/user_mailer folder.  The name of the file should match the name of the function you defined in the user_mailer.rb file.  Mine is welcome_email.html.erb

Screen Shot 2013-12-21 at 7.45.23 PM

Now that we have the function to send the email, and the text of the email itself,  we just need to add a line in the controller to have it send the email when we want it to.

You can call the mailer function wherever you want to send the email, in this case we can just send it when a new user signs up

Screen Shot 2013-12-21 at 8.50.09 PM

Now we need to set up the config files for the email address we will use to send emails. For development, in the config/environment/development.rb file:

Screen Shot 2014-02-23 at 8.00.13 PM

Set the config.action_mailer.default_url_options to ‘localhost:3000’ in development, or whatever port you are using to test.  In production, you would set it to the url of your production app.  Then set up the email smtp settings according to your email provider.  I’ve shown the settings for gmail here.

So great, now we have it set up so a new user will receive an email, at least in development.  Now getting this working in production can be slightly harder.  But I’m going to walk through one super easy solution of how to set this up using Heroku and SendGrid, but there are probably a million different ways to do this depending on your hosting, your email, etc.

So the first thing to do before moving to production is to protect the sensitive email sign in information that we just put in the config/environment/development.rb.  The easiest way to do this is to use environment variables, and a simple way to do that is to use the figaro gem.  I wrote a quick post on how to setup environment variables with the figaro gem here, so take a minute and set that up in your app first.  This will keep your email login info from getting pushed to github, in case you are using a public repository.  It should then look something like this:

So, assuming you have your app pushed to heroku for production, the next thing we need to do is setup an email add-on for your heroku app.  Of course you could fully create your own email solution, but if you know how to do that then you wouldn’t be reading this blog, would you? So, for a simpler solution, first you can choose one of the email related add-ons from the heroku add-ons page.  I happen to use SendGrid as I think its one of the simplest to set up and use, so that’s what I’ll go through here.

Add SendGrid to your heroku app by running

heroku addons:add sendgrid:starter

Now SendGrid will have automatically generated a username and password that you can see by running

heroku config:get SENDGRID_USERNAME
heroku config:get SENDGRID_PASSWORD

or simply running heroku config will show you all the heroku config variables.

Next, go to config/environment/production.rb and add our email settings there:

So you can see that SendGrid has set up environment variables on heroku for us, giving us the SENDGRID_USERNAME and SENDGRID_PASSWORD.  This is the same idea that we just did in development using the figaro gem.

Ok, so now push to heroku, migrate the database, and see if the mailer is working in production.  Not too difficult right?  Stay tuned for a follow up post where I’ll describe how to send email asynchronously with sidekiq and redis.

Advertisements

Environment variables with the Figaro Gem

Environment variables are a great way in Ruby on Rails to protect private information, especially when your project is publicly hosted on git.  For example, I just added email support to my Ruby on Rails app, and in order to send an email, I have to put in my username and password.  Well of course I don’t want that to become public information in the source code by hard coding it.  One way to avoid this is to put these variables into a separate file that does not get committed to github.  I’ll show you how to use the Figaro gem to do just that.

First, add the gem to your gem file and then run ‘bundle install’.  Then in the Terminal run

rails generate figaro:install

This creates a file called “config/application.yml” in your rails app.  It also automatically adds this file to your .gitignore file so it does not get committed to github.

Screen_Shot_2013-08-04_at_8.29.25_PM

Then simply add your sensitive variables in this application.yml file like this:

Screen Shot 2013-08-04 at 9.07.39 PM

Now back in your environment files such as “development.rb” or “production.rb” you can input your sensitive variables as such:

Screen Shot 2013-08-04 at 9.08.57 PM

Now your information is safe, and your environment variables are set.  If you want to set different variables for different environments, i.e. development vs production, simply give them different names in your application.yml file, and call the appropriate one in each development.rb or production.rb

UPDATE: A reminder that if you end up changing any of the information that you store in your environment variables, such as the password to your email or something, then it will not get pushed to production automatically when you commit to git. (because that’s the whole point of environment variables).  So if you do need to update your environment variables on heroku, simply run heroku config to view your current environment variables on heroku.

To set or change them, run:
heroku config:set USERNAME=username

Refer to the heroku documentation for more details. Don’t forget to do this after changing any of these variables – I spent an hour debugging, when all I needed to do was update the environment variables on heroku 😦 Hopefully this will save you some time!