Options for sending an email in Ruby
Mostly, you can pick one of the three options.
The simplest one is using Net::SMTP class. It 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.
The second option is to use a dedicated Ruby gem like Mail, Pony, or others. These solutions let you handle email activities in a simple and effective way. Action Mailer is a perfect email solution through the prism of Rails. And, most likely, this will be your choice.
The third option is class Socket. Mostly, this class allows you to set communication between processes or within a process. So, email sending can be implemented with it as well. However, the truth is that Socket does not provide you with extensive functionalities, and you’re unlikely to want to go with it.
Now, let’s try to send an email using each of the described solutions.
How to send emails in Ruby via Net::SMTP
From my experience, the use of that option in a regular web app is uncommon. 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.
Expand|Select|Wrap|Line Numbers
- 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
Expand|Select|Wrap|Line Numbers
- Net::SMTP.start('your.smtp.server', 25) do |smtp|
Expand|Select|Wrap|Line Numbers
- `Net::SMTP.start('your.smtp.server', 25, ‘localhost’, ‘username’, ‘password’ :plain) do |smtp|`
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 SMTP.start (`Net::SMTP.start('your.smtp.server', 25) do |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.
Expand|Select|Wrap|Line Numbers
- 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
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).
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.
Expand|Select|Wrap|Line Numbers
- 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
Expand|Select|Wrap|Line Numbers
- 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
Expand|Select|Wrap|Line Numbers
- 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
Expand|Select|Wrap|Line Numbers
- 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
Expand|Select|Wrap|Line Numbers
- 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
- begin
- 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?
Definitely, you can. send_message expects second and subsequent arguments to contain recipients’ emails. For example, like this:
Expand|Select|Wrap|Line Numbers
- 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
In Ruby ecosystem, you can find specific email gems that can improve your email sending experience.
Ruby Mail
This library is aimed at giving a single point of access to manage all email-related activities including sending and receiving email.
Pony
You might have heard a fairy tale about sending an email in one command. Hold on to your hats, cause it’s real and provided by Pony gem.
ActionMailer
This is the most popular gem for sending emails on Rails. 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.
Using Mailtrap to test email sending with Net::SMTP
Setup is very simple. Once you’re in your demo inbox, copy the SMTP credentials on the SMTP Settings tab and insert them in your code. Or you can get a ready-to-use template of a simple message in the Integrations section. Just choose a programming language or framework your app is built with.
Expand|Select|Wrap|Line Numbers
- 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
You have just read the full tutorial on how to test and send emails in Ruby. Hope you enjoyed!