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

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, correspondence โ–ช rรฉ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: "[email protected]"
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: "[email protected]",\
                   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 = "[email protected]"
  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: "[email protected]",
            cc: "[email protected]",
            provider: "mailgun",
end
Enter fullscreen mode Exit fullscreen mode

Or even on an instance of the class:

OrderEmail.deliver to: "[email protected]",\
                   from: "[email protected]",\
                   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: "[email protected]"

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 <[email protected]>
To:        [email protected]
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. ๐ŸŽท๐Ÿ›

Top comments (0)