fix(email): make the "Move to" context menu work across accounts

Moving a message to a folder in another account (own ↔ delegated/shared) via the
"Move to" context menu was a no-op — the handlers always issued a single-account
Email/set, which can't move between JMAP accounts. Drag-and-drop already routed
these correctly; the context menu never did.

Add moveToMailboxCrossAware: it detects a cross-account destination (own and
shared mailboxes both carry accountId) and routes through the drag-and-drop
crossAccountMoveEmails pipeline, else falls back to the single-account move.

Fix the pipeline for delegated folders too: a client can't stage a blob in a
delegated account (Blob/upload → blobNotFound), so importing into a shared folder
failed. When one client reaches both accounts, use a server-side JMAP Email/copy
(+ destroy original) instead of blob copy+import; the blob path is kept only for
separate cross-server login accounts. Adds client.copyEmailAcrossAccounts.

Unit tests for the dispatch; the two 08-shared-moves specs are un-pinned. Full
docker integration suite green (37 passed).
This commit is contained in:
Stefan Hildebrandt
2026-07-24 18:30:50 +02:00
parent fc116a8b2f
commit 15ad783848
7 changed files with 234 additions and 12 deletions
+3 -2
View File
@@ -282,6 +282,7 @@ export default function Home() {
toggleStar,
setEmailKeywordsLocal,
moveToMailbox,
moveToMailboxCrossAware,
moveThreadToMailbox,
searchEmails,
searchQuery,
@@ -3229,7 +3230,7 @@ export default function Home() {
}}
onMoveToMailbox={async (emailId, mailboxId) => {
if (client) {
await moveToMailbox(client, emailId, mailboxId);
await moveToMailboxCrossAware(client, emailId, mailboxId);
}
}}
onMarkAsSpam={async (email) => {
@@ -3499,7 +3500,7 @@ export default function Home() {
selectedMailbox={selectedMailbox}
onMoveToMailbox={async (mailboxId) => {
if (client && selectedEmail) {
await moveToMailbox(client, selectedEmail.id, mailboxId);
await moveToMailboxCrossAware(client, selectedEmail.id, mailboxId);
}
}}
className={isMobile ? "flex-1" : undefined}