diff --git a/lib/bamboo/attachment.ex b/lib/bamboo/attachment.ex new file mode 100644 index 00000000..b5106866 --- /dev/null +++ b/lib/bamboo/attachment.ex @@ -0,0 +1,34 @@ +defmodule Bamboo.Attachment do + @moduledoc """ + """ + + defstruct filename: nil, content_type: nil, path: nil + + @doc ~S""" + Creates a new Attachment + + Examples: + Attachment.new("/path/to/attachment.png") + Attachment.new("/path/to/attachment.png", filename: "image.png") + Attachment.new("/path/to/attachment.png", filename: "image.png", content_type: "image/png") + Attachment.new(params["file"]) # Where params["file"] is a %Plug.Upload + """ + def new(path, opts \\ []) + if Code.ensure_loaded?(Plug) do + def new(%Plug.Upload{filename: filename, content_type: content_type, path: path}, opts), do: + new(path, Dict.merge([filename: filename, content_type: content_type], opts)) + end + def new(path, opts) do + filename = opts[:filename] || Path.basename(path) + content_type = opts[:content_type] || determine_content_type(path) + %__MODULE__{path: path, filename: filename, content_type: content_type} + end + + defp determine_content_type(path) do + if Code.ensure_loaded?(Plug) do + Plug.MIME.path(path) + else + "application/octet-stream" + end + end +end diff --git a/lib/bamboo/email.ex b/lib/bamboo/email.ex index faf22771..f6fc4189 100644 --- a/lib/bamboo/email.ex +++ b/lib/bamboo/email.ex @@ -86,6 +86,7 @@ defmodule Bamboo.Email do html_body: nil, text_body: nil, headers: %{}, + attachments: [], assigns: %{}, private: %{} @@ -200,4 +201,26 @@ defmodule Bamboo.Email do def put_private(%Email{private: private} = email, key, value) do %{email | private: Map.put(private, key, value)} end + + @doc ~S""" + Adds an attachment to the email + + ## Example + put_attachment(email, path, opts \\ []) + + Accepts `filename: ` and `content_type: ` options. + + If you are using Plug, it accepts a Plug.Upload struct + + ## Example + def create(conn, params) do + #... + email + |> put_attachment(params["file"]) + #... + end + """ + def put_attachment(%__MODULE__{attachments: attachments} = email, path, opts \\ []) do + %{email | attachments: [Bamboo.Attachment.new(path, opts) | attachments]} + end end diff --git a/test/lib/bamboo/attachments_test.exs b/test/lib/bamboo/attachments_test.exs new file mode 100644 index 00000000..1e2d13b5 --- /dev/null +++ b/test/lib/bamboo/attachments_test.exs @@ -0,0 +1,53 @@ +defmodule Bamboo.AttachmentTest do + use ExUnit.Case + + alias Bamboo.Attachment + + test "create an attachment" do + path = Path.join(__DIR__, "../../support/attachment.docx") + attachment = Attachment.new(path) + assert attachment.content_type == "application/vnd.openxmlformats-officedocument.wordprocessingml.document" + assert attachment.filename == "attachment.docx" + assert attachment.path == path + end + + test "create an attachment with an unknown content type" do + path = Path.join(__DIR__, "../../support/attachment.unknown") + attachment = Attachment.new(path) + assert attachment.content_type == "application/octet-stream" + end + + test "create an attachment with a specified file name" do + path = Path.join(__DIR__, "../../support/attachment.docx") + attachment = Attachment.new(path, filename: "my-test-name.doc") + assert attachment.filename == "my-test-name.doc" + end + + test "create an attachment with a specified content type" do + path = Path.join(__DIR__, "../../support/attachment.docx") + attachment = Attachment.new(path, content_type: "application/msword") + assert attachment.content_type == "application/msword" + end + + test "create an attachment from a Plug Upload struct" do + path = Path.join(__DIR__, "../../support/attachment.docx") + upload = %Plug.Upload{filename: "test.docx", + content_type: "application/msword", + path: path} + attachment = Attachment.new(upload) + assert attachment.content_type == "application/msword" + assert attachment.filename == "test.docx" + assert attachment.path == path + end + + test "create an attachment from a Plug Upload struct with overrides" do + path = Path.join(__DIR__, "../../support/attachment.docx") + upload = %Plug.Upload{filename: "test.docx", + content_type: "application/msword", + path: path} + attachment = Attachment.new(upload, filename: "my-attachment.doc", content_type: "application/other") + assert attachment.content_type == "application/other" + assert attachment.filename == "my-attachment.doc" + assert attachment.path == path + end +end diff --git a/test/lib/bamboo/email_test.exs b/test/lib/bamboo/email_test.exs index 26e57714..d9c0eb30 100644 --- a/test/lib/bamboo/email_test.exs +++ b/test/lib/bamboo/email_test.exs @@ -76,4 +76,11 @@ defmodule Bamboo.EmailTest do assert email.private["foo"] == "bar" end + + test "put_attachment/3 atts an attachment to the attachments list" do + path = Path.join(__DIR__, "../../support/attachment.docx") + email = new_email |> put_attachment(path) + + assert [%Bamboo.Attachment{filename: "attachment.docx"}] = email.attachments + end end diff --git a/test/support/attachment.docx b/test/support/attachment.docx new file mode 100644 index 00000000..b32951ce Binary files /dev/null and b/test/support/attachment.docx differ diff --git a/test/support/attachment.unknown b/test/support/attachment.unknown new file mode 100644 index 00000000..e69de29b