Shard Detail

carbon v0.1.2

Email library for Crystal. Testable, adapter-based, and catches bugs for you. Comes with an adapter for SendGrid.

Install & Use

Add the following code to your project's shard.yml under:

dependencies to use in production
- OR -
development_dependencies to use in development

  github: luckyframework/carbon



Email library written in Crystal.

code preview


Add this to your application's shard.yml:

    github: luckyframework/carbon



First, create a base class for your emails

require "carbon"

# You can setup defaults in this class
abstract class BaseEmail < Carbon::Email
  # For example, set up a default 'from' address
  from"My App Name", "")
  # Use a string if you just need the email address
  from ""

Configure the mailer class

BaseEmail.configure do
  settings.adapter = "SEND_GRID_API_KEY")

Create a class for your email

# Create an email class
class WelcomeEmail < BaseEmail
  def initialize(@name : String, @email_address : String)

  to @email_address
  subject "Welcome, #{@name}!"
  header "My-Custom-Header", "header-value"
  reply_to ""
  # You can also do just `text` or `html` if you don't want both
  templates text, html

Create templates

Templates go in the same folder the email is in:

  • Text email: <folder_email_class_is_in>/templates/<underscored_class_name>/text.ecr
  • HTML email: <folder_email_class_is_in>/templates/<underscored_class_name>/html.ecr

So if your email class is in src/my_app/emails/, then your templates would go in src/my_app/emails/welcome_email/text|html.ecr.

# in <folder_of_email_class>/templates/welcome_email/text.ecr
# Templates have access to instance variables and methods in the email.
Welcome, #{@name}!
# in <folder_of_email_class>/templates/welcome_email/html.ecr
<h1>Welcome, #{@name}!</h1>

Deliver the email

# Send the email right away!"Kate", "").deliver

# Send the email in the background using `spawn`"Kate", "").deliver_later


Change the adapter

# In spec/ or wherever you configure your code
BaseEmail.configure do
  # This adapter will capture all emails in memory
  settings.adapter =

Reset emails before each spec and include expectations

# In spec/

# This gives you the `be_delivered` expectation
include Carbon::Expectations

Spec.before_each do

Integration testing

# Let's say we have a class that signs the user up and sends the welcome email
# that was described at the beginning of the README
class SignUpUser
  def initialize(@name : String, @email_address : String)

  def run
    sign_user_up @name, email_address: @email_address).deliver_now

it "sends an email after the user signs up" do "Emily", email_address: "").run

  # Test that this email was sent "Emily", email_address: "").should be_delivered

Unit testing

Unit testing is simple. Instantiate your email and test the fields you care about.

it "builds a nice welcome email" do
  email = "David", email_address: "")
  # Note that recipients are converted to an array of Carbon::Address
  # So if you use a string value for the `to` field, you'll get an array of
  # Carbon::Address instead. eq ["")]
  email.text_body.should contain "Welcome"
  email.html_body.should contain "Welcome"

Note that unit testing can be superfluous in most cases. Instead, try unit testing just fields that have complex logic. The compiler will catch most other issues.


  • shards install
  • Make changes
  • crystal spec -D skip-integration (will skip sending test emails to SendGrid)
  • crystal spec requires a SEND_GRID_API_KEY ENV variable. Set this in a .env file:
# in .env
# If you want to run tests that actually test emails against the SendGrid server

Note: When you open a PR, Travis CI will run the test suite and try sending a sandboxed email through SendGrid. Feel free to open a PR to run integration tests if you don't want to get an API key from SendGrid.


  1. Fork it ( )
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Make your changes
  4. Run ./bin/test to run the specs, build shards, and check formatting
  5. Commit your changes (git commit -am 'Add some feature')
  6. Push to the branch (git push origin my-new-feature)
  7. Create a new Pull Request