diff --git a/lib/mail.ex b/lib/mail.ex index 1e31359..86bb29e 100644 --- a/lib/mail.ex +++ b/lib/mail.ex @@ -430,8 +430,10 @@ defmodule Mail do iex> Mail.put_from(%Mail.Message{}, "user@example.com") %Mail.Message{headers: %{"from" => "user@example.com"}} """ - def put_from(message, sender), - do: Mail.Message.put_header(message, "from", sender) + def put_from(message, sender) do + validate_recipients([sender]) + Mail.Message.put_header(message, "from", sender) + end @doc ~S""" Retrieves the `from` header @@ -485,9 +487,11 @@ defmodule Mail do defp validate_recipients([recipient | tail]) do case recipient do {name, address} when is_binary(name) and is_binary(address) -> + Mail.Renderers.RFC2822.validate_address(address) validate_recipients(tail) address when is_binary(address) -> + Mail.Renderers.RFC2822.validate_address(address) validate_recipients(tail) other -> diff --git a/lib/mail/renderers/rfc_2822.ex b/lib/mail/renderers/rfc_2822.ex index dc2d442..ce3e4d2 100644 --- a/lib/mail/renderers/rfc_2822.ex +++ b/lib/mail/renderers/rfc_2822.ex @@ -141,7 +141,9 @@ defmodule Mail.Renderers.RFC2822 do defp render_header_value(key, value), do: render_header_value(key, List.wrap(value)) - defp validate_address(address) do + def validate_address(nil), do: raise(ArgumentError, message: "Email address cannot be nil") + + def validate_address(address) do case Regex.match?(@email_validation_regex, address) do true -> address diff --git a/test/mail/renderers/rfc_2822_test.exs b/test/mail/renderers/rfc_2822_test.exs index 932f7d5..4ba42b5 100644 --- a/test/mail/renderers/rfc_2822_test.exs +++ b/test/mail/renderers/rfc_2822_test.exs @@ -106,6 +106,31 @@ defmodule Mail.Renderers.RFC2822Test do assert header == "Bcc: user1@example.com, \"User 2\" " end + ["to", "cc", "bcc", "from", "reply-to"] + |> Enum.each(fn header -> + test "validate address headers (#{header})" do + assert_raise ArgumentError, fn -> + Mail.Renderers.RFC2822.render_header(unquote(header), {"Test User", "@example.com"}) + end + + assert_raise ArgumentError, fn -> + Mail.Renderers.RFC2822.render_header(unquote(header), {"Test User", nil}) + end + + assert_raise ArgumentError, fn -> + Mail.Renderers.RFC2822.render_header(unquote(header), {"Test User", ""}) + end + + assert_raise ArgumentError, fn -> + Mail.Renderers.RFC2822.render_header(unquote(header), {"Test User", "user"}) + end + + assert_raise ArgumentError, fn -> + Mail.Renderers.RFC2822.render_header(unquote(header), {"Test User", nil}) + end + end + end) + test "content-transfer-encoding rendering hyphenates values" do header = Mail.Renderers.RFC2822.render_header("content_transfer_encoding", :quoted_printable) assert header == "Content-Transfer-Encoding: quoted-printable" diff --git a/test/mail_test.exs b/test/mail_test.exs index 4eaa483..b07fd47 100644 --- a/test/mail_test.exs +++ b/test/mail_test.exs @@ -31,6 +31,16 @@ defmodule MailTest do assert Mail.get_to(mail) == ["one@example.com", "two@example.com"] end + test "put_to with invalid address" do + mail = Mail.build() + + assert_raise ArgumentError, fn -> + Mail.put_to(mail, "@example.com") + end + + refute Mail.Message.has_header?(mail, "to") + end + test "composing multiple `to` recipients" do mail = Mail.put_to(Mail.build(), "user@example.com") @@ -60,6 +70,16 @@ defmodule MailTest do assert Mail.get_cc(mail) == ["one@example.com", "two@example.com"] end + test "put_cc with invalid address" do + mail = Mail.build() + + assert_raise ArgumentError, fn -> + Mail.put_cc(mail, "@example.com") + end + + refute Mail.Message.has_header?(mail, "cc") + end + test "composing multiple `cc` recipients" do mail = Mail.put_cc(Mail.build(), "user@example.com") @@ -89,6 +109,16 @@ defmodule MailTest do assert Mail.get_bcc(mail) == ["one@example.com", "two@example.com"] end + test "put_bcc with invalid address" do + mail = Mail.build() + + assert_raise ArgumentError, fn -> + Mail.put_bcc(mail, "@example.com") + end + + refute Mail.Message.has_header?(mail, "bcc") + end + test "composing multiple `bcc` recipients" do mail = Mail.put_bcc(Mail.build(), "user@example.com")