View Source Swoosh.Gallery behaviour (swoosh_gallery v0.2.0)

Swoosh.Gallery is a library to preview and display your Swoosh mailers to everyone, either by exposing the previews on your application's router or publishing it on your favorite static host solution.

Getting Started

You will a gallery module to organize all your previews, and implement the expected callbacks on your mailer modules:

defmodule MyApp.Mailer.Gallery do
  use Swoosh.Gallery

  preview("/welcome", MyApp.Mailer.WelcomeMailer)
end

defmodule MyApp.Mailer.WelcomeMailer do
  # the expected Swoosh / Phoenix.Swoosh code that you already have to deliver emails
  use Phoenix.Swoosh, view: SampleWeb.WelcomeMailerView, layout: {MyApp.LayoutView, :email}

  def welcome(user) do
    new()
    |> from("noreply@sample.test")
    |> to({user.name, user.email})
    |> subject("Welcome to Sample App")
    |> render_body("welcome.html", user: user)
  end

  # `preview/0` function that builds your email using fixture data
  def preview do
    welcome(%{email: "user@sample.test", name: "Test User!"})
  end

  # `preview_details/0` with some useful metadata about your mailer
  def preview_details do
    [
      title: "Welcome to MyApp!",
      description: "First email to welcome users into the platform"
    ]
  end
end

Then in your router, you can mount your Gallery to expose it to the web:

forward "/gallery", MyApp.Mailer.Gallery

Or, you can generate static web pages with all the previews from your gallery:

mix swoosh.gallery.html --gallery MyApp.Mailer.Gallery --path "_build/emails"

By default, the previews will be sorted alphabetically. You can customize the sorting by implementing the sort/1 callback on your gallery module:

defmodule MyApp.Mailer.Gallery do
  use Swoosh.Gallery,
    sort: &MyApp.Mailer.Gallery.sort/1

  preview("/welcome", MyApp.Mailer.WelcomeMailer)
end

Or disable sorting by passing sort: false, so the previews will be displayed in the defined order in your Gallery.

 defmodule MyApp.Mailer.Gallery do
  use Swoosh.Gallery, sort: false
  ...
end

Generating preview data

Previews should be built using in memory fixture data and we do not recommend that you reuse your application's code to query for existing data or generate files during runtime. The preview/0 can be invoked multiple times as you navigate through your gallery on your browser when mounting it on the router or when using the swoosh.gallery.html task to generate the static pages.

defmodule MyApp.Mailer.SendContractEmail do
  def send_contract(user, blob) do
    contract =
      Swoosh.Attachment.new({:data, blob}, filename: "contract.pdf", content_type: "application/pdf")

    new()
    |> to({user.name, user.email})
    |> subject("Here is your Contract")
    |> attachment(contract)
    |> render_body(:contract, user: user)
  end

  # Bad - invokes application code to query data and generate the PDF contents
  def preview do
    user = MyApp.Users.find_user("testuser@acme.com")
    {:ok, blob} = MyApp.Contracts.build_contract(user)
    build(user, blob)
  end

  # Good - uses in memory structs and existing fixtures
  def preview do
    blob = File.read!("#{Application.app_dir(:my_app, "my_app")}/fixtures/sample.pdf")
    build(%User{}, blob)
  end
end

Summary

Callbacks

Sorts the previews. It receives a list of previews and should return a list of previews.

Functions

Defines a scope in which previews can be nested when rendered on your gallery. Each group needs a path and a :title option.

Declares a preview route. If expects that the module passed implements both preview/0 and preview_details/0.

Types

@type preview() :: %{
  :details_mfa => {module(), atom(), list()},
  optional(:email) => Swoosh.Email.t(),
  :email_mfa => {module(), atom(), list()},
  :group => String.t() | nil,
  :path => String.t(),
  optional(:preview_details) => map()
}

Callbacks

@callback sort([%{preview_details: map()}]) :: list()

Sorts the previews. It receives a list of previews and should return a list of previews.

Functions

Link to this macro

group(path, opts, list)

View Source (macro)

Defines a scope in which previews can be nested when rendered on your gallery. Each group needs a path and a :title option.

Example

defmodule MyApp.Mailer.Gallery do
  use Swoosh.Gallery

  group "/onboarding", title: "Onboarding Emails" do
    preview "/welcome", MyApp.Emails.Welcome
    preview "/account-confirmed", MyApp.Emails.AccountConfirmed
  end

  preview "/password-reset", MyApp.Emails.PasswordReset
end

Options

The supported options are:

  • :title - a string containing the group name.
Link to this macro

preview(path, module)

View Source (macro)
@spec preview(String.t(), module()) :: no_return()

Declares a preview route. If expects that the module passed implements both preview/0 and preview_details/0.

Examples

defmodule MyApp.Mailer.Gallery do
  use Swoosh.Gallery

  preview "/welcome", MyApp.Emails.Welcome
  preview "/account-confirmed", MyApp.Emails.AccountConfirmed
  preview "/password-reset", MyApp.Emails.PasswordReset

end