diff --git a/packages/twenty-server/src/modules/messaging/message-folder-manager/drivers/imap/services/__tests__/imap-get-all-folders.service.spec.ts b/packages/twenty-server/src/modules/messaging/message-folder-manager/drivers/imap/services/__tests__/imap-get-all-folders.service.spec.ts index f9cb244224..285cf6695e 100644 --- a/packages/twenty-server/src/modules/messaging/message-folder-manager/drivers/imap/services/__tests__/imap-get-all-folders.service.spec.ts +++ b/packages/twenty-server/src/modules/messaging/message-folder-manager/drivers/imap/services/__tests__/imap-get-all-folders.service.spec.ts @@ -190,5 +190,46 @@ describe('ImapGetAllFoldersService', () => { ); expect(result.find((f) => f.isSentFolder)).toBeUndefined(); }); + + it.each([['\\Noselect'], ['\\NoSelect'], ['\\NOSELECT'], ['\\noselect']])( + 'should treat %s as non-selectable (RFC 3501 attribute names are case-insensitive)', + async (flagSpelling) => { + const mailboxList = [ + createMockMailbox({ path: 'INBOX' }), + createMockMailbox({ + path: 'Shared Folders', + flags: new Set([flagSpelling]), + }), + createMockMailbox({ + path: 'Shared Folders/team/INBOX', + name: 'INBOX', + parentPath: 'Shared Folders/team', + }), + ]; + + mockImapClient.list.mockResolvedValue(mailboxList); + mockImapClient.status.mockImplementation(async (path: string) => { + if (path === 'Shared Folders') { + throw new Error(`Mailbox doesn't exist: ${path}`); + } + + return { uidValidity: BigInt(1) } as any; + }); + + const result = await service.getAllMessageFolders( + CONNECTED_ACCOUNT, + MESSAGE_CHANNEL, + ); + + expect(mockImapClient.status).not.toHaveBeenCalledWith( + 'Shared Folders', + expect.anything(), + ); + + const paths = result.map((f) => f.externalId?.split(':')[0]); + + expect(paths).not.toContain('Shared Folders'); + }, + ); }); }); diff --git a/packages/twenty-server/src/modules/messaging/message-folder-manager/drivers/imap/services/imap-get-all-folders.service.ts b/packages/twenty-server/src/modules/messaging/message-folder-manager/drivers/imap/services/imap-get-all-folders.service.ts index 669948b68d..975f7d34b5 100644 --- a/packages/twenty-server/src/modules/messaging/message-folder-manager/drivers/imap/services/imap-get-all-folders.service.ts +++ b/packages/twenty-server/src/modules/messaging/message-folder-manager/drivers/imap/services/imap-get-all-folders.service.ts @@ -138,7 +138,21 @@ export class ImapGetAllFoldersService implements MessageFolderDriver { } private isMailboxSelectable(mailbox: ListResponse): boolean { - return !mailbox.flags?.has('\\Noselect'); + // Per RFC 3501, IMAP attribute names are case-insensitive. Different + // servers vary the spelling (Dovecot: \Noselect, Stalwart: \NoSelect), + // so we compare lowercased to avoid attempting SELECT on a virtual + // namespace placeholder, which the server would reject as NONEXISTENT. + if (!mailbox.flags) { + return true; + } + + for (const flag of mailbox.flags) { + if (flag.toLowerCase() === '\\noselect') { + return false; + } + } + + return true; } private isValidMailbox(