DEV Community

Cover image for Salut Courrier! A New Ruby Gem to Send Emails
Rails Designer
Rails Designer

Posted on • Originally published at railsdesigner.com

2

Salut Courrier! A New Ruby Gem to Send Emails

This article was originally published on Rails Designer


Salut Courrier! 👋 📮

Courrier is a new Ruby gem for sending emails in your apps. You write a class containing the subject, HTML, and plain text content. It then uses the API from your choice of transactional email providers like Mailgun, Postmark, and Resend.

Go straight to GitHub and give it that star! ⭐

courrier /ku.ʁje/ noun, masculine

  1. mail, post (postal items)le courrier du matin - morning mail ▪ relever le courrier - to collect the mail
  2. letter, correspondencerépondre à un courrier - to reply to a letter ▪ courrier électronique - email
  3. messenger, courier (person)courrier diplomatique - diplomatic courier ▪ courrier à vélo - bike courier

Courrier is a gem extracted from my own (SaaS) apps. For years it lived as just one (😬) file in the app's lib folder. From my Rails UI consultancy work and helping people start a SaaS with Rails, it became clear the concept of Courrier was hitting a nerve. 💡

So how does it work? Create a class that inherits from Courrier::Email:

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
Enter fullscreen mode Exit fullscreen mode

You then send the email with:

OrderEmail.deliver to: "recipient@railsdesigner.com"
Enter fullscreen mode Exit fullscreen mode

Isn't that beautiful? ❤️

Need to pass on some contextual attributes? Use them in in your text or HTML, like so:

def text
  <<~TEXT
    #{download_url}
  TEXT
end
Enter fullscreen mode Exit fullscreen mode

And set them when delivering the email:

OrderEmail.deliver to: "recipient@railsdesigner.com",\
                   download_url: download_path(token: "token")
Enter fullscreen mode Exit fullscreen mode

How to Configure Courrier

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

Global Configuration

This is, typically in a Rails app, in config/initializer/courrier.rb

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

You can then override these settings per class:

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

Or even on an instance of the class:

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

If needed, you can quickly switch providers by setting the COURRIER_PROVIDER and COURRIER_API_KEY. You know, in case of emergencies. 🆘 😅

Consistent Results

Courrier returns a Result object that is consistent for each provider.

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
Enter fullscreen mode Exit fullscreen mode

The available methods on Result are:

  • success? — returns true if the API request was successful;
  • response — the raw HTTP response from the email provider;
  • data — parsed JSON response body from the provider;
  • error — contains any error that occurred during delivery.

But Courrier has quite a few more features to help you with development and testing. Let's go over them. 👇

Delivery to STDOUT

By default Courrier outputs all sent emails to STDOUT in development. It looks something like this:

--------------------------------------------------------------------------------
Timestamp: 2025-05-12 12:00:00 +0000
From:      Support Team <devs@railsdesigner.com>
To:        recipient@railsdesigner.com
Subject:   Here is your order!

Text:
text body here

HTML:

html body here
--------------------------------------------------------------------------------
Enter fullscreen mode Exit fullscreen mode

The Inbox (Rails only)

You can also preview sent emails using the inbox. Set the provider to inbox and mount the engine: mount Courrier::Engine => "/courrier".

Image description

If you prefer to view your emails in “in your face”, you can set also set config.inbox.auto_open = true. 👊 This will open a preview of the email in your default browser (just like the good-old letter_opener gem ❤️).

In Rails apps, the preview emails are stored in tmp/courrier/emails. This folder is cleared via a hook to bin/rails tmp:clear.

Layouts

The current set up of Courrier gently nudges you to keep emails simple and to-the-point. This is on purpose (or rather a nice side-effect). From my experience building, successful SaaS apps, basic emails tend to convert way better than complex HTML emails.

But if you need to prepend or append some text or HTML, you can do so using layouts. They work like this:

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

Here the plain text emails are appended with Thanks for your order! and the HTML content is wrapped with a <div />. Next to just strings, you can also pass a method as a symbol (layout html: :html_layout) or a callable class (layout html: OrderLayout).

Minimal Email Editor

Speaking of crafting emails: along with the Courrier gem, I built a minimal HTML Email Editor. Write your text in Markdown and you can copy a HTML and plain text version. Ready to paste into your Courrier email classes. 💪


Image description

There are even more features, like: Auto-generate Text from HTML and Email Address Helper. 🚀

The foundation of Courrier is really solid, but there are still a few small and bigger features I have noted down (emails being scoped like this might give something away already 🤓).

For now it would be awesome if you could help validate the currently supported providers (most are already done). See this GitHub issue for more.

Also don't forget to star it on GitHub before you give it a try. Looking forward to see your enhancements and the bugs you will find. 🎷🐛

Runner H image

An AI Agent That Handles Life, Not Just Work

From ordering flowers to booking your dinner — let Runner H turn your ideas into actions. No prompts, no hassle. Just outcomes.

Try for Free

Top comments (0)

Scale globally with MongoDB Atlas. Try free.

Scale globally with MongoDB Atlas. Try free.

MongoDB Atlas is the global, multi-cloud database for modern apps trusted by developers and enterprises to build, scale, and run cutting-edge applications, with automated scaling, built-in security, and 125+ cloud regions.

Learn More

👋 Kindness is contagious

Explore this insightful write-up embraced by the inclusive DEV Community. Tech enthusiasts of all skill levels can contribute insights and expand our shared knowledge.

Spreading a simple "thank you" uplifts creators—let them know your thoughts in the discussion below!

At DEV, collaborative learning fuels growth and forges stronger connections. If this piece resonated with you, a brief note of thanks goes a long way.

Okay