Repository: swoosh/swoosh
Pull request #895 (2024-04-19 00:16:10)

Add support for allow_nil_from
Mandrill email templates allow specification of the `from` email address and name on the template itself. Swoosh, however, requires `from` to be explicitly set which will cause the template values to always be overridden. This change adds the `allow_nil_from` config option which skips that check and allows use of the template-sourced values.

princemaple: Hi Bernard, thanks for the PR. I would prefer not adding a new config, as this would add complexity to understanding which adapter could use which configs.

There is a similar scenario in Brevo. I would like to suggest a similar solution. Simply documenting a special value `from`, e.g. `{:from, "TEMPLATE"}`, and have a special clause of `prepare from` that handles it.
https://github.com/swoosh/swoosh/blob/main/lib/swoosh/adapters/brevo.ex#L118
bernardd: Makes sense to me. I've pushed a new version with that change.
princemaple: Thanks Bernard. I'm at the airport. I'll get back to this later today, or tomorrow. Feel free to ping me if I forgot to do so. Cheers!
bernardd: No rush, thanks @princemaple :)

Patch:
diff --git a/lib/swoosh/adapters/mandrill.ex b/lib/swoosh/adapters/mandrill.ex
index b684eb7..6de9697 100644
--- a/lib/swoosh/adapters/mandrill.ex
+++ b/lib/swoosh/adapters/mandrill.ex
@@ -78,6 +78,14 @@ defmodule Swoosh.Adapters.Mandrill do
 
     * `:tags` (list[string]) - a list of strings to tag the message with
 
+  ## Template-configured 'from' address
+
+  Mandrill templates allow you to configure the 'from' address in the template itself.
+  To use the 'from' fields configured in the template, rather than specifying the value
+  explicitly, you can set
+
+    |> from("TEMPLATE")
+
   """
 
   use Swoosh.Adapter, required_config: [:api_key]
@@ -156,6 +164,8 @@ defmodule Swoosh.Adapters.Mandrill do
   defp set_async(body, %{provider_options: %{async: true}}), do: Map.put(body, :async, true)
   defp set_async(body, _email), do: body
 
+  defp prepare_from(body, %{from: {_, "TEMPLATE"}}), do: body
+
   defp prepare_from(body, %{from: {nil, address}}), do: Map.put(body, :from_email, address)
 
   defp prepare_from(body, %{from: {name, address}}) do


Test patch:
diff --git a/test/swoosh/adapters/mandrill_test.exs b/test/swoosh/adapters/mandrill_test.exs
index 9ffa0a7..c2ca1da 100644
--- a/test/swoosh/adapters/mandrill_test.exs
+++ b/test/swoosh/adapters/mandrill_test.exs
@@ -596,4 +596,34 @@ defmodule Swoosh.Adapters.MandrillTest do
 
     assert Mandrill.deliver(email, config) == {:ok, %{id: "9"}}
   end
+
+  test "deliver/1 with TEMPLATE from value returns :ok and has no from values",
+       %{bypass: bypass, config: config} do
+    email =
+      new()
+      |> from("TEMPLATE")
+      |> to({"Steve Rogers", "steve.rogers@example.com"})
+
+    Bypass.expect(bypass, fn conn ->
+      conn = parse(conn)
+
+      body_params = %{
+        "key" => "jarvis",
+        "message" => %{
+          "subject" => "",
+          "to" => [
+            %{"type" => "to", "email" => "steve.rogers@example.com", "name" => "Steve Rogers"}
+          ]
+        }
+      }
+
+      assert body_params == conn.body_params
+      assert "/messages/send.json" == conn.request_path
+      assert "POST" == conn.method
+
+      Plug.Conn.resp(conn, 200, @success_response)
+    end)
+
+    assert Mandrill.deliver(email, config) == {:ok, %{id: "9"}}
+  end
 end