Courrier
API-powered email delivery and newsletter subscription management for Ruby apps
# Quick example
class OrderEmail < Courrier::Email
def subject = "Here is your order!"
def text = "Thanks for ordering"
def html = "<p>Thanks for ordering</p>"
end
OrderEmail.deliver to: "recipient@railsdesigner.com"
# Manage newsletter subscriptions
Courrier::Subscriber.create "subscriber@example.com"Sponsored By Rails Designer
Installation
Add the gem:
bundle add courrierGenerate the configuration file:
bin/rails generate courrier:installThis creates config/initializers/courrier.rb for configuring email providers and default settings.
Usage
Generate a new email:
bin/rails generate courrier:email Orderclass 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):
- Global configuration
Courrier.configure do |config|
config.email = {
provider: "postmark",
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- Email class defaults
class OrderEmail < Courrier::Email
configure from: "orders@railsdesigner.com",
cc: "records@railsdesigner.com",
provider: "mailgun"
end- 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
endResult 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::HTTP::Response | 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}"
endProviders
Courrier supports these transactional email providers:
More Features
Additional functionality to help with development and testing:
Background jobs (Rails only)
Use deliver_later to enqueue delivering using Rails' ActiveJob. You can set
various ActiveJob-supported options in the email class, like so: enqueue queue: "emails", wait: 5.minutes.
-
queue, enqueue the email on the specified queue; -
wait, enqueue the email to be delivered with a delay; -
wait_until, enqueue the email to be delivered at (after) a specific date/time; -
priority, enqueues the email with the specified priority.
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 = trueEmails 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>"
endUsing 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
endUsing 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
endAuto-generate text from HTML
Automatically generate plain text versions from your HTML emails:
config.auto_generate_text = true # Defaults to falseEmail 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
endIn 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
endLogger 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 = ""
endThen configure it:
config.provider = "CustomProvider"Check the existing providers for implementation examples.
Newsletter subscriptions
Manage subscribers across popular email marketing platforms:
Courrier.configure do |config|
config.subscriber = {
provider: "buttondown",
api_key: "your_api_key"
}
end# Add a subscriber
subscriber = Courrier::Subscriber.create "subscriber@example.com"
# Remove a subscriber
subscriber = Courrier::Subscriber.destroy "subscriber@example.com"
if subscriber.success?
puts "Subscriber added!"
else
puts "Error: #{subscriber.error}"
endSupported providers
-
Beehiiv - requires
publication_id - Buttondown
-
Kit (formerly ConvertKit) - requires
form_id - Loops
-
Mailchimp - requires
dcandlist_id - MailerLite
Provider-specific configuration:
config.subscriber = {
provider: "mailchimp",
api_key: "your_api_key",
dc: "us19",
list_id: "abc123"
}Custom providers
Create custom providers by inheriting from Courrier::Subscriber::Base:
class CustomSubscriberProvider < Courrier::Subscriber::Base
ENDPOINT_URL = "https://api.example.com/subscribers"
def create(email)
request(:post, ENDPOINT_URL, {"email" => email})
end
def destroy(email)
request(:delete, "#{ENDPOINT_URL}/#{email}")
end
private
def headers
{
"Authorization" => "Bearer #{@api_key}",
"Content-Type" => "application/json"
}
end
endThen configure it:
config.subscriber = {
provider: CustomSubscriberProvider,
api_key: "your_api_key"
}See existing providers for more 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 templates. 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 only an API key is needed) and it packs few quality-of-life features (like the inbox feature and auto-generate text version).
Contributing
This project uses Standard for formatting Ruby code. Please make sure to run rake before submitting pull requests.
License
Courrier is released under the MIT License.
