Check out our new series - Moving to Elixir

×

#14: Sending Email with Bamboo Part 1

Elixir 1.4

Phoenix 1.2.1

Bamboo 0.8

Source code on GitHub


Here we have a movie app and it in we want to send an email notification every time a movie is deleted.

To do this we’ll use Bamboo , an Elixir project maintained by Thoughtbot , that makes it easy to send emails.

We’ll get started by opening our project’s “Mixfile” and adding the “bamboo” dependency.

And then we’ll include “bamboo” in our applications list.

mix.exs

  def application do
    [mod: {Teacher, []},
     applications: [… :bamboo]]
  end

  defp deps do
       […
         {:bamboo, "~> 0.8"}
       ]
  end

Now let’ go to our “dev.exs” file and configure our application to use Bamboo.LocalAdapter in our development environment.

config/dev.exs

config :teacher, Teacher.Mailer,
  adapter: Bamboo.LocalAdapter

One great thing about using Bamboo.LocalAdapter is that we can view our sent emails in development with Bamboo.EmailPreviewPlug.

To use this we’ll open our router.

And we’ll forward the “/sent_emails” endpoint to the Bamboo.EmailPreviewPlug.

We also only want this in our development environment, so let wrap it in a conditional to only be included if our environment is dev.

web/router.ex

  if Mix.env == :dev do
    forward "/sent_emails", Bamboo.EmailPreviewPlug
  end

Great now let’s go to the command line and stop our sever and download our updated dependencies.

$ mix deps.get

Bamboo separates the composition of an email from its delivery. Let’s start by defining our “Mailer”, which is in charge of sending our email.

We’ll create a module in “/lib/teacher” named “mailer.ex”.

Now the only line in our module adds the ‘deliver’ functions we’ll use to send our emails and configures Bamboo to use the config we set for our app.

lib/teacher/mailer.ex

defmodule Teacher.Mailer do
  use Bamboo.Mailer, otp_app: :teacher
  
end

Now let’s create a module we can use to compose our emails. Let’s create another file in the same directory called “email.ex”. And in it we’ll import ‘Bamboo.Email’

Then let’s define a function named “movie_removal_email”, which we’ll use to compose our email.

In it we’re using the “new_email” function we get from importing “Bamboo.Email” above and then passing our email data into it. We’re including the “from”, “to”, “subject”, “text_body”, and “html_body”.

lib/teacher/email.ex

defmodule Teacher.Email do
  import Bamboo.Email

  def movie_removal_email do
    new_email(
      from: "no-reply@elixircasts.io",
      to: "hello@elixircasts.io",
      subject: "Movie Added",
      text_body: "A movie was added.",
      html_body: "A movie was added."
    )
  end
end

Great, now all we need to do is trigger our email.

Since we want ours to be sent when a movie is deleted, let’s open our “MovieController”module.

Then we’ll alias our new modules: “Mailer” and “Email”.

Now let’s create a private function named send_removal_notifcation. And in it we’ll call our Email.movie_removal_email() and pipe its result into the deliver function in the “Mailer” module we want to use.

There are two functions to choose from, deliver_now which will send our email immediately, but will also slow down our request.

And deliver_later which will send our email in the background, and does so without linking to the calling process. So if there’s a problem sending our email, our app will still work. We’ll use deliver_later.

Then we’ll call send_removal_notifcation from our delete function after the movie is deleted.

web/controllers/movie_controller.ex

defmodule Teacher.MovieController do
  use Teacher.Web, :controller

  alias Teacher.{Mailer, Email, Movie}
  …
  defp send_removal_notification do
    Email.movie_removal_email() |> Mailer.deliver_later()
  end

  def delete(conn, %{"id" => id}) do
    movie = Repo.get!(Movie, id)

    Repo.delete!(movie)
    send_removal_notification()
    …
  end
end

With that let’s go back to the command line and fire up our server.

$ mix phoenix.server

Then we’ll go to our browser and delete a movie.

Now if we check out development logs we can see that our email was sent with Bamboo. And since we set up the Bamboo.EmailPreviewPlug we can see what our sent email looks like.

Let’s go to the ‘/sent_emails’ route on our app and great, we see the email we sent is displayed. And here we can see the html version and the text version. One thing to keep in mind while testing is that restarting your server will remove the test emails displayed here.