Blog

How to send emails in Ruby (with examples)

Šarūnas Ročevas Šarūnas Ročevas
· 15 min read · Tips and resources · May 30th, 2024
Ruby is a popular open-source programming language enjoyed for its simplicity and versatility. Learn how you can send emails in Ruby and get advanced functionality when used with MailerSend's email API.

Ruby is a powerful, dynamic and open-source language that has a significant influence on today’s web applications. When coupled with the Ruby on Rails framework, it’s a highly capable language for building web apps and database solutions. You can also use it to handle your email functionality!

In this guide, we’ll go over the different ways you can use Ruby to send emails. We’ll show you the methods you can use—along with code examples for common use cases, so you can start sending emails with your Ruby project. 

Let’s dive in!

Options for using Ruby to send emails

Let’s assume you’re building a web app using Ruby on Rails, and you need to code email functionality that ties into user authentication or some other transactional email delivery system. Some quick research will demonstrate that there are basically three main ways to handle email with Ruby: 

  • With an SMTP server

  • Using a standalone Ruby Gem, like ActionMailer

  • Using an API, like MailerSend

Ruby has SMTP mailing built-in with the Net::SMTP class. While it certainly provides the functionality necessary to send out emails, it lacks any real email composition features. You could compose them yourself, but that’s a lot of extra and potentially ongoing work.

Your next best choice is to go with a standalone gem, such as Mail, Pony or ActionMailer. 

All of these prebuilt solutions streamline email management in Ruby, though they do require a bit more setup. That said, once they’re configured, there’s not much else to do. Of these three gems, ActionMailer is the most popular choice.

The last option is to offload your mailing to a service such as MailerSend and handle everything through an email API. It’s faster, easier, and more efficient than a solution that only handles emails internally. And it is, without a doubt, far better if you need next-gen email analytics.

Here’s a comparison between the 3.

Feature

Ruby Net::SMTP

Email API

Action Mailer

Ease of Use

Requires manual setup

Typically straightforward

Integrated into Rails, simplifies email sending in Rails apps

Configuration

Direct configuration of SMTP server settings

API key-based configuration

Configuration within Rails environment

Email Templating

Manual HTML/Text formatting within code

Supports HTML templates

Integrated view templates

Attachments

Requires manual handling for attachments

Often supports easy attachment handling

Supports attachments with built-in methods

Error Handling

Requires explicit error handling

Often provides error reporting and handling mechanisms

Integrated error handling within Rails

Delivery Status

May require additional setup for delivery status tracking

Often includes built-in delivery status tracking

Built-in delivery status tracking and reporting

Testing

Manual testing using test SMTP servers

Often includes sandbox environments for testing

Integrated testing within Rails framework

Community Support

Widely used but less community support compared to Rails-specific solutions

Strong community support, customer support channels, and extensive documentation

Strong community support within Rails ecosystem

Customization

Highly customizable but requires more effort

Generally provides customization options

Offers customization within Rails conventions

Scaling

Scalable but may require additional infrastructure setup

Designed for scalability, often offers scalable plans

Scales well within Rails applications


How to send emails with Ruby

Let’s walk through how to send emails with Ruby using the three methods above, starting with the two most viable and feature-filled options: ActionMailer and APIs. 

Sending emails in Ruby via ActionMailer

ActionMailer is by far the most popular gem for sending emails with Ruby. It leverages classes and views for its functionality, and the so-called mailers are similar to controllers. They inherit from ActionMailer::Base and are located in the app/mailers directory. 

Once you’ve pulled down the ActionMailer gem, the first thing you’ll do is generate a mailer:

bin/rails generate mailer User

Next, you’ll instantiate the class and provide the mailer layout:

# app/mailers/application_mailer.rb
class ApplicationMailer < ActionMailer::Base
  default from: 'admin@webapp.com'
  layout 'mailer'
end

Finally, you’ll create user_mailer.rb and add:

# app/mailers/user_mailer.rb
class UserMailer < ApplicationMailer
end

Modifying the mailer

Methods on mailers are called actions and they use views for content structuring. In comparison to a controller, which generates HTML-like content to send, a mailer creates an email message.

You can add a method to the user_mailer.rb to send a message to a registered user’s email:

# app/mailers/user_mailer.rb
class UserMailer < ApplicationMailer
  default from: 'notifications@example.com'
  def welcome_email
    @user = params[:user]
    @url = 'http://webaoo.com/login'
    mail(to: @user.email, subject: 'Welcome to Web App!')
  end
end

To elaborate, the default method assigns default values for this specific mailer. In the above example, it’s used to set the :from header value, though you can still override these defaults for individual messages. The mail method itself generates the message, and you can use it to populate the values of the :to and :subject headers.

Creating a mailer view

Mailer views are essentially HTML templates that you can populate with variables. To make one, create a file named welcome_message.html.erb in app/views/user_mailer/ and fill it accordingly:

<!DOCTYPE html>
<html>
  <head>
    <meta content="text/html; charset=UTF-8" http-equiv="Content-Type" />
  </head>
  <body>
    <h1>Welcome to Web App, <%= @user.name %></h1>
    <p>
      You've successfully created an account on Web App. To login and start
      doing some nice Web App things, click here: <%= @url %>.
    </p>
    <p>See you soon!</p>
  </body>
</html>

Calling the mailer

Finally, you’ll need to call the mailer from your app. In essence, it’s no different than rendering a view—it’s just rendering and sending it through mail protocols instead of HTTP. For this reason, it’s a good idea to have your controller instruct the mailer on when to send an email, such as when a user registers.

ActionMailer is powerful but requires a lot of work to get going. If you want to learn more about it, the basics guide on Rail Guides is a good place to do so.

Sending emails in Ruby via email API

Even with a popular gem like ActionMailer, sending emails in Ruby can be a headache. This is especially true if you want more functionality and customizations. To achieve this, a better approach—which is also more secure—is to send email using an API.

This is where MailerSend’s API comes in.

Many of the email gems are handy, but they won’t allow you to leverage advanced features and functionality. You’ll be missing out on personalization, highly-polished responsive email templates, suppression list management, and sender authentication using SPF, DKIM and DMARC security protocols, just to name a few.

Getting started with Ruby and MailerSend

If you want to follow along, sign up for a free account and test it out for yourself with a trial domain. Once you’re registered and you have your API key, go ahead and install the MailerSend gem:

gem install mailersend-ruby

Next, you’ll need to initialize the gem in your Ruby file with the required "mailersend-ruby".

The MailerSend API requires that you have a .env file with a MAILERSEND_API_TOKEN variable, like so:

MAILERSEND_API_TOKEN="aSuperLongAPIKey"

Alternatively, you can enable the variable system-wide, which is useful for developing with Kubernetes or Docker containers. 

To create an API key in MailerSend, from the dashboard go to Domains, click Manage next to the domain you want to create the token for, and then click Generate new token in the API section. Enter a name for the token and choose the permissions.

How to send an HTML email

Let’s look at the code we’ll need to generate a simple HTML email message. For this example, we’ll send a notification email to let our recipient know that their account has been activated. 

require "mailersend-ruby"

# Intialize the email class
ms_email = Mailersend::Email.new

# Add parameters
ms_email.add_recipients("email" => "ron@parksandrec.com", "name" => "Ron")
ms_email.add_recipients("email" => "leslie@parksandrec.com", "name" => "Leslie")
ms_email.add_from("email" => "april@parksandrec.com", "name" => "April")
ms_email.add_subject("You’re in! Welcome.")
ms_email.add_text("We’re happy to let you know that your account has been activated and you now have access to all features.")
ms_email.add_html("<b>We’re happy to let you know that your account has been activated and you now have access to all features.</b>")

# Send the email
ms_email.send

Need some CC or BCC recipients? No problem—add them as additional parameters:

ms_email.add_cc("email" => "chris@parksandrec.com", "name" => "Chris")
ms_email.add_bcc("email" => "andy@parksandrec.com", "name" => "Andy")

How to send emails with personalization

Personalization is simple with MailerSend’s API. Simply add a structure for the appropriate variables and call them in the parameters. MailerSend variables are formatted as {{var}}.

For this example, let’s say we want to add our recipient’s name to the email. Here’s how the code would look with the personalization variables.

require "mailersend-ruby"

# Intialize the email class
ms_email = Mailersend::Email.new

# Add parameters
ms_email.add_recipients("email" => "ron@parksandrec.com", "name" => "Ron")
ms_email.add_from("email" => "april@parksandrec.com", "name" => "April")
ms_email.add_subject("Hi {{name}}, you’re in!")
ms_email.add_text("{{name}}, we’re happy to let you know that your account has been activated and you now have access to all features.")
ms_email.add_html("<b>{{name}}, we’re happy to let you know that your account has been activated and you now have access to all features.</b>")

personalization = {
  email: 'ron@parksandrec.com',
  data: {
    name: 'Ron'
  }
}

ms_email.add_personalization(personalization)

ms_email.send

How to send a templated email

Sending templated email messages is as simple as adding a template ID to the parameters. By using templates, it's much easier to send professional, branded emails that are consistent across all your communication. This is one of the benefits of sending emails with Ruby via an email API.

In MailerSend, you can create professionally designed templates in minutes with the three template builders and add in any variables you need. When you save your design, it will automatically generate a template ID that you can add to your code. Here’s an example of the code needed for a templated email.

require "mailersend-ruby"

# Initialize the email class
ms_email = Mailersend::Email.new

# Add parameters
ms_email.add_recipients("email" => "ron@parksandrec.com", "name" => "Ron")
ms_email.add_recipients("email" => "leslie@parksandrec.com", "name" => "Leslie")
ms_email.add_from("email" => "april@parksandrec.com", "name" => "April")
ms_email.add_subject("Time")
ms_email.add_template_id(12415125)

# Send the email
ms_email.send

How to send emails in bulk

With MailerSend’s bulk email endpoint, you can schedule a large number of personalized emails through a single API call. This allows you to make your email sending more efficient, saving on resources and bypassing rate limiting. 

An example of an email you might choose to send in bulk is review request emails. These are not time-sensitive for recipients, so they can be delayed to be sent out together simultaneously. Here’s a look at the example code with the bulk email endpoint.

require "mailersend-ruby"

ms_bulk_email = Mailersend::BulkEmail.new

ms_bulk_email.messages = [{
    'from' => {
      "email" => "april@parksandrec.com", "name" => "April"
    },
    'to' => [{
      "email" => "ron@parksandrec.com",
      "name" => "Ron"
    }],
    'subject' => "How was your purchase, {{name}}?",
    'text' => "Hi {{name}}! Thanks for your recent purchase. We’d love to get your feedback about our products. If you have a minute to spare, we’d appreciate your honest review.",
    'html' => "<p><b>Hi {{name}}! Thanks for your recent purchase. We’d love to get your feedback about our products. If you have a minute to spare, we’d appreciate your honest review</b></p>",
    'personalization' => [{
      'email' => 'ron@parksandrec.com',
      'data' => {
        'name' => 'Ron'
      }
    }]
  },
  {
    'from' => {
      "email" => "april@parksandrec.com", "name" => "April"
    },
    'to' => [{
      "email" => "leslie@parksandrec.com",
      "name" => "Leslie"
    }],
    'subject' => "How was your purchase, {{name}}?",
    'text' => "Hi {{name}}! Thanks for your recent purchase. We’d love to get your feedback about our products. If you have a minute to spare, we’d appreciate your honest review",
    'html' => "<p><b>Hi {{name}}! Thanks for your recent purchase. We’d love to get your feedback about our products. If you have a minute to spare, we’d appreciate your honest review</b></p>",
    'personalization' => [{
      'email' => 'leslie@parksandrec.com',
      'data' => {
        'name' => 'Leslie'
      }
    }]
  }
]

ms_bulk_email.send

How to schedule an email for a later time or date

With the send_at parameter, you can schedule emails to be sent out at a specific time or date by setting the value of the parameter with a Unix timestamp in seconds, with a maximum of 72 hours. 

An example of when you might want to schedule an email for a specific time is for important general notifications, such as product updates that will affect the way users can access and use your services or products, or security breaches.

require "mailersend-ruby"

# Intialize the email class
ms_email = Mailersend::Email.new

# Add parameters
ms_email.add_recipients(email: "ron@parksandrec.com", name: "Ron")
ms_email.add_recipients(email: "leslie@parksandrec.com", name: "Leslie")
ms_email.add_from(email: "april@parksandrec.com", name: "April")
ms_email.add_subject("Scheduled downtime tomorrow at 11pm")
ms_email.add_text("We would like to inform you that our services will be unavailable between the hours of 11:00pm and 11:30pm UTC on Thursday 23rd May due to scheduled maintenance, after which services will resume as normal. We’re sorry for any inconvenience caused.")
ms_email.add_html("<p>We would like to inform you that our services will be unavailable between the hours of 11:00pm and 11:30pm UTC on Thursday 23rd May due to scheduled maintenance, after which services will resume as normal. We’re sorry for any inconvenience caused.</p>")

# Schedule email to be sent at a later date(Unix timestamp in seconds)
send_at = (Time.now + 3600).to_i # 1 hour from now

ms_email.add_send_at(send_at)

# Send the email
ms_email.send

Adding an inbound route for incoming messages

Another super useful function that you can implement with MailerSend’s email API is inbound email processing. This enables you to allow MailerSend to receive emails on your behalf, parse them, and then forward them to an email address or webhook.

This is handy for channels that receive high volumes of incoming messages, as it allows them to be sorted and prioritized for improved productivity and efficiency. A good example of this is for customer support emails. You can use inbound routing to route messages to specific agents or departments, or integrate them into your CRM. 

Here’s an example of the code needed to add an inbound route so that incoming support emails are forwarded to a CRM application.

require "mailersend-ruby"

# Initialize the MailerSend client with your token
ms_client = Mailersend::Client.new('your_mailersend_token')

# Create a new inbound routing instance
ms_inbound_routes = Mailersend::InboundRouting.new(ms_client)

# Set the inbound route settings
ms_inbound_routes.settings = {
  'domain_id' => 'yourdomainid',
  # Replace with your actual domain ID 'name' => 'CRM Integration Route',
  # Name your route 'domain_enabled' => true,
  # Enable the domain
  for this route 'match_filter' => {
    'type' => 'match_all'
    # Match all incoming emails
  },
  'forwards' => [{
    'type' => 'webhook',
    'value' => 'https://your-crm-app.com/webhook'
    # Replace with your CRM app 's webhook URL
  }]
}

# Add the inbound route
response = ms_inbound_routes.add_inbound_route

Getting analytics and activity

As well as sending emails and processing incoming messages, you can also fetch analytics and activity to check on email deliverability and performance. 

Let’s say you want to fetch the analytics for all hard-bounced emails in April. Here’s the code you can use to do that:

require "mailersend-ruby"

ms_analytics = Mailersend::Analytics.new
ms_analytics.date(date_from: 1711918800, date_to: 1714510800, events: % w[hard_bounced])

Working with an API and an email service like MailerSend makes the entire process much easier. While the solution you choose to go with depends on your needs and preferences, MailerSend’s API provides everything you need to handle all your email needs and more. 

And if you ever plan on migrating away from Ruby to a different language, it’s not a problem. With a powerful infrastructure that scales quickly and works with countless languages, all linked to an intuitive interface that the entire team can understand, MailerSend is a better way to work with email.

Sending emails in Ruby with Net::SMTP

For more advanced email delivery integration, for example with your app, the Net::SMTP method wouldn’t be sufficient. But it could work if you’re looking for basic email functionality such as sending plain text or HTML emails without templates, activity tracking or analytics. A good example would be in-house notifications or reminders.

Creating your account and an SMTP user

If you haven’t already, you’ll want to sign up for a free MailerSend account. You can try this out immediately with a trial domain. 

Once you’re in, head to Domains, click on Manage next to the trial domain (or your own), and click Generate new user in the SMTP section. Enter a recognizable name for your SMTP user and click Save user. The credentials to log in to the SMTP server will be generated.

Sending an email 

Next, you’ll want to generate the code for your email. Here’s an example for sending an internal company reminder via email in Ruby with Net::SMTP and MailerSend’s SMTP server.

require 'net/smtp'

message = << END_OF_MESSAGE
From: Reminder < reminders @parksandrec.com >
  To: Ron < ron @parksandrec.com >
  Subject: Reminder to fill out your monthly check in
  Date: Fri, 31 May 2024 14: 00: 00 + 0000
MIME - Version: 1.0
Content - Type: text / plain;
charset = UTF - 8

Hey Ron!It’ s that time of the month again.Remember to fill out your monthly check - in before you finish today!
  END_OF_MESSAGE

Net::SMTP.start('smtp.mailersend.net', 587, 'localhost', 'username', 'password',: plain) do | smtp |
    smtp.enable_starttls
  smtp.send_message message,
  'reminders@parksandrec.com',
  'ron@parksandrec.com'
end

Sending an HTML email

With a few tweaks to the code, you can send a more aesthetically pleasing and functional HTML email message. To enable HTML, we need to edit the Content-type value plus add in our HTML tags. Here’s how the above example would look.

require 'net/smtp'

message = <<END_OF_MESSAGE
From: Reminder <reminders@parksandrec.com>
To: Ron <ron@parksandrec.com>
MIME-Version: 1.0
Content-type: text/html
Subject: Reminder to fill out your monthly check in
Date: Fri, 31 May 2024 14:00:00 +0000

<p><b>Hey Ron!</b></p>

<p>It’s that time of the month again. Remember to fill out your <a href="https://parksandrec.com/monthly-check-in">monthly check-in</a> before you finish today!</p>
END_OF_MESSAGE

Net::SMTP.start('smtp.mailersend.net', 587, 'localhost', 'username', 'password', :plain) do |smtp|
  smtp.enable_starttls
  smtp.send_message message,
    'reminders@parksandrec.com',
    'ron@parksandrec.com'
end

Sending an email with an attachment

To add an attachment to the email, we’re going to add another section to the code to define the attached file and encode it. We’ll also update the Content-type value to multipart/mixed and define a boundary marker to separate the HTML from the attachment. For this example, our email includes a summary of Ron’s monthly check-in as an attachment. Here’s what it would look like.

require 'net/smtp'
require 'base64'
require 'mime/types'

# Variables
marker = "AUNIQUEMARKER"
filename = 'monthly-summary.pdf'
file_path = 'path/to/your/monthly-summary.pdf'
file_content = File.read(file_path)
encoded_content = Base64.strict_encode64(file_content)
mime_type = MIME::Types.type_for(file_path).first.to_s

# Message
message = <<END_OF_MESSAGE
From: Reminder <reminders@parksandrec.com>
To: Ron <ron@parksandrec.com>
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary=#{marker}
Subject: Thanks for your check-in! Here’s your summary
Date: Fri, 31 May 2024 14:00:00 +0000

--#{marker}
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: 7bit

<p><b>Thanks Ron!</b></p>
<p>Attached you’ll find a summary of your latest check-in.</p>

--#{marker}
Content-Type: #{mime_type}; name="#{filename}"
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="#{filename}"

#{encoded_content}
--#{marker}--
END_OF_MESSAGE

# SMTP settings
smtp_server = 'smtp.mailersend.net'
smtp_port = 587
username = 'username'
password = 'password'

# Send the email
Net::SMTP.start(smtp_server, smtp_port, 'localhost', username, password, :plain) do |smtp|
  smtp.enable_starttls
  smtp.send_message message,
    'reminders@parksandrec.com',
    'ron@parksandrec.com'
end

Start sending emails in Ruby

There you have it: All the main ways to send email in Ruby. If you’re looking for a secure, highly customizable method to handle the email needs of your Ruby app, look no further than MailerSend. 

Try it now for free

Get started with 3,000 emails per month and test MailerSend in minutes with a trial domain.

Do you send emails in Ruby? Or do you prefer another language for your transactional email? Let us know in the comments!

Šarūnas Ročevas
Designer