defmodule Swoosh.Adapter do
@moduledoc ~S"""
Specification of the email delivery adapter.
"""
defmacro __using__(opts) do
quote bind_quoted: [opts: opts] do
@required_config opts[:required_config] || []
@required_deps opts[:required_deps] || []
@behaviour Swoosh.Adapter
def validate_config(config) do
Swoosh.Adapter.validate_config(@required_config, config)
end
def validate_dependency do
Swoosh.Adapter.validate_dependency(@required_deps)
end
end
end
@type t :: module
@type email :: Email.t()
@type config :: Keyword.t()
@doc """
Delivers an email with the given config.
"""
@callback deliver(%Swoosh.Email{}, config) :: {:ok, term} | {:error, term}
@doc """
Delivers multiple emails with the given config in one request. Some email providers allow multiple
messages to be sent in one HTTP request, for example Mailjet and Postmark allow this. Check your
provider's documentation to see if that is possible.
"""
@callback deliver_many(list(%Swoosh.Email{}), config) ::
{:ok, list(term)} | {:error, term}
@callback validate_config(config) :: :ok | no_return
@callback validate_dependency() :: :ok | [module | {atom, module}]
@optional_callbacks validate_dependency: 0, deliver_many: 2
@spec validate_config([atom], Keyword.t()) :: :ok | no_return
def validate_config(required_config, config) do
missing_keys =
Enum.reduce(required_config, [], fn key, missing_keys ->
if config[key] in [nil, ""],
do: [key | missing_keys],
else: missing_keys
end)
raise_on_missing_config(missing_keys, config)
end
defp raise_on_missing_config([], _config), do: :ok
defp raise_on_missing_config(key, config) do
raise ArgumentError, """
expected #{inspect(key)} to be set, got: #{inspect(config)}
"""
end
@spec validate_dependency([module | {atom, module}]) ::
:ok | {:error, [module | {:atom | module}]}
def validate_dependency(required_deps) do
if Enum.all?(required_deps, fn
{_lib, module} -> Code.ensure_loaded?(module)
module -> Code.ensure_loaded?(module)
end),
do: :ok,
else: {:error, required_deps}
end
end