Courrier

API-powered email delivery for Ruby apps. With support for Mailgun, Postmark, Resend and more.

Add the gem:

bundle add courrier

Generate the configuration file:

bin/rails generate courrier:install

This creates config/initializers/courrier.rb for configuring email providers and default settings.

Usage

Generate a new email:

bin/rails generate courrier:email Order
class OrderEmail < Courrier::Email
  def subject = "Here is your order!"

  def text
    <<~TEXT
      text body here
    TEXT
  end

  def html
    <<~HTML
      html body here
    HTML
  end
end

# OrderEmail.deliver to: "recipient@railsdesigner.com"

đź’ˇ Write your email content using the Minimal Email Editor.

Configuration

Courrier uses a configuration system with three levels (from lowest to highest priority):

1. Global configuration

Courrier.configure do |config|
  config.provider = "postmark"
  config.api_key = "xyz"
  config.from = "devs@railsdesigner.com"
  config.default_url_options = { host: "railsdesigner.com" }

  # Provider-specific configuration
  config.providers.loops.transactional_id = "default-template"
  config.providers.mailgun.domain = "notifications.railsdesigner.com"
end

2. Email class defaults

class OrderEmail < Courrier::Email
  configure from: "orders@railsdesigner.com",
            cc: "records@railsdesigner.com",
            provider: "mailgun",
end

3. Instance options

OrderEmail.deliver to: "recipient@railsdesigner.com",\
                   from: "shop@railsdesigner.com",\
                   provider: "sendgrid",\
                   api_key: "sk_a1b1c3"

Provider and API key settings can be overridden using environment variables (COURRIER_PROVIDER and COURRIER_API_KEY) for both global configuration and email class defaults.

Custom Attributes

Besides the standard email attributes (from, to, reply_to, etc.), you can pass any additional attributes that will be available in your email templates:

OrderEmail.deliver to: "recipient@railsdesigner.com",\
                   download_url: downloads_path(token: "token")

These custom attributes are accessible directly in your email class:

def text
  <<~TEXT
    #{download_url}
  TEXT
end

Result Object

When sending an email through Courrier, a Result object is returned that provides information about the delivery attempt. This object offers a simple interface to check the status and access response data.

Available Methods

Method Return Type Description
success? Boolean Returns true if the API request was successful
response Net::HTTPResponse The raw HTTP response from the email provider
data Hash Parsed JSON response body from the provider
error Exception Contains any error that occurred during delivery

Example

delivery = OrderEmail.deliver(to: "recipient@example.com")

if delivery.success?
  puts "Email sent successfully!"
  puts "Provider response: #{delivery.data}"
else
  puts "Failed to send email: #{delivery.error}"
end

Providers

Courrier supports these transactional email providers:

⚠️ A few providers still need manual verification of their implementation. If you’re using one of these providers, please help verify the implementation by sharing your experience in this GitHub issue. 🙏

More Features

Additional functionality to help with development and testing:

Inbox (Rails only)

You can preview your emails in the inbox:

config.provider = "inbox"

# And add to your routes:
mount Courrier::Engine => "/courrier"

If you want to automatically open every email in your default browser:

config.provider = "inbox"
config.inbox.auto_open = true

Emails are automatically cleared with bin/rails tmp:clear, or manually with bin/rails courrier:clear.

Layout Support

Wrap your email content using layouts:

class OrderEmail < Courrier::Email
 layout text: "%{content}\n\nThanks for your order!",
        html: "<div>\n%{content}\n</div>"
end

Using a method:

class OrderEmail < Courrier::Email
  layout html: :html_layout

  def html_layout
    <<~HTML
      <div style='font-family: ui-sans-serif, system-ui;'>
        %{content}
      </div>
    HTML
  end
end

Using a separate class:

class OrderEmail < Courrier::Email
  layout html: OrderLayout
end

class OrderLayout
  self.call
    <<~HTML
      <div style='font-family: ui-sans-serif, system-ui;'>
        %{content}
      </div>
    HTML
  end
end

Auto-generate Text from HTML

Automatically generate plain text versions from your HTML emails:

config.auto_generate_text = true # Defaults to false

Email Address Helper

Compose email addresses with display names:

class SignupsController < ApplicationController
  def create
    recipient = email_with_name("devs@railsdesigner.com", "Rails Designer Devs")

    WelcomeEmail.deliver to: recipient
  end
end

In Plain Ruby Objects:

class Signup
  include Courrier::Email::Address

  def send_welcome_email(user)
    recipient = email_with_name(user.email_address, user.name)

    WelcomeEmail.deliver to: recipient
  end
end

Logger Provider

Use Ruby’s built-in Logger for development and testing:

config.provider = "logger" # Outputs emails to STDOUT
config.logger = custom_logger # Optional: defaults to ::Logger.new($stdout)

Custom Providers

Create your own provider by inheriting from Courrier::Email::Providers::Base:

class CustomProvider < Courrier::Email::Providers::Base
  ENDPOINT_URL = ""

  def body = ""

  def headers = ""
end

Then configure it:

config.provider = "CustomProvider"

Check the existing providers for implementation examples.

FAQ

Is this a replacement for ActionMailer?

Yes! While different in approach, Courrier can fully replace ActionMailer. It’s a modern alternative that focuses on API-based delivery. The main difference is in how emails are structured - Courrier uses a more straightforward, class-based approach.

Is this for Rails only?

Not at all! While Courrier has some Rails-specific goodies (like the inbox preview feature and generators), it works great with any Ruby application.

Can it send using SMTP?

No - Courrier is specifically built for API-based email delivery. If SMTP is needed, ActionMailer would be a better choices.

Can separate view templates be created (like ActionMailer)?

The approach is different here. Instead of separate view files, email content is defined right in the email class using text and html methods. Layouts can be used to share common HTML or text. This makes emails more self-contained and easier to reason about.

What’s the main benefit over ActionMailer?

Courrier offers a simpler, more modern approach to sending emails. Each email is a standalone class, configuration is straightforward (typically just an API key is needed) and being API-based allows you to utilize their features (e.g. setting a template) without any extra work. Also it packs few quality-of-life features (like the inbox feature and auto-generate text versions).