Packages
swoosh
1.6.4
1.26.3
1.26.2
1.26.1
1.26.0
1.25.3
1.25.2
1.25.1
1.25.0
1.24.0
1.23.1
1.23.0
1.22.1
1.22.0
1.21.0
1.20.1
1.20.0
1.19.9
1.19.8
1.19.7
1.19.6
1.19.5
1.19.4
1.19.3
1.19.2
1.19.1
1.19.0
1.18.4
1.18.3
1.18.2
1.18.1
1.18.0
1.17.10
1.17.9
1.17.8
retired
1.17.7
retired
1.17.6
1.17.5
1.17.4
retired
1.17.3
1.17.2
1.17.1
1.17.0
1.16.12
1.16.11
1.16.10
1.16.9
1.16.8
1.16.7
1.16.6
1.16.5
1.16.4
1.16.3
1.16.2
retired
1.16.1
retired
1.16.0
1.15.3
1.15.2
1.15.1
1.15.0
1.14.4
1.14.3
1.14.2
1.14.1
1.14.0
1.13.0
1.12.0
1.11.6
1.11.5
1.11.4
1.11.3
1.11.2
1.11.1
retired
1.11.0
1.10.3
1.10.2
1.10.1
1.10.0
1.9.1
1.9.0
1.8.3
1.8.2
1.8.1
1.8.0
1.7.5
1.7.4
1.7.3
1.7.2
1.7.1
1.7.0
1.6.6
1.6.5
1.6.4
1.6.3
1.6.2
1.6.1
1.6.0
1.5.2
1.5.1
1.5.0
1.4.0
1.3.11
1.3.10
1.3.9
1.3.8
retired
1.3.7
1.3.6
retired
1.3.5
1.3.4
1.3.3
1.3.2
1.3.1
1.3.0
1.2.2
1.2.1
1.2.0
1.1.2
1.1.1
1.1.0
1.0.9
1.0.8
retired
1.0.7
retired
1.0.6
1.0.5
1.0.4
1.0.3
1.0.2
1.0.1
1.0.0
0.25.6
0.25.5
0.25.4
0.25.3
retired
0.25.2
0.25.1
0.25.0
0.24.4
0.24.3
0.24.2
0.24.1
0.24.0
0.23.5
0.23.4
0.23.3
0.23.2
0.23.1
0.23.0
0.22.2
0.22.1
0.22.0
0.21.1
0.21.0
0.20.0
0.19.0
0.18.0
0.17.0
0.16.1
0.16.0
0.15.0
0.14.0
0.13.0
0.12.1
0.12.0
0.11.0
0.10.0
0.9.1
0.9.0
0.8.1
0.8.0
0.7.0
0.6.0
0.5.0
0.4.0
0.3.0
0.2.0
0.1.0
Compose, deliver and test your emails easily in Elixir. Supports SMTP, Sendgrid, Mandrill, Postmark, Mailgun and many more out of the box. Preview your emails in the browser. Test your email sending code.
Current section
Files
Jump to
Current section
Files
lib/plug/mailbox_preview.ex
if Code.ensure_loaded?(Plug) do
defmodule Plug.Swoosh.MailboxPreview do
@moduledoc """
Plug that serves pages useful for previewing emails in development.
## Examples
# in a Phoenix router
defmodule Sample.Router do
scope "/dev" do
pipe_through [:browser]
forward "/mailbox", Plug.Swoosh.MailboxPreview
end
end
"""
use Plug.Router
use Plug.ErrorHandler
alias Swoosh.Email.Render
alias Swoosh.Adapters.Local.Storage.Memory
require EEx
EEx.function_from_file(
:defp,
:template,
"lib/plug/templates/mailbox_viewer/index.html.eex",
[:assigns]
)
def call(conn, opts) do
conn =
conn
|> assign(:base_path, Path.join(["/" | conn.script_name]))
|> assign(:storage_driver, opts[:storage_driver] || Memory)
super(conn, opts)
end
plug :match
plug :dispatch
post "/clear" do
conn.assigns.storage_driver.delete_all()
conn
|> put_resp_header("location", conn.assigns.base_path)
|> send_resp(302, '')
end
get "/json" do
emails = Enum.map(conn.assigns.storage_driver.all(), &render_email_json/1)
response = Swoosh.json_library().encode_to_iodata!(%{data: emails})
conn
|> put_resp_content_type("application/json")
|> send_resp(200, response)
end
get "/" do
emails = conn.assigns.storage_driver.all()
conn
|> put_resp_content_type("text/html")
|> send_resp(200, template(emails: emails, email: nil, conn: conn))
end
get "/:id/html" do
email = conn.assigns.storage_driver.get(id)
conn
|> put_resp_content_type("text/html")
|> send_resp(200, replace_inline_references(email))
end
get "/:id/attachments/:index" do
index = String.to_integer(index)
id
|> conn.assigns.storage_driver.get()
|> case do
%{attachments: attachments} when length(attachments) > index ->
attachments
|> Enum.at(index)
|> case do
%{data: data, content_type: content_type} when not is_nil(data) ->
conn
|> put_resp_content_type(content_type)
|> send_resp(200, data)
%{path: path, content_type: content_type} when not is_nil(path) ->
conn
|> put_resp_content_type(content_type)
|> send_resp(200, File.read!(path))
_ ->
conn
|> put_resp_content_type("text/html")
|> send_resp(500, "Attachment cannot be displayed")
end
_ ->
conn
|> put_resp_content_type("text/html")
|> send_resp(404, "Attachment Not Found")
end
end
get "/:id" do
emails = conn.assigns.storage_driver.all()
email = conn.assigns.storage_driver.get(id)
conn
|> put_resp_content_type("text/html")
|> send_resp(200, template(emails: emails, email: email, conn: conn))
end
defp render_email_json(email) do
%{
subject: email.subject,
from: Render.render_recipient(email.from),
to: Enum.map(email.to, &Render.render_recipient/1),
cc: Enum.map(email.cc, &Render.render_recipient/1),
bcc: Enum.map(email.bcc, &Render.render_recipient/1),
reply_to: Render.render_recipient(email.reply_to),
sent_at: Map.get(email.private, :sent_at),
text_body: email.text_body,
html_body: email.html_body,
headers: email.headers,
provider_options:
Enum.map(email.provider_options, fn {k, v} -> %{key: k, value: inspect(v)} end),
attachments: Enum.map(email.attachments, &render_attachment_json/1)
}
end
defp render_attachment_json(attachment) do
%{
filename: attachment.filename,
content_type: attachment.content_type,
path: attachment.path,
type: attachment.type,
headers: Map.new(attachment.headers)
}
end
defp to_absolute_url(conn, path) do
Path.join(conn.assigns.base_path, path)
end
defp render_recipient(recipient) do
case Render.render_recipient(recipient) do
"" -> "n/a"
recipient -> Plug.HTML.html_escape(recipient)
end
end
defp replace_inline_references(%{html_body: nil, text_body: text_body}) do
text_body
end
defp replace_inline_references(%{html_body: html_body, attachments: attachments}) do
~r/"cid:([^"]*)"/
|> Regex.scan(html_body)
|> Enum.reduce(html_body, fn [_, ref], body ->
with index when is_integer(index) <- Enum.find_index(attachments, &(&1.filename == ref)) do
String.replace(body, "cid:#{ref}", "attachments/#{index}")
else
nil -> html_body
end
end)
end
end
end