Packages

Straightforward, powerful, and adapter based Elixir email library. Works with Mandrill, Mailgun, SendGrid, SparkPost, Postmark, in-memory, and test.

Retired package: Release invalid - invalid

Current section

Files

Jump to
dfbamboo lib bamboo formatter.ex
Raw

lib/bamboo/formatter.ex

defprotocol Bamboo.Formatter do
@moduledoc ~S"""
Converts data to email addresses.
Implementations of the `Bamboo.Formatter` protocol convert a given data
structure to a two item tuple of `{name, address}` or an address string. The
`opts` argument is a map with the key `:type` and a value of `:from`, `:to`,
`:cc`, or `:bcc`. The options argument allows functions to pattern match an
address type and format a given data structure differently for different
types of addresses.
## Simple example
Let's say you have a user struct like this.
defmodule MyApp.User do
defstruct first_name: nil, last_name: nil, email: nil
end
Bamboo can automatically format this struct if you implement the `Bamboo.Formatter`
protocol.
defimpl Bamboo.Formatter, for: MyApp.User do
# Used by `to`, `bcc`, `cc` and `from`
def format_email_address(user, _opts) do
fullname = "#{user.first_name} #{user.last_name}"
{fullname, user.email}
end
end
Now you can create emails like this, and the user will be formatted correctly
user = %User{first_name: "John", last_name: "Doe", email: "me@example.com"}
Bamboo.Email.new_email(from: user)
## Customize formatting based on from, to, cc or bcc
By pattern matching the `opts` argument, you can format a given data
structure differently for different types of addresses. For example, if you
want to provide the name of the app when sending email on behalf of a user,
you can format the name for all `type: :from` addresses.
defimpl Bamboo.Formatter, for: MyApp.User do
# Include the app name when used in a from address
def format_email_address(user, %{type: :from}) do
fullname = "#{user.first_name} #{user.last_name}"
{fullname <> " (Sent from MyApp)", user.email}
end
# Just use the name for all other types
def format_email_address(user, _opts) do
fullname = "#{user.first_name} #{user.last_name}"
{fullname, user.email}
end
end
"""
@doc ~S"""
Receives data and opts and returns a string, a two item tuple `{name, address}`, or a list of either.
opts is a map with the key `:type` and a value of
`:from`, `:to`, `:cc` or `:bcc`. You can pattern match on this to customize
the address.
"""
@type opts :: %{optional(:type) => :from | :to | :cc | :bcc}
@spec format_email_address(any, opts) :: Bamboo.Email.address_list()
def format_email_address(data, opts)
end
defimpl Bamboo.Formatter, for: List do
def format_email_address(email_addresses, opts) do
email_addresses |> Enum.map(&Bamboo.Formatter.format_email_address(&1, opts))
end
end
defimpl Bamboo.Formatter, for: BitString do
def format_email_address(email_address, _opts) do
{nil, email_address}
end
end
defimpl Bamboo.Formatter, for: Tuple do
def format_email_address(already_formatted_email, _opts) do
already_formatted_email
end
end
defimpl Bamboo.Formatter, for: Map do
def format_email_address(invalid_address, _opts) do
raise ArgumentError, """
The format of the address was invalid. Got #{inspect(invalid_address)}.
Expected a string, e.g. "foo@bar.com", a 2 item tuple {name, address}, or
something that implements the Bamboo.Formatter protocol.
Example:
defimpl Bamboo.Formatter, for: MyApp.User do
def format_email_address(user, _opts) do
{user.name, user.email}
end
end
"""
end
end