• Stars
    star
    84
  • Rank 389,211 (Top 8 %)
  • Language
    Crystal
  • License
    MIT License
  • Created over 6 years ago
  • Updated 9 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

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

Carbon

API Documentation Website

Email library written in Crystal.

code preview

Installation

Add this to your application's shard.yml:

dependencies:
  carbon:
    github: luckyframework/carbon

Adapters

Usage

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 Carbon::Address.new("My App Name", "[email protected]")
  # Use a string if you just need the email address
  from "[email protected]"
end

Configure the mailer class

BaseEmail.configure do |settings|
  settings.adapter = Carbon::DevAdapter.new(print_emails: true)
end

Create a class for your email

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

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

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/emails/welcome_email.cr, then your templates would go in src/emails/templates/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>

For more information on what you can do with Embedded Crystal (ECR), see the official Crystal documentation.

Template layouts

Layouts are optional allowing you to specify how each email template looks individually. If you'd like to have the same layout on each, you can create a layout template in <folder_email_class_is_in>/templates/<layout_name>/layout.ecr

In this file, you'll yield the main email body with <%= content %>. Then in your BaseEmail, you can specify the name of the layout.

abstract class BaseEmail < Carbon::Email
  macro inherited
    from default_from
    layout :application_layout
  end
end
# in src/emails/templates/application_layout/layout.ecr

<h1>Our Email</h1>

<%= content %>

<div>footer</div>

Deliver the email

# Send the email right away!
WelcomeEmail.new("Kate", "[email protected]").deliver

# Send the email in the background using `spawn`
WelcomeEmail.new("Kate", "[email protected]").deliver_later

Delay email delivery

The built-in delay uses the deliver_later_strategy setting set to Carbon::SpawnStrategy. You can create your own custom delayed strategy that inherits from Carbon::DeliverLaterStrategy and defines a run method that takes a Carbon::Email and a block.

One example might be a job processor:

# Define your new delayed strategy
class SendEmailInJobStrategy < Carbon::DeliverLaterStrategy

  # `block.call` will run `deliver`, but you can call
  # `deliver` yourself on the `email` when you need.
  def run(email : Carbon::Email, &block)
    EmailJob.perform_later(email)
  end
end

class EmailJob < JobProcessor
  def perform(email : Carbon::Email)
    email.deliver
  end
end

# configure to use your new delayed strategy
BaseEmail.configure do |settings|
  settings.deliver_later_strategy = SendEmailInJobStrategy.new
end

Testing

Change the adapter

# In spec/spec_helper.cr or wherever you configure your code
BaseEmail.configure do
  # This adapter will capture all emails in memory
  settings.adapter = Carbon::DevAdapter.new
end

Reset emails before each spec and include expectations

# In spec/spec_helper.cr

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

Spec.before_each do
  Carbon::DevAdapter.reset
end

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)
  end

  def run
    sign_user_up
    WelcomeEmail.new(name: @name, email_address: @email_address).deliver
  end
end

it "sends an email after the user signs up" do
  SignUpUser.new(name: "Emily", email_address: "[email protected]").run

  # Test that this email was sent
  WelcomeEmail.new(name: "Emily", email_address: "[email protected]").should be_delivered
end

# or we can just check that some emails were sent
it "sends some emails" do
  SignUpUser.new(name: "Emily", email_address: "[email protected]").run

  Carbon.should have_delivered_emails
end

Unit testing

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

it "builds a nice welcome email" do
  email = WelcomeEmail.new(name: "David", email_address: "[email protected]")
  # 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.
  email.to.should eq [Carbon::Address.new("[email protected]")]
  email.text_body.should contain "Welcome"
  email.html_body.should contain "Welcome"
end

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.

Development

  • shards install
  • Make changes
  • ./script/test
  • ./bin/ameba

Contributing

  1. Fork it ( https://github.com/luckyframework/carbon/fork )
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Make your changes
  4. Run ./script/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

Contributors

More Repositories

1

lucky

A full-featured Crystal web framework that catches bugs for you, runs incredibly fast, and helps you write code that lasts.
Crystal
2,599
star
2

avram

A Crystal database wrapper for reading, writing, and migrating Postgres databases.
Crystal
164
star
3

lucky_cli

A Crystal command-line tool for generating new Lucky Web Applications.
Crystal
87
star
4

habitat

Easily configure settings for Crystal projects
Crystal
83
star
5

lucky_flow

Automated browser tests for web applications. Similar to Ruby's Capybara.
Crystal
51
star
6

lucky_record

Renamed to Avram ->> https://github.com/luckyframework/avram
Crystal
48
star
7

website

The Lucky website
Crystal
37
star
8

lucky_router

The router for the Lucky framework, can be used outside Lucky
Crystal
23
star
9

dexter

A logger with maximum customizability and surgical precision
Crystal
21
star
10

breeze

A development dashboard for Lucky Apps
Crystal
19
star
11

lucky_migrator

LuckyMigrator has been merged into LuckyRecord
Crystal
16
star
12

wordsmith

Handles pluralization, ordinalizing words, etc.
Crystal
14
star
13

authentic

An authentication library for Lucky projects
Crystal
14
star
14

pulsar

Pubsub and Instrumentation for Crystal
Crystal
14
star
15

avram_slugify

AvramSlugify generates slugs for database columns. These slugs can be used for creating nice looking URLs, permalinks, invite codes, etc.
Crystal
13
star
16

website-old

The old website for Lucky (archived)
HTML
11
star
17

carbon_smtp_adapter

An smtp adapter for the carbon email library
Crystal
10
star
18

html2lucky

Convert regular HTML into Lucky's Crystal DSL for HTML.
Crystal
10
star
19

lucky_inflector

This project has been moved to ->
Crystal
8
star
20

lucky_task

Library for creating command line tasks for the Lucky CLI
Crystal
7
star
21

lucky_cache

Caching library for the Lucky Framework
Crystal
5
star
22

lucky_env

An environment variable manager
Crystal
5
star
23

lucky_sec_tester

Crystal
4
star
24

homebrew-lucky

Ruby
3
star
25

teeplate

Fork of mosop/teeplate for generating files
Crystal
3
star
26

lucky_template

A simple, yet versatile, library for creating file and folder structures as code templates.
Crystal
3
star
27

lucky_hxml

Similar to LuckyHTML, but for Hyperview (https://hyperview.org/).
Crystal
2
star
28

upgrade-diffs

Diffs for easier upgrading of Lucky versions
Crystal
1
star
29

carbon_sendgrid_adapter

Crystal
1
star