Subscribe to access all episodes. View plans →
Published May 8, 2017
Elixir 1.4
Phoenix 1.2.1
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.
Denis Klimenko
7 years agoI suppose it’s just for demo purposes to have repository manipulations inside controller. It’s not ok, are you agree?)
Alekx
7 years agoHey Denis, Thanks for the comment. I think putting that logic into some kind of ‘context’ would be a great idea.