Skip to content

Commit

Permalink
Add sending adapter
Browse files Browse the repository at this point in the history
  • Loading branch information
kalys committed Jan 21, 2023
1 parent c865bc6 commit f163208
Show file tree
Hide file tree
Showing 8 changed files with 157 additions and 96 deletions.
46 changes: 46 additions & 0 deletions lib/bamboo/adapters/mailtrap_helper.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
defmodule Bamboo.MailtrapHelper do
alias Mailtrap.Email

def build_from_bamboo_email(bamboo_email) do
%Email{}
|> Email.put_from(bamboo_email.from)
|> Email.put_to(bamboo_email.to)
|> Email.put_cc(bamboo_email.cc)
|> Email.put_bcc(bamboo_email.bcc)
|> Email.put_bcc(bamboo_email.bcc)
|> Email.put_subject(bamboo_email.subject)
|> Email.put_text(bamboo_email.text_body)
|> Email.put_html(bamboo_email.html_body)
|> Email.put_headers(bamboo_email.headers)
|> Email.put_attachments(prepare_attachments(bamboo_email.attachments))
end

def get_key(config, key) do
case Map.get(config, key) do
nil -> raise_key_error(config, key)
key -> key
end
end

defp prepare_attachments(attachments) do
Enum.map(
attachments,
fn attachment ->
mailtrap_attachment =
Mailtrap.Email.Attachment.build(attachment.data, attachments.filename)

Mailtrap.Email.Attachment.put_content_id(mailtrap_attachment, attachment.content_id)
end
)
end

defp raise_key_error(config, key) do
raise ArgumentError, """
There was no #{key} set for the adapter.
* Here are the config options that were passed in:
#{inspect(config)}
"""
end
end
48 changes: 3 additions & 45 deletions lib/bamboo/adapters/mailtrap_sandbox_adapter.ex
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ defmodule Bamboo.MailtrapSandboxAdapter do
inbox_id: "my_inbox_id"
"""

alias Mailtrap.Email
@behaviour Bamboo.Adapter

import Bamboo.ApiError
import Bamboo.MailtrapHelper

@doc """
Implements Bamboo.Adapter callback
Expand All @@ -38,53 +38,11 @@ defmodule Bamboo.MailtrapSandboxAdapter do
inbox_id = get_key(config, :inbox_id)

client = Mailtrap.Sandbox.client(api_token)
email = build_from_bamboo_email(bamboo_email)

email =
%Email{}
|> Email.put_from(bamboo_email.from)
|> Email.put_to(bamboo_email.to)
|> Email.put_cc(bamboo_email.cc)
|> Email.put_bcc(bamboo_email.bcc)
|> Email.put_bcc(bamboo_email.bcc)
|> Email.put_subject(bamboo_email.subject)
|> Email.put_text(bamboo_email.text_body)
|> Email.put_html(bamboo_email.html_body)
|> Email.put_headers(bamboo_email.headers)
|> Email.put_attachments(prepare_attachments(bamboo_email.attachments))

Mailtrap.Sandbox.send(client, email, inbox_id)
|> case do
case Mailtrap.Sandbox.send(client, email, inbox_id) do
{:ok, response} -> {:ok, response}
{:error, reason} -> {:error, build_api_error(inspect(reason))}
end
end

defp prepare_attachments(attachments) do
Enum.map(
attachments,
fn attachment ->
mailtrap_attachment =
Mailtrap.Email.Attachment.build(attachment.data, attachments.filename)

Mailtrap.Email.Attachment.put_content_id(mailtrap_attachment, attachment.content_id)
end
)
end

defp get_key(config, key) do
case Map.get(config, key) do
nil -> raise_key_error(config, key)
key -> key
end
end

defp raise_key_error(config, key) do
raise ArgumentError, """
There was no #{key} set for the adapter.
* Here are the config options that were passed in:
#{inspect(config)}
"""
end
end
40 changes: 16 additions & 24 deletions lib/bamboo/adapters/mailtrap_sending_adapter.ex
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
defmodule Bamboo.MailtrapSendingAdapter do
@moduledoc """
Sends an email to Mailtrap Sending.
## Configuration
config :my_app, MyApp.Mailer,
adapter: Bamboo.MailtrapSendingAdapter,
api_token: "my_api_key"
"""

@behaviour Bamboo.Adapter

alias Mailtrap.Email
alias Mailtrap.Email.Attachment
import Bamboo.ApiError
import Bamboo.MailtrapHelper

@doc """
Implements Bamboo.Adapter callback
Expand All @@ -27,28 +32,15 @@ defmodule Bamboo.MailtrapSendingAdapter do
Implements Bamboo.Adapter callback
"""
@impl Bamboo.Adapter
def deliver(email, _config) do
%Email{}
|> Email.put_from(email.from)
|> Email.put_to(email.to)
|> Email.put_cc(email.cc)
|> Email.put_bcc(email.bcc)
|> Email.put_bcc(email.bcc)
|> Email.put_subject(email.subject)
|> Email.put_text(email.text_body)
|> Email.put_html(email.html_body)
|> Email.put_headers(email.headers)
|> Email.put_attachments(prepare_attachments(email.attachments))
|> Mailtrap.Sending.send()
end
def deliver(bamboo_email, config) do
api_token = get_key(config, :api_token)

client = Mailtrap.Sending.client(api_token)
email = build_from_bamboo_email(bamboo_email)

defp prepare_attachments(attachments) do
Enum.map(
attachments,
fn attachment ->
mailtrap_attachment = Attachment.build(attachment.data, attachments.filename)
Attachment.put_content_id(mailtrap_attachment, attachment.content_id)
end
)
case Mailtrap.Sending.send(client, email) do
{:ok, response} -> {:ok, response}
{:error, reason} -> {:error, build_api_error(inspect(reason))}
end
end
end
24 changes: 17 additions & 7 deletions lib/mailtrap/sending.ex
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,26 @@ defmodule Mailtrap.Sending do

use Tesla

plug(Mailtrap.DirectResponse)
plug(Tesla.Middleware.JSON)
plug(Tesla.Middleware.BaseUrl, "https://send.api.mailtrap.io/api")
plug(Tesla.Middleware.BearerAuth, token: Application.get_env(:mailtrap, :api_token))
@doc """
Generates client
"""
@spec client(String.t()) :: Tesla.Client.t()
def client(token) do
middleware = [
Mailtrap.DirectResponse,
Tesla.Middleware.JSON,
{Tesla.Middleware.BaseUrl, "https://send.api.mailtrap.io/api"},
{Tesla.Middleware.BearerAuth, token: token}
]

Tesla.client(middleware)
end

@doc """
Sends an email
"""
@spec send(Mailtrap.Email.t()) :: {:ok, map()} | {:error, Tesla.Env.t()}
def send(email) do
post("send", email)
@spec send(Tesla.Client.t(), Mailtrap.Email.t()) :: {:ok, map()} | {:error, Tesla.Env.t()}
def send(client, email) do
post(client, "send", email)
end
end
22 changes: 5 additions & 17 deletions test/bamboo/adapters/mailtrap_sandbox_adapter_test.exs
Original file line number Diff line number Diff line change
@@ -1,21 +1,8 @@
defmodule Bamboo.MailtrapSandboxAdapterTest do
use ExUnit.Case
import Tesla.Mock
alias Bamboo.{Email, Mailer, MailtrapSandboxAdapter}

@doc false
def new_email(to \\ "[email protected]", subject \\ "Welcome to the app.") do
Email.new_email(
to: to,
from: "[email protected]",
cc: "[email protected]",
bcc: "[email protected]",
subject: subject,
html_body: "<strong>Thanks for joining!</strong>",
text_body: "Thanks for joining!"
)
|> Mailer.normalize_addresses()
end
import Mailtrap.BambooTestHelper
alias Bamboo.MailtrapSandboxAdapter

def api_configs, do: %{api_token: "api_token", inbox_id: 11111}

Expand All @@ -30,7 +17,7 @@ defmodule Bamboo.MailtrapSandboxAdapterTest do
html: "<strong>Thanks for joining!</strong>",
subject: "Welcome to the app.",
text: "Thanks for joining!",
to: [%{email: "[email protected]"}],
to: [%{email: "[email protected]"}]
})

mock(fn
Expand All @@ -41,7 +28,8 @@ defmodule Bamboo.MailtrapSandboxAdapterTest do
{"content-type", "application/json"},
{"authorization", "Bearer api_token"}
],
url: "https://sandbox.api.mailtrap.io/api/send/11111"} ->
url: "https://sandbox.api.mailtrap.io/api/send/11111"
} ->
json(%{success: true, message_ids: [1]}, status: 200)
end)

Expand Down
47 changes: 47 additions & 0 deletions test/bamboo/adapters/mailtrap_sending_adapter_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
defmodule Bamboo.MailtrapSendingAdapterTest do
use ExUnit.Case
import Tesla.Mock
import Mailtrap.BambooTestHelper
alias Bamboo.MailtrapSendingAdapter

def api_configs, do: %{api_token: "api_token"}

test "happy path" do
expected_request_body =
Jason.encode!(%{
attachments: [],
bcc: [%{email: "[email protected]"}],
cc: [%{email: "[email protected]"}],
from: %{email: "[email protected]"},
headers: %{},
html: "<strong>Thanks for joining!</strong>",
subject: "Welcome to the app.",
text: "Thanks for joining!",
to: [%{email: "[email protected]"}]
})

mock(fn
%{
method: :post,
body: ^expected_request_body,
headers: [
{"content-type", "application/json"},
{"authorization", "Bearer api_token"}
],
url: "https://send.api.mailtrap.io/api/send"
} ->
json(%{success: true, message_ids: [1]}, status: 200)
end)

assert {:ok, _} = MailtrapSendingAdapter.deliver(new_email(), api_configs())
end

test "returns error" do
mock(fn
%{method: :post, url: "https://send.api.mailtrap.io/api/send"} ->
json(%{error: "Incorrect API token"}, status: 401)
end)

assert {:error, _} = MailtrapSendingAdapter.deliver(new_email(), api_configs())
end
end
9 changes: 6 additions & 3 deletions test/mailtrap_sending_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ defmodule Mailtrap.SendingTest do
end)

message = %Mailtrap.Email{}
assert {:error, %Tesla.Env{status: 401, body: body}} = Mailtrap.Sending.send(message)
client = Mailtrap.Sending.client("api_token")
assert {:error, %Tesla.Env{status: 401, body: body}} = Mailtrap.Sending.send(client, message)
assert %{"error" => "Incorrect API token"} == body
end

Expand All @@ -31,15 +32,17 @@ defmodule Mailtrap.SendingTest do
json(%{success: true, message_ids: ["1", "2"]})
end)

response =
message =
%Email{}
|> Email.put_subject("Hello")
|> Email.put_from({"John Doe", "[email protected]"})
|> Email.put_to({"Jane Doe", "[email protected]"})
|> Email.put_cc({"Alice", "[email protected]"})
|> Email.put_text("Hello")
|> Email.put_html("<strong>Hello</strong>")
|> Mailtrap.Sending.send()

client = Mailtrap.Sending.client("api_token")
response = Mailtrap.Sending.send(client, message)

assert {:ok, %{"message_ids" => ["1", "2"], "success" => true}} = response
end
Expand Down
17 changes: 17 additions & 0 deletions test/support/bamboo_test_helper.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
defmodule Mailtrap.BambooTestHelper do
alias Bamboo.{Email, Mailer}

@doc false
def new_email(to \\ "[email protected]", subject \\ "Welcome to the app.") do
Email.new_email(
to: to,
from: "[email protected]",
cc: "[email protected]",
bcc: "[email protected]",
subject: subject,
html_body: "<strong>Thanks for joining!</strong>",
text_body: "Thanks for joining!"
)
|> Mailer.normalize_addresses()
end
end

0 comments on commit f163208

Please sign in to comment.