Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updating docs on emails. #625

Merged
merged 1 commit into from
Apr 16, 2021
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
162 changes: 154 additions & 8 deletions src/actions/guides/emails/sending-emails-with-carbon.cr
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,23 @@ class Guides::Emails::SendingEmailsWithCarbon < GuideAction
<<-MD
## Configuring Email

Lucky leverages the [Carbon](https://github.com/luckyframework/carbon) library for writing, sending, and testing emails. Carbon can be configured using the default file generated with a new Lucky application in `config/email.cr`. In that file you can add SendGrid keys and change adapters.
Lucky leverages the [Carbon](https://github.com/luckyframework/carbon) library for writing, sending, and testing emails.
Carbon can be configured using the default file generated with a new Lucky application in `config/email.cr`. In that file
you can add SendGrid keys and change adapters.

## Adapters

Carbon supports a growing number of adapters thanks to contributions from the community.
Carbon supports a growing number of adapters thanks to contributions from the community. [View supported adapters](https://github.com/luckyframework/carbon#adapters)

> If you've built an adapter not listed, be sure to let us know!

### Dev Adapter

The `DevAdapter` ships with Carbon by default, and is useful for handling emails in a development or test environment. It can also be leveraged in production to effectively disable emails.
The `DevAdapter` ships with Carbon by default, and is useful for handling emails in a development or test environment.
It can also be leveraged in production to effectively disable emails.

There are two ways to leverage the `DevAdapter`. The first is by telling the adapter to simply capture all Carbon output without printing or displaying the email content, which is the default:
There are two ways to leverage the `DevAdapter`. The first is by telling the adapter to simply capture all Carbon output
without printing or displaying the email content, which is the default:

```crystal
# config/email.cr
Expand Down Expand Up @@ -50,12 +56,152 @@ class Guides::Emails::SendingEmailsWithCarbon < GuideAction
end
```

## Sending and testing emails
## Creating Emails

Emails are setup and configured through Crystal classes that live in your `src/emails/` directory. In that directory, you should already have a
`base_email.cr` file. This is the abstract class all of your email objects will inherit from. Use the `BaseEmail` for any defaults that
should be applied to all of your emails (e.g. `default_from` address, etc...)

The views (HTML) related to the emails will reside in the `src/emails/templates/{ NAME_OF_EMAIL }/` directory. For example, if your email file
is named `welcome_email.cr`, the templates for this will live in `src/emails/templates/welcome_email/`.

> You can also check out the `PasswordResetEmail` in the `src/emails/` directory of a newly generated auth project for a live example.

### Email templates

There are two basic templates for emails; HTML, and TEXT. The HTML template will be where you write the raw HTML for your email. The TEXT format
is used as a plain text (no HTML) email for devices and/or email apps that don't support HTML.

Place the templates inside of each specific email directory they belong to. Then name them `html.ecr`, and `text.ecr`. For example, if your email
file is named `welcome_email.cr`, your templates will be in `src/emails/templates/welcome_email/html.ecr` and `src/emails/templates/welcome_email/text.ecr`.

The email templates will use [ECR](https://crystal-lang.org/api/1.0.0/ECR.html) for interpolating Crystal code. All instance variables/methods defined in
your email class will be available within your template.

See the README at https://github.com/luckyframework/carbon
```html
<!-- src/emails/templates/welcome_email/html.ecr -->
<h1>Welcome, <%= @user.name %>!</h1>
<p>...</p>
<p>Secret token <%= @token %>.</p>
<p>Thanks, <%= email_signature %></p>
```

### Email class

In the `BaseEmail`, you can set defaults that will apply to all of your emails. This includes setting special email headers, `from` address,
or maybe helper methods you need to use in your email templates.

```crystal
# src/emails/base_email.cr
abstract class BaseEmail < Carbon::Email
macro inherited
from default_from
header "Return-Path", "[email protected]"
header "Message-ID", default_message_id
end

def default_from
Carbon::Address.new("[email protected]")
end

def default_message_id
digest = OpenSSL::Digest.new("SHA256")
digest.update(Time.utc.to_unix.to_s)
message_id = digest.final.hexstring

"<\#{message_id}@myapp.io>"
end

def email_signature : String
"The MyApp Crew"
end
end
```

```crystal
# src/emails/welcome_email.cr
class WelcomeEmail < BaseEmail

# Define your own initializer with the
# references it needs
def initializer(@user : User)
encryptor = Lucky::MessageEncryptor.new(secret: Lucky::Server.settings.secret_key_base)

# Instance variables defined are available in your templates
@token = encryptor.encrypt_and_sign("\#{@user.id}:\#{24.hours.from_now.to_unix_ms}")
end

to @user
subject "Welcome to MyApp.io!"
templates html, text
end
```

## Sending Emails

There's two strategies to sending emails; deliver now, or deliver later.

### Deliver email now

Once your email class is defined, you can call the `deliver` method to send now.

```crystal
WelcomeEmail.new(current_user).deliver
```

### Deliver email later

If you need to delay sending the email, call the `deliver_later` method to send later.

```crystal
WelcomeEmail.new(current_user).deliver_later
```

[read more](https://github.com/luckyframework/carbon#delay-email-delivery) on the `deliver_later` strategy.

## Testing Emails

Carbon comes with a few methods you can use in your specs to ensure emails are being sent. [read more](https://github.com/luckyframework/carbon#testing)

To configure testing your emails, you'll need to add `include Carbon::Expectations` in to `spec/spec_helper.cr`.
Then to make sure that emails are cleared between specs, you need to add `spec/setup/reset_emails.cr` with

```crystal
Spec.before_each do
Carbon::DevAdapter.reset
end
```

### be_delivered expectation

The `be_delivered` expectation is used to assert a specific email was delivered.

> This only checks that the `deliver` method was called. It does not account for API hanlding in other adapters.

```crystal
it "delivers the email" do
user = UserFactory.create &.email("[email protected]")
WelcomeEmail.new(user).deliver_now

# Test that this email was sent
WelcomeEmail.new(user).should be_delivered
end
```

### have_delivered_emails expectation

The `have_delivered_emails` is a bit more generic, and asserts that Carbon sent *any* email.

```crystal
it "delivers the email" do
user = UserFactory.create &.email("[email protected]")
WelcomeEmail.new(user).deliver_now

# Test that any email was sent
Carbon.should have_delivered_emails
end
```

You can also check out the `PasswordResetEmail` in the `src/emails` directory
of a newly generated project.
MD
end
end