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:
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
. Keep in mind that you have to separate these parts with a blank line.
connects to the SMTP server.
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:
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.
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 (
) 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:
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:
and
. 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
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.
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:
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
method. That’s how it may look like:
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.