diff --git a/lib/berrypod/mailer/swoosh_mailersend.ex b/lib/berrypod/mailer/swoosh_mailersend.ex new file mode 100644 index 0000000..7662fe9 --- /dev/null +++ b/lib/berrypod/mailer/swoosh_mailersend.ex @@ -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