Skip to content

Commit

Permalink
Cleanup and clarify documentation (#468)
Browse files Browse the repository at this point in the history
While reading through Bamboo's source code, there were a few places in
the documentation I found that could be clearer or had minor typos. This
commit aims to clarify some of the documentation and fix minor typos
here and there.
  • Loading branch information
lancejjohnson committed Apr 2, 2019
1 parent 494ba3a commit 89845a8
Show file tree
Hide file tree
Showing 14 changed files with 182 additions and 132 deletions.
16 changes: 8 additions & 8 deletions lib/bamboo/adapter.ex
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ defmodule Bamboo.Adapter do
@moduledoc ~S"""
Behaviour for creating Bamboo adapters
All recipients in the Bamboo.Email struct will be normalized to a 2 item tuple
of {name, address} when deliver through your mailer. For example,
`email.from |> elem(0)` would return the name and `email.from |> elem(1)`
would return the email address.
All recipients in the `Bamboo.Email` struct will be normalized to a two item
tuple of `{name, address}` when delivered through your mailer. For example,
`elem(email.from, 0)` would return the name and `elem(email.from, 1)` would
return the email address.
For more in-depth examples check out the
[adapters in Bamboo](https://github.com/paulcsmith/bamboo/tree/master/lib/bamboo/adapters).
[adapters in Bamboo](https://github.com/thoughtbot/bamboo/tree/master/lib/bamboo/adapters).
## Example
Expand All @@ -27,11 +27,11 @@ defmodule Bamboo.Adapter do
if Map.get(config, :smtp_username) do
config
else
raise "smtp_username is required in config, got #{inspect config}"
raise "smtp_username is required in config, got #{inspect(config)}"
end
end
def supports_attachments?, do: true
def supports_attachments?, do: true
end
"""

Expand Down
18 changes: 9 additions & 9 deletions lib/bamboo/adapters/local_adapter.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@ defmodule Bamboo.LocalAdapter do
Stores emails locally. Can be queried to see sent emails.
Use this adapter for storing emails locally instead of sending them. Emails
are stored and can be read from `Bamboo.SentEmail`.
Typically this adapter is used in the dev environment so emails are not
delivered to real email addresses.
are stored and can be read from `Bamboo.SentEmail`. Typically this adapter is
used in the dev environment so emails are not delivered to real email
addresses.
You can use this adapter along with `Bamboo.SentEmailViewerPlug` to view emails
in the browser.
You can use this adapter along with `Bamboo.SentEmailViewerPlug` to view
emails in the browser.
If you want to open a new browser window for every new email, set the
option `open_email_in_browser_url` to your preview path.
If you want to open a new browser window for every new email, set the option
`open_email_in_browser_url` to your preview path.
## Example config
Expand All @@ -30,13 +30,13 @@ defmodule Bamboo.LocalAdapter do

@behaviour Bamboo.Adapter

@doc "Adds email to Bamboo.SentEmail and opens it in new browser tab"
@doc "Adds email to `Bamboo.SentEmail` and opens it in new browser tab"
def deliver(email, %{open_email_in_browser_url: open_email_in_browser_url}) do
%{private: %{local_adapter_id: local_adapter_id}} = SentEmail.push(email)
open_url_in_browser("#{open_email_in_browser_url}/#{local_adapter_id}")
end

@doc "Adds email to Bamboo.SentEmail"
@doc "Adds email to `Bamboo.SentEmail`"
def deliver(email, _config) do
SentEmail.push(email)
end
Expand Down
11 changes: 6 additions & 5 deletions lib/bamboo/adapters/mandrill_helper.ex
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
defmodule Bamboo.MandrillHelper do
@moduledoc """
Functions for using features specific to Mandrill e.g. tagging, merge vars, templates
Functions for using features specific to Mandrill (e.g. tagging, merge vars,
templates).
"""

alias Bamboo.Email

@doc """
Put extra message parameters that are used by Mandrill
Put extra message parameters that are used by Mandrill.
Parameters set with this function are sent to Mandrill when used along with
the Bamboo.MandrillAdapter. You can set things like `important`, `merge_vars`,
and whatever else you need that the Mandrill API supports.
the `Bamboo.MandrillAdapter`. You can set things like `important`,
`merge_vars`, and whatever else you need that the Mandrill API supports.
## Example
Expand All @@ -37,7 +38,7 @@ defmodule Bamboo.MandrillHelper do
end

@doc """
Set merge_vars that are used by Mandrill
Set merge_vars that are used by Mandrill.
## Example
Expand Down
2 changes: 1 addition & 1 deletion lib/bamboo/adapters/test_adapter.ex
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
defmodule Bamboo.TestAdapter do
@moduledoc """
Used for testing email delivery
Used for testing email delivery.
No emails are sent, instead a message is sent to the current process and can
be asserted on with helpers from `Bamboo.Test`.
Expand Down
48 changes: 28 additions & 20 deletions lib/bamboo/email.ex
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,19 @@ defmodule Bamboo.Email do
@moduledoc """
Contains functions for composing emails.
Bamboo separates composing emails from delivering them. This separation makes emails
easy to test and makes things like using a default layout, or a default from
address easy to do. This module is for creating emails. To actually send them,
use [Bamboo.Mailer](Bamboo.Mailer.html).
Bamboo separates composing emails from delivering them. This separation makes
emails easy to test and makes things like using a default layout or a default
from address easy to do. This module is for creating emails. To actually send
them, use [Bamboo.Mailer](Bamboo.Mailer.html).
## Handling email addresses
The from, to, cc and bcc addresses accept a string, a 2 item tuple
{name, address}, or anything else that you create that implements the
[Bamboo.Formatter](Bamboo.Formatter.html) protocol. The to, cc and bcc fields
can also accepts a *list* of any combination of strings, 2 item tuples or
anything that implements the Bamboo.Formatter protocol. See
The from, to, cc, and bcc addresses of a `Bamboo.Email` can be set to any
data structure for which there is an implementation of the
[Bamboo.Formatter](Bamboo.Formatter.html) protocol or a list of such data
structures. Bamboo includes implementations for some common data structures
or you can create your own. All from, to, cc, and bcc addresses are
normalized internally to a two item tuple of `{name, address}`. See
[Bamboo.Formatter](Bamboo.Formatter.html) for more info.
## Simplest way to create a new email
Expand Down Expand Up @@ -42,24 +43,31 @@ defmodule Bamboo.Email do
def welcome_email(user) do
# Since new_email/1 returns a struct you can update it with Kernel.struct!/2
struct!(base_email,
struct!(base_email(),
to: user,
subject: "Welcome!",
text_body: "Welcome to the app",
html_body: "<strong>Welcome to the app</strong>"
)
end
def base_email do
new_email(from: "me@app.com")
end
end
# or you can use functions to build it up step by step
base_email
In addition to keyword lists, `Bamboo.Email`s can also be built using function pipelines.
defmodule MyApp.Email do
import Bamboo.Email
def welcome_email(user) do
base_email()
|> to(user)
|> subject("Welcome!")
|> text_body("Welcome to the app")
|> html_body("<strong>Welcome to the app</strong>")
end
def base_email do
new_email(from: "me@app.com")
end
end
"""

Expand Down Expand Up @@ -116,10 +124,10 @@ defmodule Bamboo.Email do
@doc """
Sets the `#{function_name}` on the email.
You can pass in a string, list of strings,
or anything that implements the `Bamboo.Formatter` protocol.
`#{function_name}` receives as an argument any data structure for which
there is an implementation of the [`Bamboo.Formatter`](Bamboo.Formatter.html) protocol.
new_email
new_email()
|> #{function_name}(["sally@example.com", "james@example.com"])
"""
@spec unquote(function_name)(__MODULE__.t(), address_list) :: __MODULE__.t()
Expand Down Expand Up @@ -209,7 +217,7 @@ defmodule Bamboo.Email do
put_attachment(email, %Bamboo.Attachment{})
Requires the fields filename and data of the %Bamboo.Attachment{} struct to be set.
Requires the fields filename and data of the `%Bamboo.Attachment{}` struct to be set.
## Example
Expand Down
20 changes: 12 additions & 8 deletions lib/bamboo/formatter.ex
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ defprotocol Bamboo.Formatter do
@moduledoc ~S"""
Converts data to email addresses.
The passed in options is currently a map with the key `:type` and a value of
`:from`, `:to`, `:cc` or `:bcc`. This makes it so that you can pattern match
and return a different address depending on if the address is being used in
the from, to, cc or bcc.
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
Expand All @@ -15,7 +17,7 @@ defprotocol Bamboo.Formatter do
defstruct first_name: nil, last_name: nil, email: nil
end
Bamboo can automatically format this struct if you implement the Bamboo.Formatter
Bamboo can automatically format this struct if you implement the `Bamboo.Formatter`
protocol.
defimpl Bamboo.Formatter, for: MyApp.User do
Expand All @@ -33,8 +35,10 @@ defprotocol Bamboo.Formatter do
## Customize formatting based on from, to, cc or bcc
This can be helpful if you want to add the name of the app when sending on
behalf of a user.
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
Expand All @@ -52,7 +56,7 @@ defprotocol Bamboo.Formatter do
"""

@doc ~S"""
Receives data and opts and should return a string or a 2 item tuple {name, address}
Receives data and opts and returns a string or a two item tuple `{name, address}`
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
Expand Down
73 changes: 37 additions & 36 deletions lib/bamboo/mailer.ex
Original file line number Diff line number Diff line change
@@ -1,55 +1,56 @@
defmodule Bamboo.Mailer do
@moduledoc """
Sets up mailers that make it easy to configure and swap adapters.
Functions for delivering emails using adapters and delivery strategies.
Adds `deliver_now/1` and `deliver_later/1` functions to the mailer module it is used by.
Adds `deliver_now/1` and `deliver_later/1` functions to the mailer module it
is used by.
## Bamboo ships with the following adapters
Bamboo [ships with several adapters][available-adapters]. It is also possible
to create your own adapter.
* `Bamboo.MandrillAdapter`
* `Bamboo.LocalAdapter`
* `Bamboo.TestAdapter`
* or create your own with `Bamboo.Adapter`
See the ["Getting Started" section of the README][getting-started] for an
example of how to set up and configure a mailer for use.
[available-adapters]: https://github.com/thoughtbot/bamboo/tree/master/lib/bamboo/adapters
[getting-started]: https://hexdocs.pm/bamboo/readme.html#getting-started
## Example
# In your config/config.exs file
config :my_app, MyApp.Mailer,
adapter: Bamboo.MandrillAdapter,
api_key: "my_api_key"
Creating a Mailer is as simple as defining a module in your application and
using the `Bamboo.Mailer`.
# Somewhere in your application. Maybe lib/my_app/mailer.ex
# some/path/within/your/app/mailer.ex
defmodule MyApp.Mailer do
# Adds deliver_now/1 and deliver_later/1
use Bamboo.Mailer, otp_app: :my_app
end
# Set up your emails
The mailer requires some configuration within your application.
# config/config.exs
config :my_app, MyApp.Mailer,
adapter: Bamboo.MandrillAdapter, # Specify your preferred adapter
api_key: "my_api_key" # Specify adapter-specific configuration
Also you will want to define an email module for building email structs that
your mailer can send. See [`Bamboo.Email`] for more information.
# some/path/within/your/app/email.ex
defmodule MyApp.Email do
import Bamboo.Email
def welcome_email do
new_mail(
to: "foo@example.com",
from: "me@example.com",
subject: "Welcome!!!",
html_body: "<strong>WELCOME</strong>",
text_body: "WELCOME"
new_email(
to: "john@example.com",
from: "support@myapp.com",
subject: "Welcome to the app.",
html_body: "<strong>Thanks for joining!</strong>",
text_body: "Thanks for joining!"
)
end
end
# In a Phoenix controller or some other module
defmodule MyApp.Foo do
alias MyApp.Email
alias MyApp.Mailer
def register_user do
# Create a user and whatever else is needed
# Could also have called Mailer.deliver_later
Email.welcome_email |> Mailer.deliver_now
end
end
You are now able to send emails with your mailer module where you sit fit
within your application.
"""

@cannot_call_directly_error """
Expand Down Expand Up @@ -90,17 +91,17 @@ defmodule Bamboo.Mailer do
end

@doc """
Deliver an email right away
Deliver an email right away.
Call your mailer with `deliver_now/1` to send an email right away. Call
`deliver_later/1` if you want to send in the background to speed things up.
`deliver_later/1` if you want to send in the background.
"""
def deliver_now(_email) do
raise @cannot_call_directly_error
end

@doc """
Deliver an email in the background
Deliver an email in the background.
Call your mailer with `deliver_later/1` to send an email using the configured
`deliver_later_strategy`. If no `deliver_later_strategy` is set,
Expand Down Expand Up @@ -215,8 +216,8 @@ defmodule Bamboo.Mailer do
@doc """
Wraps to, cc and bcc addresses in a list and normalizes email addresses.
Also formats the from address. Email normalization/formatting is done by the
[Bamboo.Formatter] protocol.
Also formats the from address. Email normalization/formatting is done by
implementations of the [Bamboo.Formatter] protocol.
"""
def normalize_addresses(email) do
%{
Expand Down
Loading

0 comments on commit 89845a8

Please sign in to comment.