Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extract address from "to", "from", "cc", etc. #114

Open
anthonator opened this issue Feb 5, 2020 · 2 comments
Open

Extract address from "to", "from", "cc", etc. #114

anthonator opened this issue Feb 5, 2020 · 2 comments

Comments

@anthonator
Copy link
Contributor

anthonator commented Feb 5, 2020

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.

@anthonator
Copy link
Contributor Author

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

@anthonator
Copy link
Contributor Author

anthonator commented Feb 6, 2020

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant