How to send emails from a Ruby app via Net::SMTP

With Ruby, you can make use of many helpful gems to let your brand-new app send emails. The most common options are ActionMailer and Mail. But what if you want to use pure Ruby to implement the delivery of transactional emails? In this case, you need to opt for the Net::SMTP class. In this article, we’ll check out the intricacies and code samples of Net::SMTP.

Minimalistic email sending with Ruby

The Net::SMTP library is deemed a minimalistic solution for sending emails with Ruby. It includes that you have to build the email string manually. Regularly, it is quite an uncommon option for web apps. At the same time, Net::SMTP can be a good fit together with serverless computing like AWS Lambda or if you use mruby on some IoT device. That’s how it looks in practice:

require 'net/smtp'

message = <<END_OF_MESSAGE
From: Sender <[email protected]>
To: Recipient <[email protected]>
Subject: Subject of the message
Date: Wed, 23 Jun 2019 13:45:17 +0700

Body text
END_OF_MESSAGE

Net::SMTP.start('smtp.example.net', 25) do |smtp|
  smtp.send_message message,
  '[email protected]',
  '[email protected]'
end

The first part of the script includes four headers: From, To, Subject, and Date. They are followed by the body text part that ends with

END_OF_MESSAGE

.  Keep in mind that you have to separate these parts with a blank line.

Net::SMTP.start('smtp.example.net', 25) do |smtp|

connects to the SMTP server.

‘smtp.example.net

is actually the server, and 25 is a default port number. If needed, you can specify other details like username, password, or authentication scheme. In this case, the line will look as follows:

Net::SMTP.start('smtp.example.net', 25, ‘localhost’, ‘username’, ‘password’ :login) do |smtp|

According to this example, the client connects to the SMTP server using a username and password via the login authentication. The client’s hostname is identified as localhost.

 send_message

is the method to actually send the email. Here you can specify the sender’s and the recipients addresses. The block form of SMTP.start (

Net::SMTP.start('your.smtp.server', 25) do |smtp|

) closes the SMTP session automatically.

Can I send MIME emails or messages with attachments?

Despite the general minimalistic nature of the Net::SMTP class, you can pump up your email as well. In the following example, you’ll see how to create a message with the HTML text:

message = <<END_OF_MESSAGE
From: Sender <[email protected]>
To: Recipient <[email protected]>
MIME-Version: 1.0
Content-type: text/html
Subject: Subject of the message
Date: Wed, 23 Jun 2019 13:45:17 +0700

Body text
<h1>HTML text of the message</h1>
END_OF_MESSAGE

The output should like the following:

Here, there are 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.

The Content-type header provides two types – HTML and plain text. Apart from MIME-Version and Content-type, MIME headers can be used including Content-Disposition and Content-Transfer-Encoding. Let’s use them in the following example of the message with an attachment.

require 'net/smtp'

filename = "/tmp/Attachment.png"
file_content = File.read(filename)
encoded_content = [file_content].pack("m")   # base64

marker = "AUNIQUEMARKER"

Here, we’re sending an email with a PNG file. In this case, you need to update Content-type to multipart/mixed. Also, use the pack(“m”) function to encode the attached file with base64 encoding. And the message will consist of three parts: main headers, message action, and attachment. And that’s how the script sample looks like:

require 'net/smtp'
filename = "/tmp/Attachment.png"
file_content = File.read(filename)
encoded_content = [file_content].pack("m")   # base64

marker = "AUNIQUEMARKER"

part1 = <<END_OF_MESSAGE
From: Sender <[email protected]>
To: Recipient <[email protected]>
Subject: Message subject
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

Body text.

<h1>HTML text.</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('smtp.example.net', 25) do |smtp|
    smtp.send_message message,
    '[email protected]',
    '[email protected]'
  End

As a result, you should receive the following message with an attachment in your test inbox:

What about mass mailing in Net::SMTP?

If you need to send emails to multiple users, you can just specify all of them as arguments for the

send_message

method. That’s how it may look like:

Net::SMTP.start('smtp.example.net', 25) do |smtp|
  smtp.send_message message,
  '[email protected]',
  '[email protected]',
  '[email protected]',
  '[email protected]',
  '[email protected]'
End

Wrapping Up

Surely, Net::SMTP is not the most attractive option to implement email sending in the Ruby app. At the same time, it provides basic functionality, which can be more than enough depending on your needs. If, however, you want more quirks, draw attention to Ruby gems.

Pankaj Kumar
Pankaj Kumar
Articles: 209