# Phoenix

A Swoosh adapter, so every Phoenix mailer and email in the app goes through emails.sh.

Phoenix generates a Swoosh mailer for every new application. Point it at an adapter of yours and the emails your context modules already build go out through the API, with no other change.

### Configure

config/runtime.exs:
```text
# config/runtime.exs
# Read at boot, not compiled in. The key comes from
# https://emails.sh/dashboard/api-keys.
config :acme, Acme.Mailer,
  adapter: Acme.EmailsshAdapter,
  api_key: System.fetch_env!("EMAILSSH_API_KEY")
```

### The adapter

lib/acme/emailssh_adapter.ex:
```text
# lib/acme/emailssh_adapter.ex
defmodule Acme.EmailsshAdapter do
  @moduledoc "Swoosh adapter for emails.sh."
  use Swoosh.Adapter, required_config: [:api_key]

  @endpoint "https://emails.sh/v1/emails"

  @impl true
  def deliver(%Swoosh.Email{} = email, config) do
    body =
      %{
        from: address(email.from),
        to: Enum.map(email.to, &elem(&1, 1)),
        subject: email.subject,
        html: email.html_body,
        text: email.text_body
      }
      |> maybe_put(:cc, Enum.map(email.cc || [], &elem(&1, 1)))
      |> maybe_put(:bcc, Enum.map(email.bcc || [], &elem(&1, 1)))
      |> Map.reject(fn {_k, v} -> is_nil(v) end)

    case Req.post(@endpoint, json: body, auth: {:bearer, config[:api_key]}, receive_timeout: 10_000) do
      {:ok, %{status: status, body: %{"id" => id}}} when status < 400 ->
        {:ok, %{id: id}}

      {:ok, %{body: %{"error" => %{"code" => code, "message" => message}}}} ->
        {:error, {code, message}}

      {:error, reason} ->
        {:error, reason}
    end
  end

  defp address({nil, addr}), do: addr
  defp address({name, addr}), do: "#{name} <#{addr}>"

  defp maybe_put(map, _key, []), do: map
  defp maybe_put(map, key, value), do: Map.put(map, key, value)
end
```

### Use it

lib/acme/accounts/user_notifier.ex:
```text
# lib/acme/accounts/user_notifier.ex, as generated by phx.gen.auth
defmodule Acme.Accounts.UserNotifier do
  import Swoosh.Email
  alias Acme.Mailer

  def deliver_confirmation_instructions(user, url) do
    new()
    |> to({user.name, user.email})
    |> from({"Acme", "hello@acme.com"})
    |> subject("Confirm your Acme account")
    |> html_body("<p>Confirm your account: <a href=\"#{url}\">#{url}</a></p>")
    |> text_body("Confirm your account: #{url}")
    |> Mailer.deliver()
  end
end
```

Leave Swoosh.Adapters.Test configured in config/test.exs. assert_email_sent keeps working and the test suite sends nothing.

---

Base URL: https://emails.sh/v1. Auth: `Authorization: Bearer esh_...`.
Whole API in one file: https://emails.sh/llms.txt. All documentation: https://emails.sh/docs.md.
