Skip to content

Ruby Sending Email

The Simple Mail Transfer Protocol (SMTP) is the standard internet protocol for sending electronic mail. Ruby’s standard library includes the Net::SMTP class, which provides a client-side interface for connecting to an SMTP server and sending emails.

Net::SMTP offers methods to establish a connection, authenticate (if required), and transmit email messages. The primary way to use it is via the Net::SMTP.start block form, which handles connection opening and closing automatically.

The Net::SMTP.start method accepts several parameters to configure the connection:

  • address: The hostname or IP address of the SMTP server (defaults to ‘localhost’).
  • port: The port number of the SMTP server (defaults to 25, the standard SMTP port).
  • helo_domain: The domain name your client identifies itself with (HELO/EHLO command, defaults to your system’s hostname).
  • user: Username for SMTP authentication (if needed, defaults to nil).
  • password: Password for SMTP authentication (if needed, defaults to nil).
  • authtype: The authentication mechanism (e.g., :plain, :login, :cram_md5, defaults to :cram_md5 if user is provided).

Inside the block passed to start, the SMTP instance provides the send_message method, which takes:

  • message_string: The full email message content (headers and body) as a string.
  • from_address: The sender’s email address (for the MAIL FROM SMTP command).
  • to_addresses: A single recipient email address (string) or an array of recipient email addresses.

Here’s a simple example of sending an email. This assumes an SMTP server is running on localhost without authentication. For real-world scenarios, you’ll likely use a remote SMTP server, often requiring authentication.

require 'net/smtp'
message_body = <<~MESSAGE_END
From: Your Name <your_email@example.com>
To: Recipient Name <recipient_email@example.com>
Subject: Test Email from Ruby (Net::SMTP)
This is a test email message sent using Net::SMTP in Ruby.
Regards,
Ruby Script
MESSAGE_END
begin
Net::SMTP.start('localhost', 25) do |smtp|
smtp.send_message message_body,
'your_email@example.com',
'recipient_email@example.com'
end
puts "Email sent successfully!"
rescue StandardError => e
puts "Error sending email: #{e.message}"
end

Note: The <<~MESSAGE_END (squiggly heredoc) allows for indented heredocs, stripping leading whitespace. Email headers (From, To, Subject) are crucial and must be formatted correctly, separated from the body by a blank line.

Connecting to a Remote SMTP Server with Authentication:

To use a remote SMTP server (like Gmail, SendGrid, etc.), you’ll need its address, port, and your credentials.

# Example for a generic authenticated SMTP server
# Replace with your actual server details and credentials
# Net::SMTP.start('smtp.your_mail_provider.com',
# 587, # Common port for TLS/STARTTLS
# 'your_helo_domain.com', # Often your sending domain
# 'your_username',
# 'your_password',
# :plain) do |smtp|
# # ... smtp.send_message ...
# end
# For Gmail, you might need to enable 'less secure app access' or use App Passwords.
# Gmail's SMTP server: smtp.gmail.com, Port: 587 (TLS) or 465 (SSL - Net::SMTP.enable_ssl before start)
# It's often better to use specific mailer gems for services like Gmail due to security and configuration nuances.

To send an email in HTML format, you need to set the Content-Type header to text/html and include a MIME-Version header.

require 'net/smtp'
html_message = <<~MESSAGE_END
From: Your Name <your_email@example.com>
To: Recipient Name <recipient_email@example.com>
MIME-Version: 1.0
Content-Type: text/html; charset=UTF-8
Subject: HTML Test Email from Ruby
<html>
<body>
<h1>Hello from Ruby!</h1>
<p>This is an email message sent in **HTML format**.</p>
<p><a href="https://www.ruby-lang.org">Visit Ruby's Official Website</a></p>
</body>
</html>
MESSAGE_END
begin
Net::SMTP.start('localhost', 25) do |smtp|
smtp.send_message html_message,
'your_email@example.com',
'recipient_email@example.com'
end
puts "HTML Email sent successfully!"
rescue StandardError => e
puts "Error sending HTML email: #{e.message}"
end

Sending attachments requires constructing a multipart MIME message. This involves defining boundaries to separate different parts of the email (text body, HTML body, attachments). Each part has its own Content-Type and Content-Disposition headers. Attachments are typically Base64 encoded.

Manually constructing multipart emails with Net::SMTP can be complex. For robust attachment handling and multipart emails, using a dedicated mailer gem like Mail is highly recommended as it simplifies these tasks significantly. However, here’s a conceptual example of how it would look with raw Net::SMTP (simplified):

require 'net/smtp'
require 'base64' # For Base64.strict_encode64
# --- Configuration ---
from_email = 'your_email@example.com'
to_email = 'recipient_email@example.com'
subject = 'Email with Attachment from Ruby'
text_body = "Please find the attached file."
file_to_attach_path = './my_document.txt' # Create this file for testing
# Create a dummy file for testing if it doesn't exist
File.write(file_to_attach_path, "This is a test document.") unless File.exist?(file_to_attach_path)
# --- Read and encode attachment ---
begin
file_content = File.read(file_to_attach_path)
encoded_content = Base64.strict_encode64(file_content)
attachment_filename = File.basename(file_to_attach_path)
rescue Errno::ENOENT
puts "Error: Attachment file not found at #{file_to_attach_path}"
exit
end
# --- Construct MIME message ---
marker = "MAIL_BOUNDARY_#{Time.now.to_i}_#{rand(1000)}"
message_parts = []
message_parts << "From: Your Name <#{from_email}>"
message_parts << "To: Recipient Name <#{to_email}>"
message_parts << "Subject: #{subject}"
message_parts << "MIME-Version: 1.0"
message_parts << "Content-Type: multipart/mixed; boundary=\"#{marker}\""
message_parts << "\n--#{marker}"
message_parts << "Content-Type: text/plain; charset=UTF-8"
message_parts << "Content-Transfer-Encoding: 7bit"
message_parts << "\n#{text_body}"
message_parts << "\n--#{marker}"
message_parts << "Content-Type: application/octet-stream; name=\"#{attachment_filename}\""
message_parts << "Content-Transfer-Encoding: base64"
message_parts << "Content-Disposition: attachment; filename=\"#{attachment_filename}\""
message_parts << "\n#{encoded_content}"
message_parts << "\n--#{marker}--"
full_message = message_parts.join("\r\n") # Use CRLF for line endings in email
# --- Send email ---
begin
Net::SMTP.start('localhost', 25) do |smtp|
smtp.send_message full_message, from_email, to_email
end
puts "Email with attachment sent successfully!"
rescue StandardError => e
puts "Error sending email with attachment: #{e.message}"
end

Important Considerations:

  • Error Handling: Always include begin...rescue blocks to catch potential errors like connection failures, authentication issues, or invalid addresses.
  • Security (TLS/SSL): For secure communication, especially with remote SMTP servers, ensure you are using TLS/STARTTLS (often on port 587) or SSL (often on port 465). Net::SMTP supports enable_starttls_auto (if server supports it) or enable_ssl (for direct SSL connections). For enable_ssl you might need to create the Net::SMTP object with Net::SMTP.new then call enable_ssl and then start without a block, or use OpenSSL context options. Check the Net::SMTP documentation for details.
  • Mailer Gems: For anything beyond simple emails, or for features like templates, advanced attachment handling, and easier configuration for various email providers, consider using gems like Mail (github.com/mikel/mail) or Action Mailer (if you are using Ruby on Rails). These gems abstract away many complexities of Net::SMTP.
  • Email Headers and Formatting: Pay close attention to RFC standards for email headers and MIME formatting to ensure your emails are rendered correctly by various email clients.

For comprehensive details, refer to the official Ruby documentation for the Net::SMTP class.