Skip to content

DockYard/courier

Repository files navigation

Courier Build Status

Mail delivery for Elixir

Courier is built and maintained by DockYard, contact us for expert Elixir and Phoenix consulting.

Courier is an OTP adapter-based mail delivery system for Elixir applications. It means serious business for sending emails.

It depends upon Mail for composing the message.

First create your mailer:

defmodule MyApp.Mailer do
  use Courier, otp_app: :my_app
end

After this we need to add the Courier Supervisor to your tree. For example, if you are using in a Phoenix app you can edit lib/my_app.ex

def start(_type, _args) do
  children = [
    supervisor(MyApp.Repo, []),
    supervisor(MyApp.Endpoint, []),

    # Mailer Supervisor
    supervisor(MyApp.Mailer, [])
  ]
end

Next set the default adapter in config/config.exs or config/{environment}.exs:

config :my_app, MyApp.Mailer,
  adapter: Courier.Adapters.SMTP,
  relay: "smtp.myserver.com",
  hostname: "my-mail-server",
  port: 2525,
  username: System.get_env("COURIER_USERNAME"),
  password: System.get_env("COURIER_PASSWORD")

More configuration options for each adapter is in the Adapters section.

Then you can compose and deliver the message:

Mail.build_multipart()
|> Mail.put_to("friend@example.com")
|> Mail.put_from("me@example.com")
|> Mail.put_subject("How are things?")
|> Mail.put_text("Let's meet for drinks!")
|> Mail.put_html("<p>Let's meet for drinks!</p>")
|> MyApp.Mailer.deliver()

Courier will deliver the message through the adapter that is configured.

Deliveries

All deliveries are pushed into a shceduler and sent out asynchronously. Let's learn how to customize this scheduler

Scheduling deliveries

By default if you do not specify a datetime to delivery at Courier will mark the message for immediate delivery. But let's say we want to schedule a specific datetime to send a message. You can do that with:

MyApp.Mailer.deliver(message, at: datetime)

The datetime variable should conform to either an Erlang calendar tuple {{year, month, day}, {hour, minute, second}}

Pooling

Courier will use a pool to rate limit the number of concurrent messages being sent. This is necessary if you are sending to services that hate their own rate limits. The default pool size is 10. If you'd like to change this default you can simply modify when configuring your mailer:

config :my_app, MyApp.Mailer,
  pool_size: 15

Read more about the Scheduler, configuring it, and using it.

Rendering with Phoenix Views

If you'd like to render the text or html parts with a Phoenix view you should use Courier.render/4

Mail.build_multipart()
|> Mail.put_to("friend@example.com")
|> Mail.put_from("me@example.com")
|> Mail.put_subject("How are things?")
|> Courier.render(MyApp.MailerView, "check_in.txt", user: user)
|> Courier.render(MyApp.MailerView, "check_in.html", user: user)
|> MyApp.Mailer.deliver()

Courier.render/4 will parse the template path to determine the expected content-type. For example, if your template is foobar.html the assumed content-type is text/html and Courier will render the template to a string and use Mail.put_html(message, rendered_template)

Adapters

Courier comes with some built-in adapters

Courier.Adapters.SMTP

The built-in SMTP adapter is implemented with gen_smtp

Options:

  • relay mail server host
  • port mail server port (defaults to 25 when ssl is false, defaults to 465 when ssl is true)
  • ssl connect with SSL (defaults to false)
  • hostname label for the relay
  • username username used for authentication
  • password password used for authentication

Courier.Adapters.Logger

Will write deliver all messages to the Logger. All attachment encoded data will render as [File content]

Options:

  • level the Logger level to send the message to (defaults to :info)

Courier.Adapters.Test

Exposes the ETS adapter from a REST based API

Courier.Adapters.Web

CourierWeb adds a web interface for viewing the messages sent. To use it add the library to your mix.exs file. For more information on this adapter please refer to CourierWeb

Writing your own adapter

Creating your own adapter is simple. The only functions necessary are start_link/1 and deliver/2

defmodule MyApp.Adapters.Custom do
  def start_link(_opts), do: :ignore

  def deliver(%Mail.Message{} = message, opts) do
    # your customized mailer
  end
end

The message passed into deliver/2 is not a rendered RFC2822 message. If you need the rendered version you can use mail to render it:

rendered_message = Mail.render(message, Mail.Renderers.RFC2822)

Please refer to the mail library to learn more about creating custom message renderers.

Each adapter is treated as its own OTP supervisor within your mailer's supervisor tree. This will give you the opportunity to create more complex adapters with their own workers. Just override start_link/1 however you'd like. The configuration options declared for your mailer within the given mix environment are passed in as the argument.

Authors

We are very thankful for the many contributors

Versioning

This library follows Semantic Versioning

Looking for help with your Elixir project?

At DockYard we are ready to help you build your next Elixir project. We have a unique expertise in Elixir and Phoenix development that is unmatched. Get in touch!

At DockYard we love Elixir! You can read our Elixir blog posts or come visit us at The Boston Elixir Meetup that we organize.

Want to help?

Please do! We are always looking to improve this library. Please see our Contribution Guidelines on how to properly submit issues and pull requests.

Legal

DockYard, Inc. © 2016

@dockyard

Licensed under the MIT license

About

No description, website, or topics provided.

Resources

Code of conduct

Stars

Watchers

Forks

Packages

No packages published

Languages