Skip to content

Commit

Permalink
Add attachment support (#156)
Browse files Browse the repository at this point in the history
  • Loading branch information
andrewtimberlake authored and paulcsmith committed May 5, 2017
1 parent 2876dfe commit 8dff421
Show file tree
Hide file tree
Showing 6 changed files with 117 additions and 0 deletions.
34 changes: 34 additions & 0 deletions lib/bamboo/attachment.ex
Original file line number Diff line number Diff line change
@@ -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
23 changes: 23 additions & 0 deletions lib/bamboo/email.ex
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ defmodule Bamboo.Email do
html_body: nil,
text_body: nil,
headers: %{},
attachments: [],
assigns: %{},
private: %{}

Expand Down Expand Up @@ -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: <name>` and `content_type: <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
53 changes: 53 additions & 0 deletions test/lib/bamboo/attachments_test.exs
Original file line number Diff line number Diff line change
@@ -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
7 changes: 7 additions & 0 deletions test/lib/bamboo/email_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Binary file added test/support/attachment.docx
Binary file not shown.
Empty file added test/support/attachment.unknown
Empty file.

0 comments on commit 8dff421

Please sign in to comment.