-
Notifications
You must be signed in to change notification settings - Fork 66
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge remote-tracking branch 'upstream/master' into remove_text_part_…
…sorting
- Loading branch information
Showing
26 changed files
with
1,374 additions
and
400 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
name: Elixir CI | ||
|
||
on: | ||
push: | ||
branches: [master] | ||
pull_request: | ||
branches: [master] | ||
|
||
env: | ||
MIX_ENV: test | ||
|
||
permissions: | ||
contents: read | ||
|
||
jobs: | ||
build: | ||
name: Build and test | ||
runs-on: ubuntu-latest | ||
|
||
strategy: | ||
matrix: | ||
elixir: ['1.14.5', '1.15.4', '1.16.3', '1.17.3'] | ||
erlang: ['24.3', '25.3', '26.0', '27.1'] | ||
exclude: | ||
- elixir: '1.14.5' | ||
erlang: '27.1' | ||
- elixir: '1.15.4' | ||
erlang: '27.1' | ||
- elixir: '1.16.3' | ||
erlang: '27.1' | ||
- elixir: '1.17.3' | ||
erlang: '24.3' | ||
steps: | ||
- uses: actions/checkout@v3 | ||
- name: Set up Elixir | ||
uses: erlef/setup-beam@v1 | ||
with: | ||
version-type: 'loose' | ||
elixir-version: ${{ matrix.elixir }} | ||
otp-version: ${{ matrix.erlang }} | ||
- name: Restore dependencies cache | ||
uses: actions/cache@v2 | ||
with: | ||
path: deps | ||
key: ${{ runner.os }}-${{ matrix.erlang }}-${{ matrix.elixir }}-mix-${{ hashFiles('**/mix.lock') }} | ||
restore-keys: ${{ runner.os }}-${{ matrix.erlang }}-${{ matrix.elixir }}-mix- | ||
- name: Install dependencies | ||
run: mix deps.get | ||
- name: Run tests | ||
run: mix test |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -25,6 +25,18 @@ defmodule Mail do | |
def build_multipart, | ||
do: %Mail.Message{multipart: true} | ||
|
||
@doc """ | ||
Primary hook for parsing | ||
You can pass in your own custom parse module. That module | ||
must have a `parse/1` function that accepts a string or list of lines | ||
By default the `parser` will be `Mail.Parsers.RFC2822` | ||
""" | ||
def parse(message, parser \\ Mail.Parsers.RFC2822) do | ||
parser.parse(message) | ||
end | ||
|
||
@doc """ | ||
Add a plaintext part to the message | ||
|
@@ -58,7 +70,7 @@ defmodule Mail do | |
["text/plain", {"charset", charset}] | ||
|
||
_else -> | ||
"text/plain" | ||
["text/plain", {"charset", default_charset()}] | ||
end | ||
|
||
Mail.Message.put_body(message, body) | ||
|
@@ -67,23 +79,22 @@ defmodule Mail do | |
end | ||
|
||
@doc """ | ||
Find the text part of a given mail | ||
Find the last text part of a given mail | ||
RFC 2046, §5.1.4 “In general, the best choice is the LAST part of a type supported by the recipient system's local environment.” | ||
If single part with `content-type` "text/plain", returns itself | ||
If single part without `content-type` "text/plain", returns `nil` | ||
If multipart with part having `content-type` "text/plain" will return that part | ||
If multipart without part having `content-type` "text/plain" will return `nil` | ||
""" | ||
def get_text(%Mail.Message{multipart: true} = message) do | ||
Enum.reduce_while(message.parts, nil, fn sub_message, acc -> | ||
Enum.reduce_while(Enum.reverse(message.parts), nil, fn sub_message, acc -> | ||
text_part = get_text(sub_message) | ||
if text_part, do: {:halt, text_part}, else: {:cont, acc} | ||
end) | ||
end | ||
|
||
def get_text(%Mail.Message{headers: %{"content-type" => "text/plain" <> _}} = message), | ||
do: message | ||
|
||
def get_text(%Mail.Message{headers: %{"content-type" => ["text/plain" | _]}} = message), | ||
do: message | ||
|
||
|
@@ -120,7 +131,7 @@ defmodule Mail do | |
["text/html", {"charset", charset}] | ||
|
||
_else -> | ||
"text/html" | ||
["text/html", {"charset", default_charset()}] | ||
end | ||
|
||
Mail.Message.put_body(message, body) | ||
|
@@ -129,15 +140,17 @@ defmodule Mail do | |
end | ||
|
||
@doc """ | ||
Find the html part of a given mail | ||
Find the last html part of a given mail | ||
RFC 2046, §5.1.4 “In general, the best choice is the LAST part of a type supported by the recipient system's local environment.” | ||
If single part with `content-type` "text/html", returns itself | ||
If single part without `content-type` "text/html", returns `nil` | ||
If multipart with part having `content-type` "text/html" will return that part | ||
If multipart without part having `content-type` "text/html" will return `nil` | ||
""" | ||
def get_html(%Mail.Message{multipart: true} = message) do | ||
Enum.reduce_while(message.parts, nil, fn sub_message, acc -> | ||
Enum.reduce_while(Enum.reverse(message.parts), nil, fn sub_message, acc -> | ||
html_part = get_html(sub_message) | ||
if html_part, do: {:halt, html_part}, else: {:cont, acc} | ||
end) | ||
|
@@ -150,6 +163,10 @@ defmodule Mail do | |
|
||
def get_html(%Mail.Message{}), do: nil | ||
|
||
defp default_charset do | ||
"UTF-8" | ||
end | ||
|
||
@doc """ | ||
Add an attachment part to the message | ||
|
@@ -212,8 +229,13 @@ defmodule Mail do | |
walk_parts([message], {:cont, []}, fn message, acc -> | ||
case Mail.Message.is_attachment?(message) do | ||
true -> | ||
["attachment", {"filename", filename} | _] = | ||
Mail.Message.get_header(message, :content_disposition) | ||
filename = | ||
case List.wrap(Mail.Message.get_header(message, :content_disposition)) do | ||
["attachment" | properties] -> | ||
Enum.find_value(properties, "Unknown", fn {key, value} -> | ||
key == "filename" && value | ||
end) | ||
end | ||
|
||
{:cont, List.insert_at(acc, -1, {filename, message.body})} | ||
|
||
|
@@ -236,8 +258,10 @@ defmodule Mail do | |
@doc """ | ||
Add a new `subject` header | ||
Mail.put_subject(%Mail.Message{}, "Welcome to DockYard!") | ||
%Mail.Message{headers: %{subject: "Welcome to DockYard!"}} | ||
## Examples | ||
iex> Mail.put_subject(%Mail.Message{}, "Welcome to DockYard!") | ||
%Mail.Message{headers: %{"subject" => "Welcome to DockYard!"}} | ||
""" | ||
def put_subject(message, subject), | ||
do: Mail.Message.put_header(message, "subject", subject) | ||
|
@@ -254,15 +278,17 @@ defmodule Mail do | |
Recipients can be added as a single string or a list of strings. | ||
The list of recipients will be concated to the previous value. | ||
Mail.put_to(%Mail.Message{}, "[email protected]") | ||
%Mail.Message{headers: %{to: ["[email protected]"]}} | ||
## Examples | ||
iex> Mail.put_to(%Mail.Message{}, "[email protected]") | ||
%Mail.Message{headers: %{"to" => ["[email protected]"]}} | ||
Mail.put_to(%Mail.Message{}, ["[email protected]", "[email protected]"]) | ||
%Mail.Message{headers: %{to: ["[email protected]", "[email protected]"]}} | ||
iex> Mail.put_to(%Mail.Message{}, ["[email protected]", "[email protected]"]) | ||
%Mail.Message{headers: %{"to" => ["[email protected]", "[email protected]"]}} | ||
Mail.put_to(%Mail.Message{}, "[email protected]") | ||
|> Mail.put_to(["[email protected]", "[email protected]"]) | ||
%Mail.Message{headers: %{to: ["[email protected]", "[email protected]", "[email protected]"]}} | ||
iex> Mail.put_to(%Mail.Message{}, "[email protected]") | ||
iex> |> Mail.put_to(["[email protected]", "[email protected]"]) | ||
%Mail.Message{headers: %{"to" => ["[email protected]", "[email protected]", "[email protected]"]}} | ||
The value of a recipient must conform to either a string value or a tuple with two elements, | ||
otherwise an `ArgumentError` is raised. | ||
|
@@ -294,15 +320,17 @@ defmodule Mail do | |
Recipients can be added as a single string or a list of strings. | ||
The list of recipients will be concated to the previous value. | ||
Mail.put_cc(%Mail.Message{}, "[email protected]") | ||
%Mail.Message{headers: %{cc: ["[email protected]"]}} | ||
## Examples | ||
Mail.put_cc(%Mail.Message{}, ["[email protected]", "[email protected]"]) | ||
%Mail.Message{headers: %{cc: ["one@example.com", "two@example.com"]}} | ||
iex> Mail.put_cc(%Mail.Message{}, "[email protected]") | ||
%Mail.Message{headers: %{"cc" => ["[email protected]"]}} | ||
Mail.put_cc(%Mail.Message{}, "[email protected]") | ||
|> Mail.put_cc(["[email protected]", "[email protected]"]) | ||
%Mail.Message{headers: %{cc: ["[email protected]", "[email protected]", "[email protected]"]}} | ||
iex> Mail.put_cc(%Mail.Message{}, ["[email protected]", "[email protected]"]) | ||
%Mail.Message{headers: %{"cc" => ["[email protected]", "[email protected]"]}} | ||
iex> Mail.put_cc(%Mail.Message{}, "[email protected]") | ||
iex> |> Mail.put_cc(["[email protected]", "[email protected]"]) | ||
%Mail.Message{headers: %{"cc" => ["[email protected]", "[email protected]", "[email protected]"]}} | ||
The value of a recipient must conform to either a string value or a tuple with two elements, | ||
otherwise an `ArgumentError` is raised. | ||
|
@@ -334,15 +362,17 @@ defmodule Mail do | |
Recipients can be added as a single string or a list of strings. | ||
The list of recipients will be concated to the previous value. | ||
Mail.put_bcc(%Mail.Message{}, "[email protected]") | ||
%Mail.Message{headers: %{bcc: ["[email protected]"]}} | ||
## Examples | ||
iex> Mail.put_bcc(%Mail.Message{}, "[email protected]") | ||
%Mail.Message{headers: %{"bcc" => ["[email protected]"]}} | ||
Mail.put_bcc(%Mail.Message{}, ["[email protected]", "[email protected]"]) | ||
%Mail.Message{headers: %{bcc: ["[email protected]", "[email protected]"]}} | ||
iex> Mail.put_bcc(%Mail.Message{}, ["[email protected]", "[email protected]"]) | ||
%Mail.Message{headers: %{"bcc" => ["[email protected]", "[email protected]"]}} | ||
Mail.put_bcc(%Mail.Message{}, "[email protected]") | ||
|> Mail.put_bcc(["[email protected]", "[email protected]"]) | ||
%Mail.Message{headers: %{bcc: ["[email protected]", "[email protected]", "[email protected]"]}} | ||
iex> Mail.put_bcc(%Mail.Message{}, "[email protected]") | ||
iex> |> Mail.put_bcc(["[email protected]", "[email protected]"]) | ||
%Mail.Message{headers: %{"bcc" => ["[email protected]", "[email protected]", "[email protected]"]}} | ||
The value of a recipient must conform to either a string value or a tuple with two elements, | ||
otherwise an `ArgumentError` is raised. | ||
|
@@ -371,8 +401,10 @@ defmodule Mail do | |
@doc """ | ||
Add a new `from` header | ||
Mail.put_from(%Mail.Message{}, "[email protected]") | ||
%Mail.Message{headers: %{from: "[email protected]"}} | ||
## Examples | ||
iex> Mail.put_from(%Mail.Message{}, "[email protected]") | ||
%Mail.Message{headers: %{"from" => "[email protected]"}} | ||
""" | ||
def put_from(message, sender), | ||
do: Mail.Message.put_header(message, "from", sender) | ||
|
@@ -386,8 +418,10 @@ defmodule Mail do | |
@doc """ | ||
Add a new `reply-to` header | ||
Mail.put_reply_to(%Mail.Message{}, "[email protected]") | ||
%Mail.Message{headers: %{reply_to: "[email protected]"}} | ||
## Examples | ||
iex> Mail.put_reply_to(%Mail.Message{}, "[email protected]") | ||
%Mail.Message{headers: %{"reply-to" => "[email protected]"}} | ||
""" | ||
def put_reply_to(message, reply_address), | ||
do: Mail.Message.put_header(message, "reply-to", reply_address) | ||
|
Oops, something went wrong.