Let’s say you have a working Ruby app and need to add an email delivery functionality to it. This could be related to user authentication, or any other kind of transactional emails, it makes no difference.
This tutorial is tailored to help you implement sending emails with Ruby and introduce versatile options for that.
Ways to send email in Ruby
The following three options are the main options used.
The first two options are Ruby gems.
Among the two, the most common is ActionMailer. It’s the gem that is built into Rails framework, so it is the most conventional choice for sending emails from a Rails app.
The second option is to use a dedicated Ruby gem like Mail or others. These solutions let you handle email activities in a simple and effective way.
Lastly, if you want to avoid dependencies altogether, use the built-in Net::SMTP
. This provides the functionality to send email via SMTP. The drawback of this option is that Net::SMTP
lacks functions to compose emails. You can always create them yourself, but this takes time.
Now, let’s try to send an email using each of the described solutions.
Best Ruby gems for sending emails
In the Ruby ecosystem, you can find specific email gems that can improve your email sending experience.
ActionMailer
This is the most common gem for sending emails in Rails framework as ActionMailer is built into it. In case your app is written on top of it, ActionMailer will certainly come up. It lets you send emails using mailer classes and views.
Here’s how a simple email built with ActionMailer may look:
class TestMailer < ActionMailer::Base
default from: 'info@yourrubyapp.com'
def simple_message(recipient)
mail(
to: recipient,
subject: 'Any subject you want',
body: 'Lorem Ipsum'
)
end
end
How to send emails with ActionMailer
At RailsGuides, you’ll find a detailed tutorial on how to use ActionMailer at best. What we need is to create and send an email. So, make use of this step-by-step guide.
Create a mailer model
Your app will send emails using a mailer model and views. So, you need to create them first.
$ rails generate mailer Notifier
To generate an email message we need helpers that are defined in a mailer model. You can set up variables in the mailer views, options on the mail like :to address, as well as attachments. Also, different helpers are available to:
add attachments:
attachments ['filename.png'] = File.read('path/to/attachment.pdf')
add an inline attachment:
attachments.inline['filename.png'] = File.read('path/to/attachment.pdf')
specify a header field:
headers['X-No-Spam'] = 'True'
specify multiple headers:
headers({'X-No-Spam' => 'True', 'In-Reply-To' => '1234@message.id'})
specify the email to be sent: mail
Here’s the result:
class UserMailer< ApplicationMailer
def simple_message(recipient)
attachments["attachment.pdf"] = File.read("path/to/file.pdf")
mail(
to: 'your@bestuserever.com',
subject: "New account information",
content_type: "text/html",
body: "<html><strong>Hello there</strong></html>"
)
end
end
This mailer class already includes an attachment and HTML content. Now, let’s create a corresponding view.
Create a view
View denotes a template to be used with a mailer. You need to create an .erb file named the same as the method in the mailer class. In our case, it is new-account.html.erb. Locate it in app/views/notifier_mailer/
. This template will be used for the HTML formatted emails. Also, you can make a text part for this email by creating new-account.txt.erb in the same directory. Fill both files with the relevant content.
Server configuration
The next step is ActionMailer configuration and defining a delivery method. SMTP is set by default and you can adjust it using config.action_mailer.smtp_settings
. You can pick another delivery method like sendmail, file (save emails to files), and test (save emails to ActionMailer::Base.deliveries array). Here is an example of SMTP configuration.:
config.action_mailer.delivery_method = :smtp
config.action_mailer.smtp_settings = {
address: 'smtp.yourserver.com',
port: 25,
domain: 'yourrubyapp.com',
user_name: '<username>',
password: '<password>',
authentication: 'plain',
enable_starttls_auto: true
}
Port 25 is set by default and you can select plain
, login
or cram_md5
as an authentication option.
Sending email
We’ve defined a mailer and a template and ready to deliver the message. Just call deliver_now
to do it right away. Optionally, you can defer the delivery for later with deliver_later
. In Action Mailer, you need to call UserMailer.simple_message('recipient@example.com').deliver_now
.
Sending email to multiple recipients
Also, you can set your email to be sent to several recipients. This can be done by setting a list of email addresses to the :to
key, as well as :cc
, and :bcc
keys. You can create the list in the form of an array of recipients’ addresses or a single string in which emails are separated by commas.
class AdminMailer < ApplicationMailer
default to: -> { Admin.pluck(:email) }, from: 'info@yourrubyapp.com'
def new_registration(user)
@user = user
mail(subject: "New User Signup: #{@user.email}")
end
end
Want to learn more about using the Action Mailer? Don’t hesitate to read this comprehensive introduction by Matthew Croak.
Ruby Mail
This library is aimed at giving a single point of access to manage all email-related activities including sending and receiving email. To get started with Mail, execute require 'mail'
.
A simple email looks as follows:
mail = Mail.new do
from 'info@yourrubyapp.com'
to 'your@bestuserever.com'
subject 'Any subject you want'
body 'Lorem Ipsum'
end
SMTP is a default mail delivery method with a local host port 25. You can change SMTP settings:
Mail.defaults do
delivery_method :smtp, address: "localhost", port: 1025
end
or even the delivery method:
mail.delivery_method :sendmail
mail.deliver
Sending an email with HTML and attachment in Ruby Mail
You won’t have any troubles with building a multipart email. Check out this example:
mail = Mail.new do
from 'info@yourrubyapp.com'
to 'your@bestuserever.com'
subject 'Email with HTML and an attachment'
text_part do
body 'Put your plain text here'
end
html_part do
content_type 'text/html; charset=UTF-8'
body '<h1>And here is the place for HTML</h1>'
end
add_file '/path/to/Attachment.pdf'
end
That’s a brief overview of Ruby Mail for email sending. You can read more about this library here.
How to send emails with Ruby via Gmail SMTP
Actually, we wanted to skip this part entirely because it has no practical use case. You are able to use any aforementioned tool to configure a Gmail SMTP server and use it for sending emails. For example, this one is for Ruby Mail:
Mail.defaults do
delivery_method :smtp, {
address: 'smtp.gmail.com',
port: 587,
domain: 'yourrubyapp.com',
user_name: '<username>',
password: '<password>',
authentication: 'plain',
enable_starttls_auto: true
}
end
This is the Gmail SMTP server configuration for ActionMailer:
config.action_mailer.delivery_method = :smtp
config.action_mailer.smtp_settings = {
address: 'smtp.gmail.com',
port: 587,
user_name: 'your mail',
password: 'your password',
authentication: 'plain',
enable_starttls_auto: true
}
Using Mailtrap to send emails with Ruby
If you’re looking for a reliable and hassle-free email sending service with Ruby, you should probably consider Mailtrap Email Delivery Platform, which offers both a reliable email API with high deliverability rates by design.
Mailtrap also provides you with up to 60 days of email logs for improved troubleshooting (saving your hard data during this time span) and dashboards with a clear snapshot of the state of your email infrastructure are always at hand for analytics.
Another advantage of Mailtrap Email API are our timely email deliverability alerts that give you greater control over your email infrastructure and domain authority. This means that if anything goes wrong with your deliverability, you get an alert with a color-coded table plus insights on where to inspect a deliverability issue. Yet, Mailtrap sends you regular weekly reports on your deliverability performance to keep you up to date with your email sending and deliverability performance.
For ActionMailer and/or Rails users, we provide a custom Mailtrap delivery method which allows them to use our API with existing ActionMailer functionality and simple setup – you need to set the API key and choose the delivery method. After this, you can continue using ActionMailer as you used previously.
So how do you add email sending functionality to your Ruby application with Mailtrap?
Add this line to your application’s Gemfile:
gem 'mailtrap'
And then execute:
$ bundle install
Or install it yourself as:
$ gem install mailtrap
For ActionMailer:
This gem also adds ActionMailer delivery method. To configure it, add the following to your ActionMailer configuration (in Rails projects located in config/$ENVIRONMENT.rb
):
config.action_mailer.delivery_method = :mailtrap
config.action_mailer.mailtrap_settings = {
api_key: ENV.fetch('MAILTRAP_API_KEY')
}
And continue to use ActionMailer as usual.
To add category
and custom_variables
, add them to the mail generation:
mail(
to: 'your@email.com',
subject: 'You are awesome!',
category: 'Test category',
custom_variables: { test_variable: 'abc' }
)
Now, if you don’t have Rails, or you don’t use ActionMailer, please, use Mail gem (for Net::SMTP
option as well) for integration.
For minimal and full usage of the Ruby package to send emails with Mailtrap, have a look at this documentation.
Server configuration
Here is how your SMTP server configuration to start sending with Ruby would look like in Mailtrap (go to SMTP credentials at Mailtrap interface, then just copy and paste them):
config.action_mailer.delivery_method = :smtp
config.action_mailer.smtp_settings = {
address: 'live.smtp.mailtrap.io',
port: 587,
domain: 'yourdomain',
user_name: 'api',
password: '********059a',
authentication: 'plain',
enable_starttls_auto: true
}
The API integration for Mailtrap Ruby gem
It’s as simple as ABC. Use this code for Mailtrap API relay.
require "mailtrap"
mail = Mailtrap::Sending::Mail.new(
from:
{
email: "mailtrap@mailtrap.io",
name: "Mailtrap Test",
},
to: [
{
email: "youremail@yourdomain",
}
],
subject: "You are awesome!",
text: "Congrats for sending test email with Mailtrap!",
category: "Integration Test"
)
client = Mailtrap::Sending::Client.new(
api_key: "f3368c69855590e3095f329b0ee5059a",
api_host: "https://send.api.mailtrap.io/",
)
response = client.send(mail)
puts response
Obviously, you can modify "from:"
, "to:"
, "subject:"
, "headers:"
and "content:"
values.
Now you know how to send emails with Ruby with and without Mailtrap Email API.
However, sending should always be the closing stage of your development efforts. Remember: the rule of thumb is there is no successful sending without email testing. Testing of email functionality helps foresee and reduce any potential deliverability risks and improves your general sender’s reputation.
If your Ruby app sends emails via Net::SMTP
or ActionMailer, you should definitely see how Mailtrap can help you with testing delivery functionality.
How to send emails in Ruby via Net::SMTP
From our experience, no one would use that option in a regular web app. However, sending emails via Net::SMTP
could be a fit if you use mruby (a lightweight implementation of the Ruby language) on some IoT device. Also, it will do if used in serverless computing, for example, AWS Lambda. Check out this script example first and then we’ll go through it in detail.
require 'net/smtp'
message = <<END_OF_MESSAGE
From: YourRubyApp <info@yourrubyapp.com>
To: BestUserEver <your@bestuserever.com>
Subject: Any email subject you want
Date: Tue, 02 Jul 2019 15:00:34 +0800
Lorem Ipsum
END_OF_MESSAGE
Net::SMTP.start('your.smtp.server', 25) do |smtp|
smtp.send_message message,
'info@yourrubyapp.com',
'your@bestuserever.com'
end
This is a simple example of sending a textual email via SMTP (official documentation can be found here). You can see four headers: From, To, Subject, and Date. Keep in mind that you have to separate them with a blank line from the email body text. Equally important is to connect to the SMTP server.
Net::SMTP.start('your.smtp.server', 25) do |smtp|
# ...
end
Naturally, here will appear your data instead of your.smtp.server
‘, and 25 is a default port number. If needed, you can specify other details like username, password, or authentication scheme (:plain
, :login
, and :cram_md5
). It may look as follows:
Net::SMTP.start('your.smtp.server', 25, 'localhost', 'username', 'password', :plain) do |smtp|
# ...
end
Here, you will connect to the SMTP server using a username and password in plain text format, and the client’s hostname will be identified as localhost.
After that, you can use the send_message
method and specify the addresses of the sender and the recipient as parameters. The block form of
Net::SMTP.start('your.smtp.server', 25) { |smtp| ... }
closes the SMTP session automatically.
In the Ruby Cookbook, sending emails with the Net::SMTP
library is referred to as minimalism since you have to build the email string manually. Nevertheless, it’s not as hopeless as you may think of. Let’s see how you can enhance your email with HTML content and even add an attachment.
Sending an HTML email in Net::SMTP
Check out this script example that refers to the message section.
message = <<END_OF_MESSAGE
From: YourRubyApp <info@yourrubyapp.com>
To: BestUserEver <your@bestuserever.com>
MIME-Version: 1.0
Content-type: text/html
Subject: Any email subject you want
Date: Tue, 02 Jul 2019 15:00:34 +0800
A bit of plain text.
<strong>The beginning of your HTML content.</strong>
<h1>And some headline, as well.</h1>
END_OF_MESSAGE
Apart from HTML tags in the message body, we’ve got two additional headers: MIME-Version
and Content-type
. MIME refers to Multipurpose Internet Mail Extensions. It is an extension to Internet email protocol that allows you to combine different content types in a single message body. The value of MIME-Version
is typically 1.0
. It indicates that a message is MIME-formatted.
As for the Content-type
header, everything is clear. In our case, we have two types – HTML and plain text. Also, make sure to separate these content types using defining boundaries.
Except for MIME-Version
and Content-type
, you can use other MIME headers:
Content-Disposition
– specifies the presentation style (inline or attachment)Content-Transfer-Encoding
– indicates a binary-to-text encoding scheme (7bit, quoted-printable, base64, 8bit, or binary).
We’ll check them out in one of the following examples.
Sending an email with an attachment in Net::SMTP
Let’s add an attachment, such as a PDF file. In this case, we need to update Content-type
to multipart/mixed. Also, use the pack("m")
function to encode the attached file with base64 encoding.
require 'net/smtp'
filename = "/tmp/Attachment.pdf"
file_content = File.read(filename)
encoded_content = [file_content].pack("m") # base64
marker = "AUNIQUEMARKER"
After that, you need to define three parts of your email.
Part 1 – Main headers
part1 = <<END_OF_MESSAGE
From: YourRubyApp <info@yourrubyapp.com>
To: BestUserEver <your@bestuserever.com>
Subject: Adding attachment to email
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary = #{marker}
--#{marker}
END_OF_MESSAGE
Part 2 – Message action
part2 = <<END_OF_MESSAGE
Content-Type: text/html
Content-Transfer-Encoding:8bit
A bit of plain text.
<strong>The beginning of your HTML content.</strong>
<h1>And some headline, as well.</h1>
--#{marker}
END_OF_MESSAGE
Part 3 – Attachment
part3 = <<END_OF_MESSAGE
Content-Type: multipart/mixed; name = "#{filename}"
Content-Transfer-Encoding:base64
Content-Disposition: attachment; filename = "#{filename}"
#{encoded_content}
--#{marker}--
END_OF_MESSAGE
Now, we can put all the parts together and finalize the script. That’s how it will look:
require 'net/smtp'
filename = "/tmp/Attachment.pdf"
file_content = File.read(filename)
encoded_content = [file_content].pack("m") # base64
marker = "AUNIQUEMARKER"
part1 = <<END_OF_MESSAGE
From: YourRubyApp <info@yourrubyapp.com>
To: BestUserEver <your@bestuserever.com>
Subject: Adding attachment to email
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary = #{marker}
--#{marker}
END_OF_MESSAGE
part2 = <<END_OF_MESSAGE
Content-Type: text/html
Content-Transfer-Encoding:8bit
A bit of plain text.
<strong>The beginning of your HTML content.</strong>
<h1>And some headline, as well.</h1>
--#{marker}
END_OF_MESSAGE
part3 = <<END_OF_MESSAGE
Content-Type: multipart/mixed; name = "#{filename}"
Content-Transfer-Encoding:base64
Content-Disposition: attachment; filename = "#{filename}"
#{encoded_content}
--#{marker}--
END_OF_MESSAGE
message = part1 + part2 + part3
Net::SMTP.start('your.smtp.server', 25) do |smtp|
smtp.send_message message,
'info@yourrubyapp.com',
'your@bestuserever.com'
end
Can I send an email to multiple recipients in Net::SMTP
?
You certainly can. send_message
expects second and subsequent arguments to contain recipients’ emails. For example, like this:
Net::SMTP.start('your.smtp.server', 25) do |smtp|
smtp.send_message message,
'info@yourrubyapp.com',
'your@bestuserever1.com',
'your@bestuserever2.com',
'your@bestuserever3.com'
end
Using Mailtrap to test email sending with Net::SMTP
With all this code written down, a lot of things can go wrong. Your HTML might not render correctly in all clients, your personalization variables might be off, your messages might be getting marked as spam, etc.
To avoid this, you can use another inseparable part of Mailtrap Email Delivery Platform, Email Testing.
With Mailtrap Email Testing, you can test your email-sending capabilities of your app in staging and inspect HTML/CSS to ensure your emails reach your recipients’ inboxes in a mint condition.
Moreover, Email Testing also checks your spam score, which, if you keep under 5, you prevent a significant amount of any potential deliverability issues once your app moves to production. Basically, you ensure your emails will land in the recipient’s inbox, instead of their spam folder.
On top of these, and other advanced features, Mailtrap Email Testing is super easy to use.
Here’s how it works:
- Create a free Mailtrap account
- Click on Email Testing and select your inbox
- Copy the SMTP credentials from the SMTP Settings tab and insert them into your code or use a template for a simple message in the Integrations section
Here’s what it looks like for Ruby:
require 'net/smtp'
message = <<END_OF_MESSAGE
From: YourRubyApp <info@yourrubyapp.com>
To: BestUserEver <your@bestuserever.com>
Subject: Any email subject you want
Date: Tue, 02 Jul 2019 15:00:34 +0800
Lorem Ipsum
END_OF_MESSAGE
Net::SMTP.start('smtp.mailtrap.io', 587, '<username>', '<password>', :cram_md5) do |smtp|
smtp.send_message message,
'info@yourrubyapp.com',
'your@bestuserever.com'
end
If everything is alright, you’ll see your message in the Mailtrap Demo inbox. Also, you can try to check your email with HTML content and an attachment. Mailtrap allows you to see how your email will look and check HTML if necessary.
Now, what is really cool about the Mailtrap Email Delivery Platform is that it allows you to send, test, and control emails with Ruby. All in one place.
Final remarks
Whichever method to send emails with Ruby you choose, remember the very simple truth: he sends best, who tests best.
Clearly, there is a variety of Ruby applications that may require different email sending solutions. It may be ActionMailer or Net::SMTP
, you may use the Rails framework or not, having said that, it is always easier to have an entire email infrastructure in one place.
Well, at least that’s what we preach here at Maitrap.