Skip to content

feat(ui): paste or copy several e-mail addresses into address fields at once#9347

Merged
ChristophWurst merged 1 commit into
nextcloud:mainfrom
arublov:feature/add-several-emails-at-once
May 19, 2026
Merged

feat(ui): paste or copy several e-mail addresses into address fields at once#9347
ChristophWurst merged 1 commit into
nextcloud:mainfrom
arublov:feature/add-several-emails-at-once

Conversation

@arublov
Copy link
Copy Markdown
Member

@arublov arublov commented Feb 15, 2024

Details:

Case 1: string = 'test@test.com, Jane Doe, MSc jane@doe.tld'

Result:
Screenshot 2024-02-23 at 5 36 07 PM

newRecipients:
Screenshot 2024-02-23 at 5 43 48 PM

Case 2: string = 'ian eiloart iane@example.ac.uk>;shuf6@example.ac.uk,, test+user@company.c, "ian,eiloart"<ian@example.ac.uk>, <@example.com:foo@example.ac.uk>, foo@#,ian@-example.com, ian@one@two;asdas< test@test.com> test@test.com, Newasd Na@,me >; testaaaa@aasd.com'

Result:
Screenshot 2024-02-23 at 5 37 12 PM

newRecipients:
Screenshot 2024-02-23 at 5 42 42 PM

@arublov
Copy link
Copy Markdown
Member Author

arublov commented Feb 16, 2024

@ChristophWurst I pushed this last commit into this PR for review, and I'm not sure if it applies to this task or not:

  1. try to add something like this: "Test Test test@test.com, Test Test1 a@rublov.me" I need to compare and then do something?
  2. If this is the string: "Test Test Test test@test.com/ Test Test Test1 a@rublov.me" it's wrong and do I need to do something?

Hint this is relevant to this task, if yes, I will cover these cases with code. If there are more, I will be ready to solve them :)

@arublov arublov marked this pull request as ready for review February 16, 2024 12:55
@arublov arublov force-pushed the feature/add-several-emails-at-once branch from 58dd9b5 to 3887fc8 Compare February 16, 2024 19:53
@arublov
Copy link
Copy Markdown
Member Author

arublov commented Feb 21, 2024

@ChristophWurst any updates here? Thanks :)

@ChristophWurst
Copy link
Copy Markdown
Member

This is a bit of a gamble with the regex. Can you make sure that selecting people with titles doesn't split single values? E.g. if "Jane Doe, MSc jane@doe.tld" is entered, it should stay "Jane Doe, MSc jane@doe.tld", not become "Jane Doe" and ", MSc jane@doe.tld"

@arublov arublov force-pushed the feature/add-several-emails-at-once branch from 3887fc8 to f9da4ce Compare February 21, 2024 13:50
@arublov arublov marked this pull request as draft February 21, 2024 21:19
@arublov arublov force-pushed the feature/add-several-emails-at-once branch 2 times, most recently from 8ca309b to 4adceef Compare February 23, 2024 15:40
@arublov
Copy link
Copy Markdown
Member Author

arublov commented Feb 23, 2024

@ChristophWurst , yes done, I fixed some cases and tested, could you please see the new changes and write me feedback, what do you think about this? Maybe I need to change something in my solution?

P.S. Maybe need to move the regex to another space somewhere, so that it can be accessed in any other classes in the project?

@arublov arublov marked this pull request as ready for review February 23, 2024 16:51
@arublov arublov force-pushed the feature/add-several-emails-at-once branch from 6e9e6a0 to d1c7b42 Compare February 23, 2024 16:51
@arublov
Copy link
Copy Markdown
Member Author

arublov commented Feb 23, 2024

@ChristophWurst I was doing research on this a couple days ago and tried your examples based on thunderbird, gmail and roundcube. So created a more flexible solution based on these apps and my research, so if I need to further improve or change the logic in my solution I will be happy to work on this further :)

Just FYI:

How works Thunderbird:

  1. When string = "Jane Doe, MSc jane@doe.tld; Jane Doe, MSc jane@doe.tld" :
Screenshot 2024-02-21 at 3 05 57 PM
  1. When string = "Jane Doe, MSc jane@doe.tld" :
Screenshot 2024-02-21 at 3 33 15 PM

How works Web Gmail

  1. When string = "Jane Doe, MSc jane@doe.tld; Jane Doe, MSc jane@doe.tld" :
Screenshot 2024-02-21 at 3 14 00 PM
  1. When string = "Jane Doe, MSc jane@doe.tld" :
Screenshot 2024-02-21 at 3 33 38 PM

All of these invalid

Look: rfc822 standard
Look: rfc2822 standard

@arublov arublov self-assigned this Feb 28, 2024
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 3, 2024

Hello there,
Thank you so much for taking the time and effort to create a pull request to our Nextcloud project.

We hope that the review process is going smooth and is helpful for you. We want to ensure your pull request is reviewed to your satisfaction. If you have a moment, our community management team would very much appreciate your feedback on your experience with this PR review process.

Your feedback is valuable to us as we continuously strive to improve our community developer experience. Please take a moment to complete our short survey by clicking on the following link: https://cloud.nextcloud.com/apps/forms/s/i9Ago4EQRZ7TWxjfmeEpPkf6

Thank you for contributing to Nextcloud and we hope to hear from you soon!

@4liceD
Copy link
Copy Markdown

4liceD commented Sep 9, 2025

Is this PR still being worked on? I just found out about it and honestly was surprised that nextcloud doesn't support pasting multiple addresses yet.

@Ephtolens
Copy link
Copy Markdown

Hi !
I'm finding out this PR after trying to put multiple email at once. What's the next step ? Is there a way we can help this PR to succeed ?
Thanks

@Muffexx
Copy link
Copy Markdown

Muffexx commented Feb 25, 2026

I think this feature should get some attention.

As a workaround, I started creating mailto links from my lists of email addresses. This way the email addresses are inserted properly.

@ChristophWurst ChristophWurst force-pushed the feature/add-several-emails-at-once branch from d1c7b42 to 7cc4d25 Compare February 25, 2026 13:35
@ChristophWurst
Copy link
Copy Markdown
Member

Rebased to resolve conflicts

ChristophWurst

This comment was marked as resolved.

Comment thread src/util/emailAddress.js Outdated
Copilot AI review requested due to automatic review settings April 20, 2026 11:04

This comment was marked as outdated.

@ChristophWurst ChristophWurst requested a review from Copilot April 20, 2026 11:27

This comment was marked as outdated.

This comment was marked as low quality.

@ChristophWurst ChristophWurst requested a review from Copilot April 20, 2026 13:16

This comment was marked as low quality.

This comment was marked as low quality.

@ChristophWurst ChristophWurst requested a review from Copilot April 29, 2026 12:15
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 5 comments.

Comment thread src/util/emailAddress.js Outdated
Comment on lines +77 to +78
// Strip trailing delimiters that address-rfc2822 can't handle
const cleaned = str.replace(/[,;]+$/, '').trim()
Copy link

Copilot AI Apr 29, 2026

Choose a reason for hiding this comment

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

The delimiter stripping runs before trim(), so inputs like "alice@example.com, " (comma + trailing space) won’t have the comma removed and can fail parsing. Trim first and then strip delimiters (or expand the regex to include trailing whitespace) so common paste/typing patterns work reliably.

Suggested change
// Strip trailing delimiters that address-rfc2822 can't handle
const cleaned = str.replace(/[,;]+$/, '').trim()
// Trim first so trailing delimiters followed by whitespace are still removed
const cleaned = str.trim().replace(/[,;]+$/, '').trim()

Copilot uses AI. Check for mistakes.
Comment on lines +1482 to +1489
for (const addr of parsedFromSearch) {
if (!list.some((recipient) => recipient.email === addr.email)) {
const recipient = { ...addr }
this.newRecipients.push(recipient)
list.push(recipient)
changed = true
}
}
Copy link

Copilot AI Apr 29, 2026

Choose a reason for hiding this comment

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

De-duplication compares recipient.email === addr.email (case-sensitive). This can allow duplicates for the same address pasted with different casing (pretty common when copying from different sources). Consider comparing on a canonical form (e.g., email.toLowerCase() at least for the domain part, or entirely lowercased if that matches existing app behavior) to avoid duplicate recipients.

Copilot uses AI. Check for mistakes.
Comment on lines +1482 to +1489
for (const addr of parsedFromSearch) {
if (!list.some((recipient) => recipient.email === addr.email)) {
const recipient = { ...addr }
this.newRecipients.push(recipient)
list.push(recipient)
changed = true
}
}
Copy link

Copilot AI Apr 29, 2026

Choose a reason for hiding this comment

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

list.some(...) is called for each parsed address, making this O(n*m) as recipients grow. Using a Set of existing emails (and updating it as you add) would make de-dup checks O(1) and keep recipient addition snappy for large pastes.

Copilot uses AI. Check for mistakes.
Comment thread src/components/Composer.vue Outdated
Comment on lines 1690 to 1693
if (parseEmailList(value).length === 0) {
throw new Error('Skipping because it does not look like a valid email address')
}
return { email: value, label: value }
Copy link

Copilot AI Apr 29, 2026

Choose a reason for hiding this comment

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

createRecipientOption now accepts values that parse into one or more addresses, but it returns { email: value, label: value } even if value contains multiple addresses and/or invalid tokens. This can create confusing transient UI labels (the chip/option may display the entire pasted blob). Consider normalizing the returned label/email (e.g., trimming) and/or handling multi-address pastes as a distinct path so the created option better matches what will actually be added.

Suggested change
if (parseEmailList(value).length === 0) {
throw new Error('Skipping because it does not look like a valid email address')
}
return { email: value, label: value }
const parsedRecipients = parseEmailList(value)
if (parsedRecipients.length === 0) {
throw new Error('Skipping because it does not look like a valid email address')
}
const firstRecipient = parsedRecipients[0]
const normalizedValue = (typeof firstRecipient === 'string'
? firstRecipient
: firstRecipient.email || firstRecipient.address || firstRecipient.label || firstRecipient.name || value
).trim()
return { email: normalizedValue, label: normalizedValue }

Copilot uses AI. Check for mistakes.
Comment thread src/util/emailAddress.js Outdated
}

// Strip trailing delimiters that address-rfc2822 can't handle
const cleaned = str.replace(/[,;]+$/, '').trim()
Copy link

Copilot AI Apr 29, 2026

Choose a reason for hiding this comment

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

There’s no unit test covering trailing delimiters with trailing whitespace (e.g., 'alice@example.com, ' or 'alice@example.com; '), which is a common paste/typing pattern and currently fails due to the replace() happening before trim(). Add a regression test for this case alongside the existing trailing delimiter tests.

Suggested change
const cleaned = str.replace(/[,;]+$/, '').trim()
const cleaned = str.trim().replace(/[,;]+$/, '').trim()

Copilot uses AI. Check for mistakes.
@ChristophWurst
Copy link
Copy Markdown
Member

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 13, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 13, 2026

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 552532c2-caeb-4905-bf5f-c3d2b83f7219

📥 Commits

Reviewing files that changed from the base of the PR and between 4bc6fcb and 95f27be.

📒 Files selected for processing (1)
  • src/components/Composer.vue
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/components/Composer.vue

📝 Walkthrough

Walkthrough

This PR adds src/util/emailAddress.js with tryParse, splitOnDelimiters, getLabelAndAddress, and parseEmailList to parse single and comma/semicolon-separated address lists (respecting quoted names and angle-brackets). It adds unit tests for those functions (including issue #6013 regressions) and updates src/components/Composer.vue to use parseEmailList for recipient handling: clearOnBlur, createRecipientOption, and onNewAddr now support multi-address typed/pasted inputs, deduplicate case-insensitively, and only persist drafts when new recipients are added.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title '[Feature] #9298 : Add several e-mail addresses into address fields at once' directly matches the PR's main objective of enabling multiple email addresses to be parsed and added as separate recipients.
Description check ✅ Passed The description relates to the PR by demonstrating the feature implementation with two concrete test cases showing email parsing behavior with complex inputs and screenshots of parsed results.
Linked Issues check ✅ Passed The PR successfully implements the requirement from issue #6013 by parsing pasted email lists into separate recipient entries through new parseEmailList() and getLabelAndAddress() functions and refactored Composer.vue logic.
Out of Scope Changes check ✅ Passed All changes are focused on email list parsing: new utility module, comprehensive unit tests, and Composer refactoring to use the new parsing logic—directly aligned with issue #6013 requirements.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Comment @coderabbitai help to get the list of available commands and usage tips.

coderabbitai[bot]

This comment was marked as outdated.

coderabbitai[bot]

This comment was marked as outdated.

@ChristophWurst
Copy link
Copy Markdown
Member

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 19, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@ChristophWurst
Copy link
Copy Markdown
Member

This works well now. If there are no major issues found we can merge it.

@ChristophWurst ChristophWurst force-pushed the feature/add-several-emails-at-once branch 2 times, most recently from 1b4f3d4 to e4e5f2d Compare May 19, 2026 11:58
Copy link
Copy Markdown
Member

@ChristophWurst ChristophWurst left a comment

Choose a reason for hiding this comment

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

Tested, cleaned-up and works 👍

…at once

Signed-off-by: Andrii Rublov <airublev@outlook.com>
@ChristophWurst ChristophWurst force-pushed the feature/add-several-emails-at-once branch from e4e5f2d to 98f6282 Compare May 19, 2026 11:59
@ChristophWurst ChristophWurst merged commit 34d8036 into nextcloud:main May 19, 2026
45 checks passed
@ChristophWurst ChristophWurst changed the title [Feature] #9298 : Add several e-mail addresses into address fields at once feat(ui): paste or copy several e-mail addresses into address fields at once May 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Ability to paste list of email

7 participants