DEV Community

Cover image for How to Send Emails in Ruby - Complete Guide with Code Examples
David Ozokoye for SendLayer

Posted on • Originally published at sendlayer.com

How to Send Emails in Ruby - Complete Guide with Code Examples

Do you need to add email functionality to your Ruby application?

Whether you're building user authentication, notification systems, or contact forms, sending emails is a fundamental feature that every developer needs to master.

In this comprehensive Ruby email tutorial, I'll show you 2 ways to send email in Ruby app.

Table of Contents

How to Send Email with Ruby

There are different ways to send emails using Ruby. If you're using Ruby on Rails, you can integrate quickly with the ActionMailer gem. This guide will focus on sending methods for vanilla Ruby applications.

Prerequisites

Before diving into the email implementations, make sure you have:

  • Ruby installed (version 3.1 or higher recommended)
  • Basic Ruby programming knowledge
  • A text editor or IDE of your choice
  • An email service provider

You can use any email service provider you want. However, for this tutorial, I'll use SendLayer's SMTP credentials when implementing the email function.

SendLayer is one of the leading email service providers that lets you send emails easily and integrates with any application.

One of the standout features I like is the domain reputation protection. SendLayer automatically creates a subdomain to handle email sending activities. This thereby protects your main domain from any deliverability issues.

SendLayer offers a free account that allows users to send up to 200 emails per month. The pricing plan is also flexible, starting at $5 monthly.

Start your free trial at SendLayer

How to Send Emails in Ruby Using the Mail Gem

The Ruby Mail gem is a customizable library that gives you control over your email implementation. It is perfect for Ruby applications outside of Rails. Here's how to get started with the Mail gem.

Installation and Setup

To start, you'll need to install the Mail gem as a dependency to your project. To install it, open a terminal window and run the command below:

gem install mail
Enter fullscreen mode Exit fullscreen mode

Tip: Prefix the command with sudo if you encounter permission issues when installing the Mail Ruby gem.

Once the installation completes, you should see a success notification in your terminal window.

Ruby Mail gem installation in terminal

Basic Email Configuration

Before you can send an email, you'll need to configure your SMTP server. Here's how to configure the Mail gem with SendLayer SMTP. Start by creating an email_service.rb file in your project's directory.

touch email_service.rb
Enter fullscreen mode Exit fullscreen mode

Then open the file with a code editor. Once open, copy and paste the code below to the email service file:

require 'mail'

Mail.defaults do
  delivery_method :smtp, {
    address: 'smtp.sendlayer.net',
    port: 587,
    user_name: 'your_sendlayer_username',
    password: 'your_sendlayer_password',
    authentication: 'plain',
    enable_starttls_auto: true
  }
end
Enter fullscreen mode Exit fullscreen mode

You'll need to retrieve your SMTP credentials from the email provider you chose. In SendLayer, you'll be able to access these details from your account area.

Once logged in, navigate to the Settings sidebar menu. Then select the SMTP Credentials tab.

SendLayer SMTP credentials

You'll see the SMTP credentials required to use SendLayer's SMTP server. The Host and Port number are the same for all users. However, the Username and Password details are unique to your SendLayer account.

Go ahead and replace user_name and password in the snippet above with your actual credentials.

Pro Tip: Never commit sensitive credentials to version control platforms. Always use environment variables.

After updating your SMTP credentials, you're ready to start sending emails.

Sending Plain Text Emails

Here's a basic implementation for sending text emails:

require 'mail'

class EmailService
  def self.configure_smtp
    Mail.defaults do
      delivery_method :smtp, {
        address: 'smtp.sendlayer.net',
        port: 587,
        user_name: ENV['SENDLAYER_USERNAME'],
        password: ENV['SENDLAYER_PASSWORD'],
        authentication: 'plain',
        enable_starttls_auto: true
      }
    end
  end

  def self.send_welcome_email(user_email, user_name)
    welcome_message = generate_welcome_message(user_name)

    mail = Mail.new do
      from     'paulie@example.com'
      to       user_email
      subject  'Welcome to Our Platform!'
      body     welcome_message
    end

    mail.deliver!
    puts "Welcome email sent to #{user_email}"
  rescue Mail::SMTPError => e
    puts "Failed to send email: #{e.message}"
  end

  private

  def self.generate_welcome_message(name)
    <<~MESSAGE
      Hello #{name},

      Welcome to our platform! We're excited to have you join our community.

      You can log in to your account at: https://yourdomain.com/login

      If you have any questions, please don't hesitate to contact our support team.

      Best regards,
      The Team
    MESSAGE
  end
end
Enter fullscreen mode Exit fullscreen mode

Code breakdown

The configure_smtp method sets up the mail delivery configuration using Mail.defaults. We specify the SMTP details, including the address (smtp.sendlayer.net), port (587 for TLS), authentication credentials from environment variables, and enable STARTTLS for secure transmission.

The send_welcome_email method creates a new Mail object using a block syntax. We set the sender address with from, recipient with to, email subject, and generate the email body by calling a private helper method.

The mail.deliver! method actually sends the email through the configured SMTP server. The exclamation mark indicates this method will raise an exception if delivery fails.

Error handling is implemented using a rescue block that catches Mail::SMTPError exceptions. When an SMTP error occurs during delivery, it prints a failure message instead of crashing the application.

The private generate_welcome_message method uses Ruby's heredoc syntax (<<~MESSAGE) to create a multi-line string template. The ~ removes leading whitespace, making the code more readable while preserving the email formatting.

Send a Test Email

The next step after implementing the email function is to call the class. Let's create a main.rb file that'll send the message. After that, copy and paste the code below into the file:

# importing the email service
require_relative 'email_service'

# configure SMTP settings
EmailService.configure_smtp

# send welcome email
EmailService.send_welcome_email('pattie@example.com', 'Pattie Paloma')
Enter fullscreen mode Exit fullscreen mode

In the snippet above, we first import the email service file. Then call the configure_smtp() method to initialize the SMTP connection. Finally, we call the send_welcome_email() method to send the email. This method accepts 2 parameters: the recipient's email address and name.

To run the script, open a terminal window and run the command:

ruby main.rb
Enter fullscreen mode Exit fullscreen mode

You should see a welcome email delivered to the specified email address with personalized content.

Send email in ruby Gmail example

Sending an HTML Email

The Mail gem also supports HTML content with embedded CSS. This is ideal for brands looking to send newsletter content to users. To send HTML emails, you'll need to use the html_part property when defining the mail object. Within the property, you'll need to pass the content_type and body attributes.

Here's the code to implement this logic. You can add this as an additional class within the email_service.rb file:

require 'mail'

class HtmlEmailService
    def self.configure_smtp
        Mail.defaults do
          delivery_method :smtp, {
            address: 'smtp.sendlayer.net',
            port: 587,
            user_name: ENV['SENDLAYER_USERNAME'],
            password: ENV['SENDLAYER_PASSWORD'],
            authentication: 'plain',
            enable_starttls_auto: true
          }
        end
    end

    def self.send_newsletter(recipient_email, newsletter_data)

      newsletter_message = generate_html_content(newsletter_data)
      text_message = generate_text_content(newsletter_data)

      mail = Mail.new do
        from     'newsletter@example.com'
        to       recipient_email
        subject  'Monthly Newsletter - Ruby Tips & Tricks'

        html_part do
          content_type 'text/html; charset=UTF-8'
          body newsletter_message
        end

        text_part do
          body text_message
        end
      end

      mail.deliver!
    end

    private

    def self.generate_html_content(data)
      <<~HTML
        <!DOCTYPE html>
        <html>
          <head>
            <style>
              body { font-family: Arial, sans-serif; margin: 0; padding: 20px; }
              .header { background: #2c3e50; color: white; padding: 20px; text-align: center; }
              .content { padding: 20px; background: #f9f9f9; }
              .article { margin-bottom: 20px; padding: 15px; background: white; border-radius: 5px; }
              .footer { text-align: center; padding: 20px; font-size: 12px; color: #666; }
            </style>
          </head>
          <body>
            <div class="header">
              <h1>#{data[:title]}</h1>
            </div>
            <div class="content">
              #{data[:articles].map { |article| format_article(article) }.join}
            </div>
            <div class="footer">
              <p>© 2024 Your Company. All rights reserved.</p>
            </div>
          </body>
        </html>
      HTML
    end

    def self.format_article(article)
      <<~ARTICLE
        <div class="article">
          <h2>#{article[:title]}</h2>
          <p>#{article[:summary]}</p>
          <a href="#{article[:url]}">Read More</a>
        </div>
      ARTICLE
    end

    def self.generate_text_content(data)
      content = "#{data[:title]}\n\n"
      data[:articles].each do |article|
        content += "#{article[:title]}\n#{article[:summary]}\nRead more: #{article[:url]}\n\n"
      end
      content += "© 2024 Your Company. All rights reserved."
      content
    end
  end
Enter fullscreen mode Exit fullscreen mode

Code Breakdown

The Mail object uses multipart structure with separate html_part and text_part blocks. The HTML part explicitly sets the content type to 'text/html; charset=UTF-8' to ensure proper rendering, while the text part uses the default plain text format. This approach ensures email clients can display either version based on their capabilities.

The generate_html_content method uses Ruby's heredoc syntax to create a complete HTML email template. It includes inline CSS styling for better email client compatibility and uses string interpolation (#{data[:title]}) to insert dynamic content from the newsletter data hash.

The helper method format_article generates individual article HTML blocks using the same heredoc approach. It takes an article hash and formats it with title, summary, and read-more link within styled div containers.

The generate_text_content method creates a plain text fallback version by iterating through the articles array using each and building a simple text format. This ensures users with text-only email clients can still read the newsletter content.

While Rails mailer includes built-in mailer views for template management, in vanilla Ruby, we handle HTML templates directly.

Send a Test HTML email in Ruby

Here's how you'll use the HTMLEmailService class we created. In your main.rb file, copy and paste the code snippet below:

# importing the email service
require_relative 'email_service'

# configure SMTP settings
HtmlEmailService.configure_smtp

# create newsletter data
newsletter_data = {
    title: "This Month in SendLayer",
    articles: [
      {
        title: "New Ruby SDK Launched",
        summary: "Discover the latest improvements in SendLayer API",
        url: "https://example.com/features"
      }
    ]
  }

# send HTML email
HtmlEmailService.send_newsletter('pattie@example.com', newsletter_data)
Enter fullscreen mode Exit fullscreen mode

When you test this implementation, email clients will automatically select the HTML or text version based on user preferences and client capabilities. Providing the best possible experience for all recipients.

Test HTML email in ruby

Send Email with Attachments

The Mail gem includes support for attaching files to emails. To send an email with an attachment, you'll need to include the add_file property when specifying the email parameters. Here's an example:

require 'mail'

def send_email_with_attachment(recipient, attachment_path)
  mail = Mail.new do
    from     'noreply@yourdomain.com'
    to       recipient
    subject  'Document Attached'
    body     'Please find the attached document.'

    add_file attachment_path
  end

  mail.deliver!
end
Enter fullscreen mode Exit fullscreen mode

The value of the add_file property should be the path to the file you wish to attach. The Mail gem handles encoding and also tries to guess the file type.

To send multiple attachments, use Ruby's foreach syntax to map each attachment file to the add_file property. Here is an example:

# For multiple attachments
def send_email_with_multiple_attachments(recipient, attachment_paths)
  mail = Mail.new do
    from     'noreply@yourdomain.com'
    to       recipient
    subject  'Multiple Documents Attached'
    body     'Please find the attached documents.'

    attachment_paths.each { |path| add_file path }
  end

  mail.deliver!
end
Enter fullscreen mode Exit fullscreen mode

That's it! You've now learned how to send emails in Ruby using SMTP.

How to Send Emails in Ruby Using Email API

Sending emails through SMTP works well for smaller projects. However, it is less secure and slower when compared to using an email API.

Fortunately, platforms like SendLayer also include an API for sending emails and tracking events such as open and bounce rates. I'll show you how to set up a program that uses the SendLayer API to send emails.

Start your free trial at SendLayer

Send Emails With SendLayer API

To send an email using SendLayer API, you'll need 3 parameters:

  • Base URL: This is the API endpoint for sending emails. For SendLayer, this endpoint is available at https://console.sendlayer.com/api/v1/email
  • Headers: This is where you'll define the format for the request and also authenticate your connection
  • Payload: This contains the JSON object with details for sending an email, like the sender and recipient email addresses

Ruby provides a default net/http library for making HTTP requests. I'll use this gem to make the HTTP request to SendLayer's email endpoint. Here's the snippet to send emails with the SendLayer API.

require 'uri'
require 'net/http'

url = URI("https://console.sendlayer.com/api/v1/email")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = {
  "From": {
    "name": "Paulie Paloma",
    "email": "paulie@example.com"
  },
  "To": [
    {
      "name": "Pattie Paloma",
      "email": "pattie@exampledomain.com"
    }
  ],
  "Subject": "Test email with Ruby and SendLayer API",
  "ContentType": "HTML",
  "HTMLContent": "<html><body><p>This is a test email sent with the <a href='https://sendlayer.com'>SendLayer</a> API and Ruby!</p></body></html>",
}.to_json

response = http.request(request)
puts response.read_body
Enter fullscreen mode Exit fullscreen mode

Code Breakdown

In the snippet above, we first create a URI object from the SendLayer API endpoint and initialize an HTTP connection. We call http.use_ssl = true to enable SSL/TLS encryption for secure communication with the API server.

Next, we create a POST request object and set the required headers. The Authorization header uses Bearer token authentication with 'Bearer <token>', and we set the Content-Type to 'application/json' since we're sending JSON data.

Note: Remember to replace <token> with your actual SendLayer API token and update the email addresses to valid ones for testing.

The request body contains a Ruby hash with the email data structure that SendLayer expects. This hash is then converted to JSON format using .to_json before being assigned to request.body. This ensures the data is properly serialized for the API request.

Finally, we execute the request using http.request(request) and print the API response with response.read_body. The response will typically contain information about the delivery status or any error messages from the SendLayer service.

Retrieving SendLayer API Key

To get your API key, log in to your SendLayer account. Once you're logged in, click the Settings menu and select the API Keys tab.

Click API keys tab

Then click the copy icon next to Default API key to copy it.

Copy SendLayer API key

Sending Email to Multiple Recipients

SendLayer's API allows you to send emails to multiple recipients, including CC and BCC email addresses. To send an email to multiple recipients in Ruby, update the To array in the email body with the additional recipient(s) you want to add. Here's an example:

# other code snippets...

request.body = {
  "From": {
    "name": "Paulie Paloma",
    "email": "paulie@example.com"
  },
  "To": [
    {
      "name": "Pattie Paloma",
      "email": "pattie@example.com"
    },
   {
      "name": "John Doe",
      "email": "johndoe@example.com"
    }
  ],
  "CC": [
    {
      "name": "Pattie Paloma CC",
      "email": "pattie.cc@example.com"
    }
  ],
  "BCC": [
    {
      "name": "Pattie Paloma BCC",
      "email": "pattie.bcc@example.com"
    }
  ],
  "ReplyTo": [
    {
      "name": "Pattie Paloma ReplyTo",
      "email": "pattie.reply@example.com"
    }
  ],
  "Subject": "This is the email to multiple recipients",
  "ContentType": "HTML",
  "HTMLContent": "<html><body><p>This is a test email sent with the <a href='https://sendlayer.com'>SendLayer</a> API and Ruby!</p></body></html>",
}.to_json

# ... other code
Enter fullscreen mode Exit fullscreen mode

SendLayer API also lets you attach files to your email messages. See our developer guide for more details on sending emails through an email API.

Frequently Asked Questions

These are answers to some of the top questions developers ask about sending emails in Ruby.

What's the difference between Action Mailer and the Mail gem in Ruby?

Action Mailer is a built-in email framework providing seamless integration with Ruby on Rails applications. It includes templating, testing helpers, and background job integration. The Mail gem, on the other hand, is a standalone library that works in any Ruby application. It offers more low-level control over email creation and delivery.

How do I handle bounced emails and delivery failures?

The best way to handle delivery failures is by implementing proper error handling with try-catch blocks. You can also use webhook endpoints provided by your SMTP service to handle bounce notifications. Services like SendLayer provide detailed delivery reports and bounce handling.

How do I configure SMTP settings for production?

Proper mailer configuration is crucial for production environments. Always use environment variables for SMTP Ruby credentials and ensure your SMTP class implementation includes proper error handling and connection pooling.

What are the security best practices for email delivery in Ruby?

Below, we've highlighted some of the best practices for handling email in Ruby applications:

  • Always use environment variables for credentials
  • Enable TLS/SSL connections
  • Validate email addresses before sending
  • Implement rate limiting
  • Use reputable SMTP providers with proper authentication
  • Never expose API keys or passwords in your source code

Wrapping Up

In this comprehensive tutorial, we've walked through everything you need to know about sending emails in Ruby.

Have questions or want to share your implementation? Drop a comment below—I'd love to hear how you're handling email in your Ruby projects!

Ready to implement this in your application? Start your free trial at SendLayer and send your first email in minutes.

Top comments (0)