Current section
Files
Jump to
Current section
Files
lib/bamboo/sent_email.ex
defmodule Bamboo.SentEmail do
@moduledoc """
Used for storing and retrieving sent emails when used with `Bamboo.LocalAdapter`.
When emails are sent with the `Bamboo.LocalAdapter`, they are stored in
`Bamboo.SentEmail`. Use the functions in this module to store and retrieve the emails.
Remember to start the Bamboo app by adding it to the app list in `mix.exs` or
starting it with `Application.ensure_all_started(:bamboo)`
"""
use Agent
@id_length 16
defmodule DeliveriesError do
defexception [:message]
def exception(emails) do
message = """
SentEmail.one/1 expected to find one email, got #{Enum.count(emails)}:
#{email_list(emails)}
This function is used when you expect only one email to have been sent. If
you meant to send more than one email, you can call
SentEmail.all/0 to get all sent emails.
For example: SentEmail.all |> List.first
"""
%DeliveriesError{message: message}
end
defp email_list(emails) do
Enum.map_join(emails, "\n", &inspect/1)
end
end
defmodule NoDeliveriesError do
defexception [:message]
def exception(_) do
message = "expected to find one email, but got none."
%NoDeliveriesError{message: message}
end
end
@doc "Starts the SentEmail Agent"
def start_link(_opts) do
Agent.start_link(fn -> [] end, name: __MODULE__)
end
@doc """
Gets the email's id.
The email must be an email that was sent with `Bamboo.LocalAdapter` or added
via `Bamboo.SentEmail.push/1`, otherwise the id will not have been set.
"""
def get_id(%Bamboo.Email{private: %{local_adapter_id: id}}) do
id
end
def get_id(%Bamboo.Email{}) do
raise """
SentEmail.get_id/1 expected the email to have an id, but no id was present.
This is usually because the email was not sent with Bamboo.LocalAdapter
or wasn't pushed with SentEmail.push/1
"""
end
def get_id(email) do
raise "SentEmail.get_id/1 expected a %Bamboo.Email{}, instead got: #{inspect(email)}"
end
@doc """
Gets an email by id. Returns nil if it can't find a matching email.
"""
def get(id) do
do_get(id)
end
@doc """
Gets an email by id. Raises if it can't find one.
"""
def get!(id) do
do_get(id) || raise NoDeliveriesError, nil
end
defp do_get(id) do
Enum.find(all(), nil, fn email ->
email |> get_id() |> String.downcase() == String.downcase(id)
end)
end
@doc "Returns a list of all sent emails"
def all do
Agent.get(__MODULE__, fn emails -> emails end)
end
@doc """
Adds an email to the list of sent emails.
Adds an email to the beginning of the sent emails list. Also gives the email
an id that can be fetched with `Bamboo.SentEmail.get_id/1`.
"""
def push(email) do
email = put_rand_id(email)
Agent.update(__MODULE__, fn emails ->
[email | emails]
end)
email
end
defp put_rand_id(email) do
Bamboo.Email.put_private(email, :local_adapter_id, rand_id())
end
defp rand_id do
@id_length
|> :crypto.strong_rand_bytes()
|> Base.url_encode64()
|> binary_part(0, @id_length)
end
@doc """
Returns exactly one sent email. Raises if none, or more than one are found
Raises `NoDeliveriesError` if there are no emails. Raises `DeliveriesError` if
there are 2 or more emails.
"""
def one do
case all() do
[email] -> email
[] -> raise NoDeliveriesError
emails -> raise DeliveriesError, emails
end
end
@doc "Clears all sent emails"
def reset do
Agent.update(__MODULE__, fn _ ->
[]
end)
end
end