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

WIP: Allow multiple header values for the same key #472

Closed
wants to merge 1 commit into from

Conversation

lancejjohnson
Copy link
Contributor

The Email struct can have multiple values added for the same name. This
commit updates the put_header function on the Email module by allowing
header values to be added as a list and combining multiple values for
the same name into lists. The Mailer module also has a function to
normalize those headers into a list of two element tuples to can be sent
to the http client library based on the strategy elected by the caller.

Resolves #469, #343, #360

@lancejjohnson lancejjohnson changed the title Allow multiple header values for the same key WIP: Allow multiple header values for the same key Apr 8, 2019
Copy link
Contributor

@maymillerricci maymillerricci left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I took a glance through this and overall it looks good, and I like the idea of the optional :combine key that can be used if needed but otherwise the default behavior remains. I'm curious about the options for normalize_headers - is the idea that different adapters will require the multiple headers to come in different ways, and so we need to allow for the different ways of normalizing them? If so, I find myself wondering whether maybe this is trying to do too much at once, and can we introduce this with maybe the base strategy, which would resolve a certain set of cases, and then follow up with the other strategy? I don't have the full context though and not sure how this ties in with the individual adapters so not totally sure. 😄 Thanks for starting to tackle this - this is a hard problem!

README.md Outdated Show resolved Hide resolved
README.md Show resolved Hide resolved
Copy link
Contributor

@jutonz jutonz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Couple of random little questions, but overall this looks great! Nice work 🎉


def normalize_headers(%{headers: headers}, :csv) do
Enum.reduce(headers, [], fn
{header_key, [_ | _] = header_value}, normalized ->
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It always takes me a second to grok [_ | _] matches--would it be possible to use a guard here instead? Maybe something like this

{header_key, header_value}, normalized when is_list(header_value) ->
   # ...
{header_key, header_value}, normalized ->
   # ...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[_ | _] is actually a pattern match for a non-empty list. To use guards in that case would require

{header_key, header_value}, normalized when is_list(header_value) and length(header_value) > 0 -> 
  # ...

My personal preference is the pattern match. Do you think the guard clause is an improvement?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a good point. Do we need to differentiate between empty and non-empty lists? I think currently if you passed an empty list, it'd fall to the second function definition (which expects an atom or a string), and would eventually result in some other error. On the other hand, if we just looked for a list (and didn't care whether it was empty or not), the worse we'd end up doing is Enum.join([], ", "), which would just be an empty string.

At a somewhat higher level, I'm not sure whether put_header("my-header", []) is a valid operation or not. I kinda feel like it's not, but I think we should probably leave that up to the developer and treat it the same as we would put_header("my-header", ""). What do you think?

lib/bamboo/mailer.ex Outdated Show resolved Hide resolved
lib/bamboo/mailer.ex Show resolved Hide resolved
test/lib/bamboo/email_test.exs Outdated Show resolved Hide resolved
test/lib/bamboo/email_test.exs Show resolved Hide resolved
README.md Outdated Show resolved Hide resolved
The Email struct can have multiple values added for the same name. This
commit updates the `put_header` function on the Email module by allowing
header values to be added as a list and combining multiple values for
the same name into lists. The Mailer module also has a function to
normalize those headers into a list of two element tuples to can be sent
to the http client library based on the strategy elected by the caller.

Resolves #469, #343, #360
@maymillerricci
Copy link
Contributor

@lancejjohnson Was there more you wanted to do here, or is it ready to merge? (It is marked WIP but looks like you addressed most of the feedback I think?)

Copy link
Collaborator

@germsvel germsvel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @lancejjohnson 👋 , what do you think is the status of this PR?

I see that we're allowing users to set multiple headers, but how do we translate those for each adapter? Do we have a default that can work for adapters or is that work that we need to add to this PR?

Thanks for trying to handle this. I know it's a big one.

separated string. Passing `:list` as the second argument, however, produces a
distinct tuple for every value in the header value list.
"""
def normalize_headers(%{headers: _} = email) do
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we be calling this function from validate_and_normalize in line 185 from which we callnormalize_addresses?

As it stands, we've given users the ability to set different types of headers, but they have to explicitly call normalize_headers/2? Is there a default we could call? Or does the user need to determine how they send headers?

@germsvel
Copy link
Collaborator

This PR seems to have stalled.

Since I think there's more work to be done here, and this can't be merged as is (and if you don't mind @lancejjohnson), I'm going to close this so it doesn't look as though it's ready to go.

If we ever loop back here, feel free to reopen and we can get this merged in.

@germsvel germsvel closed this Jun 25, 2021
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

Successfully merging this pull request may close these issues.

Allow mutliple headers with the same key
4 participants