Current section
Files
Jump to
Current section
Files
lib/courier.ex
defmodule Courier do
use GenServer
@moduledoc """
This module is `use`ed by your custom mailer.
## Example:
defmodule MyApp.Mailer do
use Courier, otp_app: :my_app
end
"""
defmacro __using__(opts) do
{_otp_app, adapter, config} = parse_config(__CALLER__.module, opts)
quote do
use Supervisor
import Courier
def start_link() do
Courier.start_link(__MODULE__, unquote(Macro.escape(config)))
end
def deliver(%Mail.Message{} = message, opts \\ []) do
opts =
Keyword.merge(unquote(Macro.escape(config)), opts)
|> Keyword.merge([adapter: __adapter__(), mailer: __MODULE__, sent_from: self()])
message
|> Mail.Message.put_header(:date, :calendar.universal_time())
|> Courier.Scheduler.deliver(opts)
end
def init(_), do: :ok
def __adapter__(),
do: unquote(Macro.escape(adapter))
end
end
@doc false
def start_link(mailer, config) do
Supervisor.start_link(__MODULE__, config, [name: mailer])
end
@doc false
def init(config) do
import Supervisor.Spec
Courier.Scheduler.children(config)
|> supervise(strategy: :one_for_all)
end
@doc false
def parse_config(mailer, opts) do
otp_app = Keyword.fetch!(opts, :otp_app)
config = Application.get_env(otp_app, mailer, [])
adapter = config[:adapter]
{otp_app, adapter, config}
end
@doc """
View rendering for mail parts
Based upon the `template` extension the mail will have the proper `content-type` added.
For example with the following:
Courier.render(mail, MailerView, "user.html")
`Courier` will use `Mail.put_html/2` once it has rendered the template.
"""
def render(%Mail.Message{} = message, view, template, assigns \\ []) do
body =
view.render(template, assigns)
|> case do
{:safe, iodata} -> IO.iodata_to_binary(iodata)
body when is_binary(body) -> body
end
case Path.extname(template) do
".html" -> Mail.put_html(message, body)
".txt" -> Mail.put_text(message, body)
end
end
end