Skip to content

fix(emails): copy list and map arguments in CreateEmailOptions builder - #150

Merged
kewynakshlley merged 2 commits into
resend:mainfrom
RaphaelFakhri:fix/create-email-options-defensive-copy
Oct 7, 2026
Merged

kewynakshlley merged 2 commits into
resend:mainfrom
RaphaelFakhri:fix/create-email-options-defensive-copy

Conversation

@RaphaelFakhri

@RaphaelFakhri RaphaelFakhri commented Sep 29, 2026 •

Copy link
Copy Markdown
Contributor

Copies the collection arguments that CreateEmailOptions.Builder receives, so the builder no longer keeps a reference to the caller's list or map.

Problem

to(List<String>), tags(List<Tag>), attachments(List<Attachment>) and headers(Map<String, String>) store the argument as-is. The addTo, addTag, addAttachment and addHeader methods then mutate that same object:

  • With an immutable collection, the follow-up call throws UnsupportedOperationException:

    CreateEmailOptions.builder()
        .to(List.of("a@example.com"))
        .addTo("b@example.com"); // throws
  • With a mutable collection, addTo changes the caller's list, and later changes to the caller's list change the built options.

cc(List), bcc(List) and replyTo(List) already copy the argument, so the four methods behave differently from their siblings.

Solution

Store a copy in each of the four methods. The methods still replace the current value, as before, and null still clears it.

Tests

CreateEmailOptionsTest covers each method with an immutable argument followed by an add* call, and checks that to(List) does not write through to the caller's list. All five tests fail without the change and pass with it.

./gradlew test --tests "com.resend.services.emails.CreateEmailOptionsTest"

The full test task passes.


Summary by cubic

Fixes CreateEmailOptions.Builder storing the caller's to, tags, attachments, and headers collections by reference, so the builder now copies them instead.

Previously, addTo, addTag, addAttachment, and addHeader mutated the caller's collection: an immutable list such as List.of(...) caused UnsupportedOperationException, and a mutable list changed the caller's data. cc, bcc, and replyTo already copied their arguments, so the methods behaved inconsistently.

Adds CreateEmailOptionsTest, which covers immutable arguments followed by add* calls and confirms to(List) doesn't write through to the caller's list.

Written for commit dd70a94. Summary will update on new commits.

View guided diff

@github-actions github-actions Bot added the linear-synced PR has been synced to Linear label Sep 30, 2026
@kewynakshlley

Copy link
Copy Markdown
Collaborator

Thanks for contributing @RaphaelFakhri

@kewynakshlley
kewynakshlley merged commit 5723dd4 into resend:main Oct 7, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

linear-synced PR has been synced to Linear

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants