elixir-mail
elixir-mail copied to clipboard
Extract address from "to", "from", "cc", etc.
I've run into an issue when using gen_smtp where providing an address that's a tuple or contains a name causes the SMTP server (AWS SES in this case) to return an invalid email error. The fix is to extract the address from the tuple/string with name. I'm curious if introducing something like get_address(message, header) makes sense for this project. I'd expect this to be a common problem for folks.
Here's an example of the problem I'm referring to.
message =
Mail.build()
|> Mail.put_from("Me <[email protected]>")
|> Mail.put_to("You <[email protected]>")
|> Mail.put_subject("Hello, you!")
|> Mail.put_text("Sup")
from = Mail.get_from(message) # returns "Me <[email protected]>"
to = Mail.get_to(message) # returns "You <[email protected]>"
body = Mail.render(message)
:gen_smtp_client({ from, to, body }, config) # returns a 533 invalid address 😵
You can fix the the problem by making both from and to plain addresses instead of the name/address combo. However, the From and To headers now won't contain the name. This puts the burden on the users of mail to figure this out.
My proposal is to provide a get_address/2 function that would provide this functionality.
message =
Mail.build()
|> Mail.put_from("Me <[email protected]>")
|> Mail.put_to("You <[email protected]>")
|> Mail.put_subject("Hello, you!")
|> Mail.put_text("Sup")
from = Mail.get_address(message, :from) # returns "[email protected]"
to = Mail.get_address(message, :to) # returns "[email protected]"
body = Mail.render(message)
:gen_smtp_client({ from, to, body }, config) # it works 🎉
We've implemented something similar in our project and I'd be happy to provide a PR.
Here's what I've put together to solve this problem for us.
defp address([h | t]) do
[address(h)] ++ address(t)
end
defp address([]) do
[]
end
defp address({ _name, address }) do
address
end
defp address(string) when is_binary(string) do
case Regex.run(~r/.+ <(.+)>/, string) do
nil ->
string
[_, address] ->
address
end
end
Digging deeper I found Mail.Parsers.RFC2822.parse_recipient_value/1. We may be able to use this to provide a function that just returns an address.
https://github.com/DockYard/elixir-mail/blob/master/lib/mail/parsers/rfc_2822.ex#L178-L184