Mails in Ruby on Rails – Complete Action Mailer Guide

Mails in Ruby on Rails – Complete Guide with Examples

Mails in Ruby on Rails – Complete Guide

📌 What are Mails in Rails?

In Ruby on Rails, sending emails is handled by a component called Action Mailer. It’s a powerful module that allows your application to send emails using SMTP, APIs, or third-party services. You can use it to notify users, reset passwords, confirm orders, send invoices, and much more.

Action Mailer works just like a controller. You define a mailer class and methods inside it, then use views to create email content (both plain text and HTML). It supports background delivery with Active Job (e.g. Sidekiq), file attachments, email previews in development, and even custom layouts.

Rails abstracts all the complexity of email configuration and gives you a clean way to create and send dynamic and styled emails. You can use it for everything from user account actions to marketing.

Use Cases:

  • 🔐 Password reset links
  • 👋 Welcome emails after signup
  • 📩 Order confirmations with tracking info
  • 🧾 Invoice attachments
  • 📢 Admin notifications or newsletters

Overall, Action Mailer makes it extremely easy for Rails developers to integrate email functionality into any type of application without writing low-level code.

🧩 Different Types of Email Templates in Rails

In Rails, email templates are written just like views. Each mailer method has corresponding templates which can be in multiple formats:

Template TypeFile ExtensionDescriptionExample File
HTML Email.html.erbRich HTML content for modern email clientswelcome_email.html.erb
Plain Text Email.text.erbFallback for clients that don’t support HTMLwelcome_email.text.erb
Multipart EmailBothRails automatically picks both HTML and text if both templates existwelcome_email.html.erb + welcome_email.text.erb
Partial Templates_*.html.erbReusable template blocks (e.g. signature, header)_footer.html.erb
Layout Templateslayouts/mailer.html.erbShared email layout for branding (wrapper with styles)mailer.html.erb

📄 Example: Welcome Email Template


    # app/views/user_mailer/welcome_email.html.erb
    
    <h1>Welcome, <%= @user.name %>!</h1>
    <p>Thanks for signing up with us. You can now enjoy our services.</p>
    
    <%= render 'shared/footer' %>
      

✅ Best Practices

  • Use multipart templates to support both HTML and plain text clients.
  • Separate common components (e.g., signature, branding) into partials.
  • Use layouts to keep a consistent design across emails.
  • Keep templates clean and test rendering with Mailer Previews.
  • Avoid heavy CSS — stick to inline styles for maximum compatibility.

⚙️ Full Implementation Cycle of Mail Templates in Rails

Here’s a step-by-step implementation flow for using email templates effectively with Action Mailer.

1️⃣ Generate the Mailer

rails generate mailer UserMailer

This creates:

  • app/mailers/user_mailer.rb
  • app/views/user_mailer/
  • test/mailers/user_mailer_test.rb

2️⃣ Define a Mail Method

# app/mailers/user_mailer.rb
    
    class UserMailer < ApplicationMailer
      def welcome_email(user)
        @user = user
        mail(to: @user.email, subject: "Welcome to Our App!")
      end
    end
      

3️⃣ Create HTML and Text Templates

# app/views/user_mailer/welcome_email.html.erb
    
    <h1>Welcome, <%= @user.name %>!</h1>
    <p>Thank you for joining. Start exploring now!</p>
      
# app/views/user_mailer/welcome_email.text.erb
    
    Welcome, <%= @user.name %>!
    Thank you for joining. Start exploring now!
      

4️⃣ Create a Layout (Optional)

Use a layout to wrap your emails with consistent branding.

# app/views/layouts/mailer.html.erb
    
    <!DOCTYPE html>
    <html>
      <head><meta charset="utf-8"></head>
      <body>
        <div style="padding: 20px; font-family: sans-serif;">
          <%= yield %>
          <hr>
          <p style="font-size: 12px;">This is an automated message.</p>
        </div>
      </body>
    </html>
      

5️⃣ Add a Partial (Reusable Footer)

# app/views/user_mailer/_footer.html.erb
    
    <p>Thanks,<br>The Support Team</p>
      
# In your main template
    <%= render 'footer' %>
      

6️⃣ Trigger Mail from Controller or Background Job

In controller:

UserMailer.welcome_email(@user).deliver_now

Or with background job:

UserMailer.welcome_email(@user).deliver_later

7️⃣ Preview Emails in Development

# app/mailers/previews/user_mailer_preview.rb
    
    class UserMailerPreview < ActionMailer::Preview
      def welcome_email
        user = User.first
        UserMailer.welcome_email(user)
      end
    end
      

Then visit http://localhost:3000/rails/mailers to preview the email!

8️⃣ SMTP Settings for Sending

# config/environments/development.rb
    
    config.action_mailer.delivery_method = :smtp
    config.action_mailer.smtp_settings = {
      address: "smtp.sendgrid.net",
      port: 587,
      authentication: :plain,
      user_name: ENV["SMTP_USER"],
      password: ENV["SMTP_PASSWORD"],
      domain: "yourdomain.com",
      enable_starttls_auto: true
    }
      

✅ Summary of the Template Lifecycle

  1. Create a mailer
  2. Add mail methods
  3. Create HTML and plain views
  4. Add layout and partials
  5. Trigger email via controller/job
  6. Use deliver_later for background jobs
  7. Test with Mailer Preview
  8. Deploy with SMTP config

This cycle makes it easy to build beautiful, testable, and scalable email systems in Rails.

📚 Key Terms and Concepts in Rails Mailer

TermDescription
ActionMailerRails component responsible for sending emails using SMTP or API services.
Mailer ClassA Ruby class that defines email methods (e.g., UserMailer).
mail()Rails method to construct an email — sets to, from, subject.
.html.erbTemplate for HTML content in emails (rich formatting).
.text.erbPlain text version of the email for fallback clients.
layouts/mailer.html.erbShared layout template applied to all emails (branding, wrappers).
PartialReusable snippet used in templates, e.g. _footer.html.erb.
deliver_nowSends the email immediately (synchronous).
deliver_laterSends the email asynchronously using Active Job and a background processor.
Mailer PreviewTool in development to preview emails in browser at /rails/mailers.
SMTPSimple Mail Transfer Protocol – the default protocol used for sending email.
SidekiqA background job processor often used with deliver_later.
ENV[]Used to access environment variables for securing credentials like SMTP user/password.
rails generate mailerRails CLI command to create a new mailer class with test and view files.

🌐 Different Platforms to Send Emails in Rails

You can integrate Rails with various platforms for reliable and scalable email delivery. Here’s a comparison:

PlatformTypeDescriptionBest For
SendGridAPI / SMTPPopular, reliable email service with APIs and dashboards. Free tier available.Transactional & marketing emails, scalable apps
MailgunAPI / SMTPDeveloper-friendly email service with advanced analytics and inbound routing.High-volume transactional emails, dev automation
PostmarkAPI / SMTPFast, reliable transactional email service focused on deliverability.Important user notifications (password resets, invoices)
Amazon SESSMTP / APIHighly scalable and cost-effective from AWS. Requires domain verification.Large-scale apps needing low cost
Gmail SMTPSMTPUse your Gmail account to send mail via SMTP. Good for personal or small projects.Testing, small apps, internal tools
Outlook/Office365 SMTPSMTPMicrosoft’s SMTP service for business-level email accounts.Corporate tools, admin notifications
Brevo (ex-Sendinblue)SMTP / APIEmail marketing & transactional delivery service. Offers automation workflows.Newsletter + system alerts
Zoho MailSMTPZoho Mail provides SMTP for apps with domain-linked inboxes.Business mail + app notifications
SMTP2GOSMTPGlobally distributed SMTP delivery system with detailed logs and bounce handling.Remote apps, distributed teams

Tip: For production apps, use API-based services like SendGrid or Postmark with background job delivery to ensure better deliverability and tracking.

🧾 Using Templates from Email Platforms in Rails

Most modern email services like SendGrid, Mailgun, Postmark, Brevo (Sendinblue), and Amazon SES offer hosted templates that you can create and manage directly on their dashboard. Instead of designing email content inside Rails views (.html.erb), you offload the layout and formatting to the platform.

💡 What Are Hosted Templates?

Hosted templates are reusable email layouts stored and rendered on the email provider’s side. These templates support:

  • 📄 Visual builders (drag & drop or WYSIWYG)
  • 📦 Reusable layout and design
  • 🧠 Dynamic variables (e.g., user name, order ID)
  • 📈 Analytics like opens, clicks, bounce tracking
  • 🪄 A/B testing, version control, automation triggers

🔗 Integration Flow from Rails

  1. Create your email template in the provider dashboard (SendGrid, Mailgun, etc.)
  2. Get the template_id (or slug)
  3. Inject dynamic values using the provider’s API (e.g., name, code, links)
  4. Send the email via HTTP request (not using ActionMailer views)

📊 Template Feature Comparison

PlatformVisual BuilderDynamic VariablesAPI SendingRails SDK/Gem
SendGrid✅ Drag & Drop✅ Handlebars {{name}}✅ via v3/mail/sendsendgrid-ruby
Mailgun⚠️ Code or upload✅ via %recipient.name%✅ via /messagesmailgun-ruby
Postmark✅ HTML + editor✅ via {{name}}✅ via /email/withTemplatepostmark-rails
Amazon SES⚠️ JSON-based✅ via JSON inputSendTemplatedEmailaws-sdk-ses
Brevo (Sendinblue)✅ Drag & Drop✅ {{contact.FIRSTNAME}}✅ via /smtp/emailsib-api-v3-sdk

🛠️ Example: SendGrid Email Template Integration in Rails

# Gemfile
    gem 'sendgrid-ruby'
# app/jobs/send_promotional_email_job.rb
    
    class SendPromotionalEmailJob < ApplicationJob
      queue_as :default
    
      def perform(user)
        data = {
          personalizations: [
            {
              to: [{ email: user.email }],
              dynamic_template_data: {
                name: user.name,
                discount: "25% OFF",
                cta_link: "https://yourapp.com/deals"
              }
            }
          ],
          from: { email: "no-reply@yourapp.com" },
          template_id: ENV["SENDGRID_TEMPLATE_ID"]
        }
    
        sg = SendGrid::API.new(api_key: ENV["SENDGRID_API_KEY"])
        sg.client.mail._("send").post(request_body: data)
      end
    end
      

🔁 Now you can update your email design in the SendGrid dashboard without changing any code in Rails.

✅ Best Practices

  • Use deliver_later or background jobs for sending platform-based emails
  • Keep template_id in ENV variables
  • Use versioning or naming convention for templates (e.g., welcome_v2)
  • Use the email provider’s built-in test and preview tools before activating in production
  • Monitor delivery, bounce, and open rates via dashboard or webhook callbacks

Tip: This approach is ideal for high-conversion transactional or marketing emails. It also makes it easier for designers or marketing teams to update content without developer involvement.

📬 How to Send HTML, Text, or Multipart Emails in Rails

Ruby on Rails supports three common formats when sending emails: plain text, HTML, or multipart (both). You don’t need to configure anything special—Rails automatically chooses the right format based on which templates you provide in the app/views/mailer_name/ folder.

1️⃣ Plain Text Only Email

If you only provide a .text.erb file, Rails will send a plain email with no styling or HTML tags.

# app/views/user_mailer/welcome_email.text.erb
    
    Hello <%= @user.name %>,
    
    Thanks for joining our app!
    
    Best,
    The Team
      

Use Case: Minimalist systems, CLI emails, fallback-only systems.

2️⃣ HTML Only Email

If you only create a .html.erb template, Rails will send the email as HTML.

# app/views/user_mailer/welcome_email.html.erb
    
    <h1>Welcome, <%= @user.name %>!</h1>
    <p>Thanks for signing up.</p>
    <p><a href="https://yourapp.com">Click here</a> to get started.</p>
      

Use Case: Styled content, links, buttons, visual branding.

3️⃣ Multipart Email (HTML + Text)

This is the most recommended setup. Just create both templates:

  • app/views/user_mailer/welcome_email.text.erb
  • app/views/user_mailer/welcome_email.html.erb

Rails will automatically send a multipart email that contains both formats. Email clients (like Gmail, Apple Mail, Outlook) decide which version to display depending on user preferences or compatibility.

📁 File Structure Example


    app/
    └── views/
        └── user_mailer/
            ├── welcome_email.html.erb
            └── welcome_email.text.erb
      

✅ Best Practices

  • Always provide both versions when possible (HTML + Text)
  • Use tools like Litmus or Mailtrap to preview both formats
  • Use inline styles in HTML (avoid CSS files—many email clients ignore them)
  • Keep the text version simple and readable
  • Test both formats in multiple mail clients (Gmail, Apple Mail, Outlook)

By following the multipart approach, you ensure better **accessibility**, **spam score compliance**, and **user experience** across all devices and clients.

📎 How to Attach Files and Images in Rails Emails

Rails makes it easy to send attachments (like PDFs or images) with your emails using attachments[] in your mailer method. You can also embed inline images (e.g., company logos) inside the email body.

📄 1. Attaching a File (e.g. PDF Invoice)

# app/mailers/user_mailer.rb
    
    def invoice_email(user)
      @user = user
      pdf_path = Rails.root.join("public", "invoices", "invoice_#{user.id}.pdf")
    
      attachments["invoice.pdf"] = File.read(pdf_path)
      mail(to: @user.email, subject: "Your Invoice is Ready")
    end
      

Note: You can dynamically generate files (e.g. with Prawn or WickedPDF) before attaching them.

🖼️ 2. Embedding Inline Images (e.g. Logo)

To display an image inside the email content:

# app/mailers/user_mailer.rb
    
    def welcome_email(user)
      @user = user
      attachments.inline['logo.png'] = File.read(Rails.root.join("app/assets/images/logo.png"))
      mail(to: @user.email, subject: "Welcome to Our App")
    end
      
<!-- app/views/user_mailer/welcome_email.html.erb -->
    
    <h1>Welcome, <%= @user.name %></h1>
    <img src="cid:logo.png" alt="Company Logo" />
    <p>We’re glad to have you!</p>
      

📦 3. Sending Multiple Attachments

Loop through a list of files and attach each one:

["report1.pdf", "report2.pdf"].each do |filename|
      attachments[filename] = File.read(Rails.root.join("reports", filename))
    end

⚠️ Common Pitfalls

  • ✅ Ensure the file path exists and is readable in production
  • 📁 Don’t store sensitive files publicly—use private locations or signed URLs
  • 📧 Large attachments (over 5MB) may fail depending on SMTP limits
  • 💡 Use background jobs when generating and attaching dynamic files

✅ Best Practices

  • Generate PDFs on the fly using Prawn or WickedPDF
  • Use inline attachments for branding images (e.g., company logo)
  • Preview emails locally to confirm attachments appear correctly
  • For marketing emails with many images, consider external hosted images with CDN

File and image attachments improve email UX—just make sure they’re used carefully to avoid bloated emails or delivery issues.

❓ 10 In-Depth Questions & Answers on Mails in Ruby on Rails

  1. Q1: What is Action Mailer in Ruby on Rails?
    A: Action Mailer is a core framework in Rails used to send emails. It works much like controllers: you define mailer classes, methods (actions), and views (email templates). With Action Mailer, you can send both plain text and HTML emails, attach files, use layouts, and even preview emails in development. It supports sending via SMTP or external APIs like SendGrid, Mailgun, etc.
  2. Q2: What’s the difference between deliver_now and deliver_later?
    A:
    • deliver_now sends the email immediately during the request-response cycle, blocking the user until complete.
    • deliver_later adds the email to a background job queue (like Sidekiq or Active Job) and sends it asynchronously.

    Example:

    UserMailer.welcome_email(@user).deliver_later – this won’t delay your web request.

  3. Q3: How do I create and send a basic email in Rails?
    A:
    1. Generate a mailer: rails generate mailer UserMailer
    2. Add a method:
      def welcome_email(user); @user = user; mail(to: user.email, subject: "Welcome!"); end
    3. Create a template: app/views/user_mailer/welcome_email.html.erb
    4. Call it: UserMailer.welcome_email(@user).deliver_now
  4. Q4: How can I preview emails in development?
    A: Rails supports mail previews. Create a preview file like this:
    # test/mailers/previews/user_mailer_preview.rb
        class UserMailerPreview < ActionMailer::Preview
          def welcome_email
            UserMailer.welcome_email(User.first)
          end
        end
              
    Then visit: http://localhost:3000/rails/mailers to preview your emails.
  5. Q5: Can I send both HTML and plain text emails?
    A: Yes. Create two versions:
    • welcome_email.html.erb – for rich HTML
    • welcome_email.text.erb – fallback for email clients that don’t support HTML
    Rails will automatically send a multipart email with both versions included.
  6. Q6: How do I attach a file to an email in Rails?
    A: Use the attachments[] syntax inside your mailer:
    attachments["invoice.pdf"] = File.read("/path/to/invoice.pdf")
        mail(to: user.email, subject: "Your Invoice")
    This works well for sending invoices, PDFs, or images.
  7. Q7: How do I configure SMTP for production?
    A: Configure config/environments/production.rb like this:
    config.action_mailer.delivery_method = :smtp
        config.action_mailer.smtp_settings = {
          address: "smtp.sendgrid.net",
          port: 587,
          user_name: ENV["SMTP_USERNAME"],
          password: ENV["SMTP_PASSWORD"],
          authentication: :plain,
          enable_starttls_auto: true
        }
    Always store credentials in ENV or Rails encrypted credentials.
  8. Q8: What happens if a background email fails?
    A: If you’re using deliver_later, Rails uses Active Job to enqueue the task. If the job fails:
    • It will retry automatically (depending on your queue adapter)
    • You can use rescue_from to handle mail failures
    • Monitor it using tools like Sidekiq Web or Exception Tracking
  9. Q9: Can I use SendGrid or Mailgun templates instead of Rails views?
    A: Yes. These platforms support hosted templates. In Rails, you send an API call with template ID and merge variables. Example using SendGrid:
    mail.template_id = "d-123abc456"
        dynamic_template_data: { name: "John" }
    This allows non-developers to manage the design on SendGrid dashboard.
  10. Q10: What is the benefit of using a mailer layout?
    A: A layout is like a shared wrapper around all emails. You can define headers, footers, and common branding (like logos or disclaimers) in: app/views/layouts/mailer.html.erb
    Example:
    <html>
          <body>
            <%= yield %>
            <p>Thanks, The Team</p>
          </body>
        </html>
    This keeps your emails consistent and DRY.

✅ Best Practices for Sending Emails in Ruby on Rails

  • 📁 Organize your mailers by feature or role:
    Use separate mailer classes like AdminMailer, UserMailer, OrderMailer for better separation of concerns.
  • 📄 Use multipart emails (HTML + Text):
    Always create both .html.erb and .text.erb versions so clients can choose based on compatibility.
  • 🖼️ Use layouts and partials:
    DRY your email templates with shared headers, footers, and branding via partials and a mailer layout (e.g. layouts/mailer.html.erb).
  • 📤 Always use deliver_later in production:
    Offload email delivery to background jobs using ActiveJob with Sidekiq/Resque to avoid blocking the request.
  • 🔒 Hide SMTP credentials:
    Never hard-code SMTP usernames or passwords. Use Rails credentials (config/credentials.yml.enc) or ENV variables.
  • 📬 Use a trusted provider:
    Use platforms like SendGrid, Postmark, or Mailgun to improve deliverability, spam compliance, and analytics.
  • 📈 Monitor email success/failure:
    Use dashboards and webhook callbacks (from your provider) to track bounces, opens, clicks, and failures.
  • 🧪 Test emails thoroughly:
    Write mailer specs with RSpec or Minitest. Preview each mail using /rails/mailers to confirm layout and data rendering.
  • 🛑 Avoid heavy attachments:
    Keep attachments under 5 MB. For large files, consider sending links to signed downloads (e.g., from AWS S3).
  • 🕓 Delay non-critical emails:
    For marketing or newsletters, delay delivery using deliver_later(wait: 10.minutes) or schedule with cron/Sidekiq.

Following these best practices ensures your Rails email system is clean, efficient, reliable, and secure for users and developers alike.

🔗 External Resources & Further Reading

Here are some official docs, guides, and tools to help you dive deeper into sending emails with Rails:

These resources will help you understand mail delivery, debugging, testing, and using external providers like SendGrid or Mailgun effectively with Rails.

Learn more about Rails

Scroll to Top