Providing HTML for Swoosh emails

almirsarajcic

almirsarajcic

Created 1 month ago

Phoenix comes out of the box with an email library called Swoosh. The user authentication generator creates a UserNotifier, which provides default emails, but only with plain text. If you want to include HTML, you’ll have to roll up your sleeves a bit.

Generate the user authentication code with mix phx.gen.auth command if you haven’t already. Then, make the following changes.

defmodule MyApp.Accounts.UserNotifier do
  use MyAppWeb, :html

  import MyAppWeb.EmailComponents

  defp deliver(recipient, subject, html, text) do
    html =
      html_escape()
      |> Phoenix.HTML.html_escape()
      |> Phoenix.HTML.safe_to_string()

    email =
      # ...
      |> html_body(html)

    # ...
  end

  # ...

  def deliver_confirmation_instructions(user, url) do
    assigns = %{url: url}

    email_body = ~H"""
    <.confirmation_instructions_email url={@url} />
    """

    deliver(user.email, "Confirmation instructions", email_body, "text body")
  end
end

Your lib/my_app_web/components/email_components.ex file needs to look like this:

defmodule MyAppWeb.EmailComponents do
  use MyAppWeb, :html

  def confirmation_instructions_email(assigns) do
    ~H"""
    <.layout>
      <h1>Confirmation instructions</h1>
      <p>
        Welcome to MyApp!
      </p>
      <p>
        You can confirm your account by visiting the URL below:
        <a href={@url}>{@url}</a>
      </p>
    </.layout>
    """
  end

  slot :inner_block

  defp layout(assigns) do
    ~H"""
    <html>
      <body>
        <%= render_slot(@inner_block) %>
      </body>
    </html>
    """
  end
end

Done. Kinda. You still have to do that for every email in your codebase, but this way the code duplication will be reduced to a minimum.