add custom Swoosh adapter for MailerSend
All checks were successful
deploy / deploy (push) Successful in 1m23s

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
jamey 2026-02-21 23:48:06 +00:00
parent a0985bd07e
commit 04cdb62a8d

View File

@ -0,0 +1,113 @@
defmodule Swoosh.Adapters.MailerSend do
@moduledoc """
Swoosh adapter for the MailerSend API.
Requires `api_key` in config. Uses the v1 email endpoint.
"""
use Swoosh.Adapter, required_config: [:api_key]
alias Swoosh.Email
@base_url "https://api.mailersend.com"
@api_endpoint "/v1/email"
def deliver(%Email{} = email, config \\ []) do
headers = [
{"Authorization", "Bearer #{config[:api_key]}"},
{"Content-Type", "application/json"},
{"User-Agent", "swoosh/#{Swoosh.version()}"}
]
body = email |> prepare_body() |> Swoosh.json_library().encode!()
url = [config[:base_url] || @base_url, @api_endpoint]
case Swoosh.ApiClient.post(url, headers, body, email) do
{:ok, code, _headers, body} when code >= 200 and code <= 299 ->
{:ok, decode_success(body)}
{:ok, code, _headers, body} ->
case Swoosh.json_library().decode(body) do
{:ok, error} -> {:error, {code, error}}
{:error, _} -> {:error, {code, body}}
end
{:error, reason} ->
{:error, reason}
end
end
defp decode_success(""), do: %{}
defp decode_success(body) do
case Swoosh.json_library().decode(body) do
{:ok, %{"message_id" => id}} -> %{id: id}
{:ok, parsed} -> parsed
_ -> %{}
end
end
defp prepare_body(email) do
%{}
|> prepare_from(email)
|> prepare_to(email)
|> prepare_cc(email)
|> prepare_bcc(email)
|> prepare_reply_to(email)
|> prepare_subject(email)
|> prepare_text(email)
|> prepare_html(email)
end
defp prepare_from(body, %{from: {name, address}}) when name not in [nil, ""] do
Map.put(body, "from", %{"email" => address, "name" => name})
end
defp prepare_from(body, %{from: {_name, address}}) do
Map.put(body, "from", %{"email" => address})
end
defp prepare_to(body, %{to: to}) do
Map.put(body, "to", Enum.map(to, &format_recipient/1))
end
defp prepare_cc(body, %{cc: []}), do: body
defp prepare_cc(body, %{cc: cc}) do
Map.put(body, "cc", Enum.map(cc, &format_recipient/1))
end
defp prepare_bcc(body, %{bcc: []}), do: body
defp prepare_bcc(body, %{bcc: bcc}) do
Map.put(body, "bcc", Enum.map(bcc, &format_recipient/1))
end
defp prepare_reply_to(body, %{reply_to: nil}), do: body
defp prepare_reply_to(body, %{reply_to: {name, address}}) when name not in [nil, ""] do
Map.put(body, "reply_to", %{"email" => address, "name" => name})
end
defp prepare_reply_to(body, %{reply_to: {_name, address}}) do
Map.put(body, "reply_to", %{"email" => address})
end
defp prepare_subject(body, %{subject: subject}) when subject not in [nil, ""] do
Map.put(body, "subject", subject)
end
defp prepare_subject(body, _), do: body
defp prepare_text(body, %{text_body: nil}), do: body
defp prepare_text(body, %{text_body: text}), do: Map.put(body, "text", text)
defp prepare_html(body, %{html_body: nil}), do: body
defp prepare_html(body, %{html_body: html}), do: Map.put(body, "html", html)
defp format_recipient({name, email}) when name not in [nil, ""] do
%{"email" => email, "name" => name}
end
defp format_recipient({_name, email}), do: %{"email" => email}
end