Project

chain_mail

0.01
The project is in a healthy, maintained state
ChainMail provides a unified interface for sending transactional emails through multiple providers (SendGrid, Postmark, Mailgun, etc.) with automatic failover and Rails integration.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
 Dependencies

Runtime

>= 6.0
 Project Readme

ChainMail Logo

chain_mail

Coverage Status Ruby Build Status License: MIT RuboCop

chain_mail is a Ruby gem that ensures your transactional emails never fail by automatically switching between multiple email providers (SendGrid, Postmark, Mailgun, SES, etc.) when one fails to send. No more lost emails, no more manual intervention required.

Why chain_mail?

  • Zero Downtime: If one provider fails, emails automatically route to the next available provider
  • Easy Setup: Simple configuration with familiar Rails patterns
  • Multiple Providers: Built-in support for all major email services
  • Error Aggregation: Get detailed reports on any delivery issues

Installation

Add this line to your application's Gemfile:

gem 'chain_mail'

And then execute:

$ bundle install

Or install it yourself as:

$ gem install chain_mail

Usage

Rails Setup

Add a configuration initializer at config/initializers/chain_mail.rb:

ChainMail.configure do |config|
  config.providers = [
    { send_grid:  { api_key: ENV["SENDGRID_API_KEY"] } },
    { mailgun:    { domain: ENV["MAILGUN_DOMAIN"], api_key: ENV["MAILGUN_API_KEY"] } },
    # Add more providers as needed
  ]
end

Set the delivery method in your environment config (e.g. config/environments/production.rb):

config.action_mailer.delivery_method = :chain_mail

Send an email using ActionMailer:

class UserMailer < ApplicationMailer
  def welcome_email(user)
    mail(
      to: user.email,
      from: 'noreply@example.com',
      subject: 'Welcome!',
      body: 'Hello and welcome!'
    )
  end
end

Requirements

  • Ruby 3.0 or higher
  • Rails 6.0+ (for Rails integration)
  • Active email provider accounts (SendGrid, Postmark, etc.)

Architecture

  • Configuration: Set up providers and credentials in an initializer or before sending.
  • Delivery: Handles failover, input validation, and error aggregation.
  • Providers: Each adapter implements a standardized interface and error handling.

Supported Email Providers

chain_mail includes built-in support for the following email providers. Here's how to configure each one in your Rails initializer:

Amazon SES

ChainMail.configure do |config|
  config.providers = [
    { ses: {
        region: ENV["AWS_REGION"],
        access_key_id: ENV["AWS_ACCESS_KEY_ID"],
        secret_access_key: ENV["AWS_SECRET_ACCESS_KEY"]
      } }
  ]
end

Brevo (formerly Sendinblue)

ChainMail.configure do |config|
  config.providers = [
    { brevo: {
        api_key: ENV["BREVO_API_KEY"],
        sandbox: ENV["BREVO_SANDBOX"] == "true" # optional
      } }
  ]
end

Mailgun

ChainMail.configure do |config|
  config.providers = [
    { mailgun: {
        domain: ENV["MAILGUN_DOMAIN"],
        api_key: ENV["MAILGUN_API_KEY"]
      } }
  ]
end

OneSignal

ChainMail.configure do |config|
  config.providers = [
    { one_signal: { api_key: ENV["ONESIGNAL_API_KEY"] } }
  ]
end

Postmark

ChainMail.configure do |config|
  config.providers = [
    { postmark: { api_key: ENV["POSTMARK_API_KEY"] } }
  ]
end

SendGrid

ChainMail.configure do |config|
  config.providers = [
    { send_grid: { api_key: ENV["SENDGRID_API_KEY"] } }
  ]
end

SendPulse

ChainMail.configure do |config|
  config.providers = [
    { send_pulse: {
        client_id: ENV["SENDPULSE_CLIENT_ID"],
        client_secret: ENV["SENDPULSE_CLIENT_SECRET"]
      } }
  ]
end

Multiple Providers by Priority (send_grid -> mailgun -> ses)

ChainMail.configure do |config|
  config.providers = [
    { send_grid: { api_key: ENV["SENDGRID_API_KEY"]} },
    { mailgun: {
        domain: ENV["MAILGUN_DOMAIN"],
        api_key: ENV["MAILGUN_API_KEY"]
      } },
    { ses: {
        region: ENV["AWS_REGION"],
        access_key_id: ENV["AWS_ACCESS_KEY_ID"],
        secret_access_key: ENV["AWS_SECRET_ACCESS_KEY"]
      } }
  ]
end

Note: Always store API keys and credentials securely using environment variables. Providers are tried in the order listed - the first available provider will handle the email delivery.

Provider Priorities & Dynamic Configuration

  • Providers are tried in the order listed in config.providers.
  • You can register/unregister adapters at runtime:
ChainMail.register_provider(:custom, CustomProviderClass)
ChainMail.unregister_provider(:send_grid)
  • You can update provider priorities or credentials dynamically:
ChainMail.config.providers = [
  { custom: { api_key: "CUSTOM_API_KEY" } },
  { mailgun: { domain: "MAILGUN_DOMAIN", api_key: "MAILGUN_API_KEY" } }
]
  • API keys and credentials should be stored securely, e.g. using environment variables.

Star History

Star History Chart

Development

Check out the repo and start developing!

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/taltas/chain_mail.