Back to home

Sending Your First Email With ActionMailer In Rails 7 main image

Sending Your First Email With ActionMailer In Rails 7

This post will act as "Hello, World" of sorts for sending your first email using ActionMailer with Ruby on Rails 7.

We will take a welcome email example from the Postmark templates and send it from the Rails console and view it in the browser using the letter_opener gem.

Source code can be found here

Prerequisites

  1. Basic familiarity with setting up a new Rails project.

Getting started

We will use Rails to initialize the project demo-action-mailer-hello-world:

# Create a new rails project $ rails new demo-action-mailer-hello-world $ cd demo-action-mailer-hello-world

Update your Gemfile and add the following:

gem "letter_opener", group: :development

To install the gem, run bundle on the command line.

Configuring the developer environment for Letter Opener

Update config/environments/development.rb to add the following two lines:

config.action_mailer.delivery_method = :letter_opener config.action_mailer.perform_deliveries = true

Creating our welcome email

We are going to create a basic welcome email.

# Create a User mailer $ bin/rails generate mailer User # Create a file for our email template $ touch app/views/user_mailer/welcome_email.html.erb app/views/user_mailer/welcome_email.text.erb

Inside of app/mailers/application_mailer.rb we have a default from address of from@example.com. We can leave that for now.

We are going to use the postmark-templates for our Welcome email. I did a regex swap of variables to ensure they're using ERB.

Inside of app/views/user_mailer/welcome_email.html.erb, let's add the following:

<span class="preheader" style="display: none !important; visibility: hidden; mso-hide: all; font-size: 1px; line-height: 1px; max-height: 0; max-width: 0; opacity: 0; overflow: hidden;" >Thanks for trying out [Product Name]. We’ve pulled together some information and resources to help you get started.</span > <table class="email-wrapper" width="100%" cellpadding="0" cellspacing="0" role="presentation" style="width: 100%; -premailer-width: 100%; -premailer-cellpadding: 0; -premailer-cellspacing: 0; background-color: #F2F4F6; margin: 0; padding: 0;" bgcolor="#F2F4F6" > <tr> <td align="center" style='word-break: break-word; font-family: "Nunito Sans", Helvetica, Arial, sans-serif; font-size: 16px;' > <table class="email-content" width="100%" cellpadding="0" cellspacing="0" role="presentation" style="width: 100%; -premailer-width: 100%; -premailer-cellpadding: 0; -premailer-cellspacing: 0; margin: 0; padding: 0;" > <tr> <td class="email-masthead" style='word-break: break-word; font-family: "Nunito Sans", Helvetica, Arial, sans-serif; font-size: 16px; text-align: center; padding: 25px 0;' align="center" > <a href="https://example.com" class="f-fallback email-masthead_name" style="color: #A8AAAF; font-size: 16px; font-weight: bold; text-decoration: none; text-shadow: 0 1px 0 white;" > [Product Name] </a> </td> </tr> <tr> <td class="email-body" width="570" cellpadding="0" cellspacing="0" style='word-break: break-word; margin: 0; padding: 0; font-family: "Nunito Sans", Helvetica, Arial, sans-serif; font-size: 16px; width: 100%; -premailer-width: 100%; -premailer-cellpadding: 0; -premailer-cellspacing: 0;' > <table class="email-body_inner" align="center" width="570" cellpadding="0" cellspacing="0" role="presentation" style="width: 570px; -premailer-width: 570px; -premailer-cellpadding: 0; -premailer-cellspacing: 0; background-color: #FFFFFF; margin: 0 auto; padding: 0;" bgcolor="#FFFFFF" > <tr> <td class="content-cell" style='word-break: break-word; font-family: "Nunito Sans", Helvetica, Arial, sans-serif; font-size: 16px; padding: 45px;' > <div class="f-fallback"> <h1 style="margin-top: 0; color: #333333; font-size: 22px; font-weight: bold; text-align: left;" align="left" > Welcome, <%= @name %>! </h1> <p style="font-size: 16px; line-height: 1.625; color: #51545E; margin: .4em 0 1.1875em;" > Thanks for trying [Product Name]. We’re thrilled to have you on board. To get the most out of [Product Name], do this primary next step: </p> <table class="body-action" align="center" width="100%" cellpadding="0" cellspacing="0" role="presentation" style="width: 100%; -premailer-width: 100%; -premailer-cellpadding: 0; -premailer-cellspacing: 0; text-align: center; margin: 30px auto; padding: 0;" > <tr> <td align="center" style='word-break: break-word; font-family: "Nunito Sans", Helvetica, Arial, sans-serif; font-size: 16px;' > <table width="100%" border="0" cellspacing="0" cellpadding="0" role="presentation" > <tr> <td align="center" style='word-break: break-word; font-family: "Nunito Sans", Helvetica, Arial, sans-serif; font-size: 16px;' > <a href="<%= @action_url %>" class="f-fallback button" target="_blank" style="color: #FFF; border-color: #3869d4; border-style: solid; border-width: 10px 18px; background-color: #3869D4; display: inline-block; text-decoration: none; border-radius: 3px; box-shadow: 0 2px 3px rgba(0, 0, 0, 0.16); -webkit-text-size-adjust: none; box-sizing: border-box;" >Do this Next</a > </td> </tr> </table> </td> </tr> </table> <p style="font-size: 16px; line-height: 1.625; color: #51545E; margin: .4em 0 1.1875em;" > For reference, here's your login information: </p> <table class="attributes" width="100%" cellpadding="0" cellspacing="0" role="presentation" style="margin: 0 0 21px;" > <tr> <td class="attributes_content" style='word-break: break-word; font-family: "Nunito Sans", Helvetica, Arial, sans-serif; font-size: 16px; background-color: #F4F4F7; padding: 16px;' bgcolor="#F4F4F7" > <table width="100%" cellpadding="0" cellspacing="0" role="presentation" > <tr> <td class="attributes_item" style='word-break: break-word; font-family: "Nunito Sans", Helvetica, Arial, sans-serif; font-size: 16px; padding: 0;' > <span class="f-fallback"> <strong>Login Page:</strong> <%= @login_url %> </span> </td> </tr> <tr> <td class="attributes_item" style='word-break: break-word; font-family: "Nunito Sans", Helvetica, Arial, sans-serif; font-size: 16px; padding: 0;' > <span class="f-fallback"> <strong>Username:</strong> <%= @username %> </span> </td> </tr> </table> </td> </tr> </table> <p style="font-size: 16px; line-height: 1.625; color: #51545E; margin: .4em 0 1.1875em;" > You've started a <%= @trial_length %> day trial. You can upgrade to a paying account or cancel any time. </p> <table class="attributes" width="100%" cellpadding="0" cellspacing="0" role="presentation" style="margin: 0 0 21px;" > <tr> <td class="attributes_content" style='word-break: break-word; font-family: "Nunito Sans", Helvetica, Arial, sans-serif; font-size: 16px; background-color: #F4F4F7; padding: 16px;' bgcolor="#F4F4F7" > <table width="100%" cellpadding="0" cellspacing="0" role="presentation" > <tr> <td class="attributes_item" style='word-break: break-word; font-family: "Nunito Sans", Helvetica, Arial, sans-serif; font-size: 16px; padding: 0;' > <span class="f-fallback"> <strong>Trial Start Date:</strong> <%= @trial_start_date %> </span> </td> </tr> <tr> <td class="attributes_item" style='word-break: break-word; font-family: "Nunito Sans", Helvetica, Arial, sans-serif; font-size: 16px; padding: 0;' > <span class="f-fallback"> <strong>Trial End Date:</strong> <%= @trial_end_date %> </span> </td> </tr> </table> </td> </tr> </table> <p style="font-size: 16px; line-height: 1.625; color: #51545E; margin: .4em 0 1.1875em;" > If you have any questions, feel free to <a href="mailto:<%= @support_email %>" style="color: #3869D4;" >email our customer success team</a >. (We're lightning quick at replying.) We also offer <a href="<%= @live_chat_url %>" style="color: #3869D4;" >live chat</a > during business hours. </p> <p style="font-size: 16px; line-height: 1.625; color: #51545E; margin: .4em 0 1.1875em;" > Thanks, <br /> [Sender Name] and the [Product Name] Team </p> <p style="font-size: 16px; line-height: 1.625; color: #51545E; margin: .4em 0 1.1875em;" > <strong>P.S.</strong> Need immediate help getting started? Check out our <a href="<%= @help_url %>" style="color: #3869D4;" >help documentation</a >. Or, just reply to this email, the [Product Name] support team is always ready to help! </p> <table class="body-sub" role="presentation" style="margin-top: 25px; padding-top: 25px; border-top-width: 1px; border-top-color: #EAEAEC; border-top-style: solid;" > <tr> <td style='word-break: break-word; font-family: "Nunito Sans", Helvetica, Arial, sans-serif; font-size: 16px;' > <p class="f-fallback sub" style="font-size: 13px; line-height: 1.625; color: #51545E; margin: .4em 0 1.1875em;" > If you’re having trouble with the button above, copy and paste the URL below into your web browser. </p> <p class="f-fallback sub" style="font-size: 13px; line-height: 1.625; color: #51545E; margin: .4em 0 1.1875em;" > <%= @action_url %> </p> </td> </tr> </table> </div> </td> </tr> </table> </td> </tr> <tr> <td style='word-break: break-word; font-family: "Nunito Sans", Helvetica, Arial, sans-serif; font-size: 16px;' > <table class="email-footer" align="center" width="570" cellpadding="0" cellspacing="0" role="presentation" style="width: 570px; -premailer-width: 570px; -premailer-cellpadding: 0; -premailer-cellspacing: 0; text-align: center; margin: 0 auto; padding: 0;" > <tr> <td class="content-cell" align="center" style='word-break: break-word; font-family: "Nunito Sans", Helvetica, Arial, sans-serif; font-size: 16px; padding: 45px;' > <p class="f-fallback sub align-center" style="font-size: 13px; line-height: 1.625; text-align: center; color: #A8AAAF; margin: .4em 0 1.1875em;" align="center" > © 2021 [Product Name]. All rights reserved. </p> <p class="f-fallback sub align-center" style="font-size: 13px; line-height: 1.625; text-align: center; color: #A8AAAF; margin: .4em 0 1.1875em;" align="center" > [Company Name, LLC] <br /> 1234 Street Rd. <br /> Suite 1234 </p> </td> </tr> </table> </td> </tr> </table> </td> </tr> </table>

Also ensure that you update app/views/layouts/mailer.html.erb:

<!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="x-apple-disable-message-reformatting" /> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <meta name="color-scheme" content="light dark" /> <meta name="supported-color-schemes" content="light dark" /> <title></title> <style type="text/css" rel="stylesheet" media="all"> /* Base ------------------------------ */ @import url("https://fonts.googleapis.com/css?family=Nunito+Sans:400,700&amp;display=swap"); body { width: 100% !important; height: 100%; margin: 0; -webkit-text-size-adjust: none; } a { color: #3869D4; } a img { border: none; } td { word-break: break-word; } .preheader { display: none !important; visibility: hidden; mso-hide: all; font-size: 1px; line-height: 1px; max-height: 0; max-width: 0; opacity: 0; overflow: hidden; } /* Type ------------------------------ */ body, td, th { font-family: "Nunito Sans", Helvetica, Arial, sans-serif; } h1 { margin-top: 0; color: #333333; font-size: 22px; font-weight: bold; text-align: left; } h2 { margin-top: 0; color: #333333; font-size: 16px; font-weight: bold; text-align: left; } h3 { margin-top: 0; color: #333333; font-size: 14px; font-weight: bold; text-align: left; } td, th { font-size: 16px; } p, ul, ol, blockquote { margin: .4em 0 1.1875em; font-size: 16px; line-height: 1.625; } p.sub { font-size: 13px; } /* Utilities ------------------------------ */ .align-right { text-align: right; } .align-left { text-align: left; } .align-center { text-align: center; } /* Buttons ------------------------------ */ .button { background-color: #3869D4; border-top: 10px solid #3869D4; border-right: 18px solid #3869D4; border-bottom: 10px solid #3869D4; border-left: 18px solid #3869D4; display: inline-block; color: #FFF; text-decoration: none; border-radius: 3px; box-shadow: 0 2px 3px rgba(0, 0, 0, 0.16); -webkit-text-size-adjust: none; box-sizing: border-box; } .button--green { background-color: #22BC66; border-top: 10px solid #22BC66; border-right: 18px solid #22BC66; border-bottom: 10px solid #22BC66; border-left: 18px solid #22BC66; } .button--red { background-color: #FF6136; border-top: 10px solid #FF6136; border-right: 18px solid #FF6136; border-bottom: 10px solid #FF6136; border-left: 18px solid #FF6136; } @media only screen and (max-width: 500px) { .button { width: 100% !important; text-align: center !important; } } /* Attribute list ------------------------------ */ .attributes { margin: 0 0 21px; } .attributes_content { background-color: #F4F4F7; padding: 16px; } .attributes_item { padding: 0; } /* Related Items ------------------------------ */ .related { width: 100%; margin: 0; padding: 25px 0 0 0; -premailer-width: 100%; -premailer-cellpadding: 0; -premailer-cellspacing: 0; } .related_item { padding: 10px 0; color: #CBCCCF; font-size: 15px; line-height: 18px; } .related_item-title { display: block; margin: .5em 0 0; } .related_item-thumb { display: block; padding-bottom: 10px; } .related_heading { border-top: 1px solid #CBCCCF; text-align: center; padding: 25px 0 10px; } /* Discount Code ------------------------------ */ .discount { width: 100%; margin: 0; padding: 24px; -premailer-width: 100%; -premailer-cellpadding: 0; -premailer-cellspacing: 0; background-color: #F4F4F7; border: 2px dashed #CBCCCF; } .discount_heading { text-align: center; } .discount_body { text-align: center; font-size: 15px; } /* Social Icons ------------------------------ */ .social { width: auto; } .social td { padding: 0; width: auto; } .social_icon { height: 20px; margin: 0 8px 10px 8px; padding: 0; } /* Data table ------------------------------ */ .purchase { width: 100%; margin: 0; padding: 35px 0; -premailer-width: 100%; -premailer-cellpadding: 0; -premailer-cellspacing: 0; } .purchase_content { width: 100%; margin: 0; padding: 25px 0 0 0; -premailer-width: 100%; -premailer-cellpadding: 0; -premailer-cellspacing: 0; } .purchase_item { padding: 10px 0; color: #51545E; font-size: 15px; line-height: 18px; } .purchase_heading { padding-bottom: 8px; border-bottom: 1px solid #EAEAEC; } .purchase_heading p { margin: 0; color: #85878E; font-size: 12px; } .purchase_footer { padding-top: 15px; border-top: 1px solid #EAEAEC; } .purchase_total { margin: 0; text-align: right; font-weight: bold; color: #333333; } .purchase_total--label { padding: 0 15px 0 0; } body { background-color: #F2F4F6; color: #51545E; } p { color: #51545E; } .email-wrapper { width: 100%; margin: 0; padding: 0; -premailer-width: 100%; -premailer-cellpadding: 0; -premailer-cellspacing: 0; background-color: #F2F4F6; } .email-content { width: 100%; margin: 0; padding: 0; -premailer-width: 100%; -premailer-cellpadding: 0; -premailer-cellspacing: 0; } /* Masthead ----------------------- */ .email-masthead { padding: 25px 0; text-align: center; } .email-masthead_logo { width: 94px; } .email-masthead_name { font-size: 16px; font-weight: bold; color: #A8AAAF; text-decoration: none; text-shadow: 0 1px 0 white; } /* Body ------------------------------ */ .email-body { width: 100%; margin: 0; padding: 0; -premailer-width: 100%; -premailer-cellpadding: 0; -premailer-cellspacing: 0; } .email-body_inner { width: 570px; margin: 0 auto; padding: 0; -premailer-width: 570px; -premailer-cellpadding: 0; -premailer-cellspacing: 0; background-color: #FFFFFF; } .email-footer { width: 570px; margin: 0 auto; padding: 0; -premailer-width: 570px; -premailer-cellpadding: 0; -premailer-cellspacing: 0; text-align: center; } .email-footer p { color: #A8AAAF; } .body-action { width: 100%; margin: 30px auto; padding: 0; -premailer-width: 100%; -premailer-cellpadding: 0; -premailer-cellspacing: 0; text-align: center; } .body-sub { margin-top: 25px; padding-top: 25px; border-top: 1px solid #EAEAEC; } .content-cell { padding: 45px; } /*Media Queries ------------------------------ */ @media only screen and (max-width: 600px) { .email-body_inner, .email-footer { width: 100% !important; } } @media (prefers-color-scheme: dark) { body, .email-body, .email-body_inner, .email-content, .email-wrapper, .email-masthead, .email-footer { background-color: #333333 !important; color: #FFF !important; } p, ul, ol, blockquote, h1, h2, h3, span, .purchase_item { color: #FFF !important; } .attributes_content, .discount { background-color: #222 !important; } .email-masthead_name { text-shadow: none !important; } } :root { color-scheme: light dark; supported-color-schemes: light dark; } </style> <!--[if mso]> <style type="text/css"> .f-fallback { font-family: Arial, sans-serif; } </style> <![endif]--> <style type="text/css" rel="stylesheet" media="all"> body { width: 100% !important; height: 100%; margin: 0; -webkit-text-size-adjust: none; } body { font-family: "Nunito Sans", Helvetica, Arial, sans-serif; } body { background-color: #F2F4F6; color: #51545E; } </style> </head> <body style="width: 100% !important; height: 100%; -webkit-text-size-adjust: none; font-family: &quot;Nunito Sans&quot;, Helvetica, Arial, sans-serif; background-color: #F2F4F6; color: #51545E; margin: 0;" bgcolor="#F2F4F6"> <%= yield %> </body> </html>

Setting up our text email template

As for the text file app/views/user_mailer/welcome_email.text.erb:

Thanks for trying out [Product Name]. We’ve pulled together some information and resources to help you get started. [Product Name] ( https://example.com ) ****************** Welcome, <%= @name %>! ****************** Thanks for trying [Product Name]. We’re thrilled to have you on board. To get the most out of [Product Name], do this primary next step: Do this Next ( <%= @action_url %> ) For reference, here's your login information: Login Page: <%= @login_url %> Username: <%= @username %> You've started a <%= @trial_length %> day trial. You can upgrade to a paying account or cancel any time. Trial Start Date: <%= @trial_start_date %> Trial End Date: <%= @trial_end_date %> If you have any questions, feel free to email our customer success team ( <%= @support_email %> ). (We're lightning quick at replying.) We also offer live chat ( <%= @live_chat_url %> ) during business hours. Thanks, [Sender Name] and the [Product Name] Team P.S. Need immediate help getting started? Check out our help documentation ( <%= @help_url %> ). Or, just reply to this email, the [Product Name] support team is always ready to help! If you’re having trouble with the button above, copy and paste the URL below into your web browser. <%= @action_url %> © 2021 [Product Name]. All rights reserved. [Company Name, LLC] 1234 Street Rd. Suite 1234

Updating our Mailer class

We want to be able to pass some arguments to this email template. Some will come dynamically, and others we will set statically as part of the mailer method for demonstration purposes.

Inside of app/mailers/user_mailer.rb, update the code to the following:

class UserMailer < ApplicationMailer default from: 'notifications@example.com' def welcome_email @email = params[:email] @name = params[:name] @username = params[:username] @trial_start_date = Date.current @trial_end_date = Date.current + 7.days @trial_length = '7 days' @support_email = 'support@example.com' @help_url = 'https://help.example.com' @action_url = 'http://localhost:3000' @login_url = 'http://localhost:3000/login' mail(to: @email, subject: 'Welcome to My Awesome Site') end end

In one terminal, start the Rails server with rails s and open up the browser at localhost:3000.

In another, start the Rails console with rails c.

We can send an email from the console with the following:

UserMailer.with(email: "hello@example.com", name: "Billy Bob", username: "dennisokeeffe92").welcome_email.deliver_later

Letter opener will open up the URL with a preview.

Successfully sent email

Successfully sent email

Perfect! Our welcome email has been sent with our expected values.

Summary

Today's post demonstrated how to send a basic email template in Rails using ActionMailer.

We used the letter opener gem to preview those emails sent in development.

Resources and further reading

Photo credit: joelfilip

Personal image

Dennis O'Keeffe

@dennisokeeffe92
  • Melbourne, Australia

Hi, I am a professional Software Engineer. Formerly of Culture Amp, UsabilityHub, Present Company and NightGuru.
I am currently working on workingoutloud.dev, Den Dribbles and LandPad .

1,200+ PEOPLE ALREADY JOINED ❤️️

Get fresh posts + news direct to your inbox.

No spam. We only send you relevant content.