Bamboo

Flexible and easy to use email for Elixir.

  • Adapter based so it can be used with Mandrill, SMTP, or whatever else you want. Comes with a Mandrill adapter out of the box.
  • Easy to format recipients. You can do new_email(to: Repo.one(User)) and Bamboo can format the User struct if you implement Bamboo.Formatter.
  • Works out of the box with Phoenix. Use views and layouts to make rendering email easy.
  • Very composable. Emails are just a Bamboo.Email struct and be manipulated with plain functions.
  • Easy to unit test. Because delivery is separated from email creation, no special functions are needed, just assert against fields on the email.
  • Easy to test delivery in integration tests. As little repeated code as possible.

See the docs for the most up to date information.

Adapters

The official Bamboo adapter is for Mandrill, but there are other adapters as well.

The Bamboo.MandrillAdapter is being used in production and is known to work. Refer to the other adapters README’s for their status and for installation instructions.

Basic Usage

Bamboo breaks email creation and email sending into two separate modules. This is done to make testing easier and to make emails easy to pipe/compose.

# In your config/config.exs file
config :my_app, MyApp.Mailer,
  adapter: Bamboo.MandrillAdapter,
  api_key: "my_api_key"

# Somewhere in your application
defmodule MyApp.Mailer do
  use Bamboo.Mailer, otp_app: :my_app
end

# Define your emails
defmodule MyApp.Emails do
  import Bamboo.Email

  def welcome_email do
    new_email(
      to: "foo@example.com",
      from: "me@example.com",
      subject: "Welcome!!!",
      html_body: "<strong>Welcome</strong>",
      text_body: "welcome"
    )
  end
end

# In a controller or some other module
Emails.welcome_email |> Mailer.deliver

# You can also deliver emails in the background with Mailer.deliver_later
Emails.welcome_email |> Mailer.deliver_later

Delivering Emails in the Background

By default delivering later uses Bamboo.TaskSupervisorStrategy, but you can deliver in the background however you want. See Bamboo.DeliverLaterStrategy.

Composing with Pipes. (Useful for default from address, default layouts, etc.)

defmodule MyApp.Emails do
  import Bamboo.Email

  def welcome_email do
    base_email
    |> to("foo@bar.com")
    |> subject("Welcome!!!")
    |> put_header("Reply-To", "someone@example.com")
    |> html_body("<strong>Welcome</strong>")
    |> text_body("Welcome")
  end

  defp base_email do
    # Here you can set a default from, default headers, etc.
    new_email
    |> from("myapp@example.com")
    |> put_html_layout({MyApp.LayoutView, "email.html"})
    |> put_text_layout({MyApp.LayoutView, "text.html"})
  end
end

Handling Recipients

The from, to, cc and bcc addresses can be passed a string, a 2 item tuple or anything that implements the Bamboo.Formatter protocol. See the Bamboo.Email docs for more info and examples.

Using Phoenix Views and Layouts

You can use Phoenix views and layouts with Bamboo. See Bamboo.Phoenix

Mandrill Specific Functionality (tags, merge vars, etc.)

See Bamboo.MandrillEmail

Testing

You can use the Bamboo.TestAdapter to make testing your emails a piece of cake. See documentation for Bamboo.Test for more examples.

Installation

To use the latest from master.

  1. Add bamboo to your list of dependencies in mix.exs:

        def deps do
          [{:bamboo, github: "paulcsmith/bamboo"}]
        end
        ```
    
  2. Ensure bamboo is started before your application:

        def application do
          [applications: [:bamboo]]
        end
        ```
    
  3. Add the the Bamboo.TaskSupervior as a child to your supervisor
  # Usually in lib/my_app_name/my_app_name.ex
  def start(_type, _args) do
    import Supervisor.Spec

    children = [
      # Add the supervisor that handles deliver_later calls
      Bamboo.TaskSupervisorStrategy.child_spec
    ]

    # This part is usually already there.
    opts = [strategy: :one_for_one, name: MyApp.Supervisor]
    Supervisor.start_link(children, opts)
  end