From 3c3a8078fe86eb8d9c7b2c815153409c8ae1c47c Mon Sep 17 00:00:00 2001
From: neo773 <62795688+neo773@users.noreply.github.com>
Date: Fri, 3 Jul 2026 18:23:01 +0530
Subject: [PATCH] fix email alias guard with message channel availibility
(#22521)
---
.../email-alias-manager.module.ts | 3 +-
.../email-alias-manager.service.spec.ts | 38 +++++++++++
.../services/email-alias-manager.service.ts | 63 +++++++++++--------
3 files changed, 77 insertions(+), 27 deletions(-)
diff --git a/packages/twenty-server/src/modules/connected-account/email-alias-manager/email-alias-manager.module.ts b/packages/twenty-server/src/modules/connected-account/email-alias-manager/email-alias-manager.module.ts
index 03ddb6b2b2..dfdc3d2fa7 100644
--- a/packages/twenty-server/src/modules/connected-account/email-alias-manager/email-alias-manager.module.ts
+++ b/packages/twenty-server/src/modules/connected-account/email-alias-manager/email-alias-manager.module.ts
@@ -2,6 +2,7 @@ import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { ConnectedAccountEntity } from 'src/engine/metadata-modules/connected-account/entities/connected-account.entity';
+import { MessageChannelEntity } from 'src/engine/metadata-modules/message-channel/entities/message-channel.entity';
import { GmailEmailAliasErrorHandlerService } from 'src/modules/connected-account/email-alias-manager/drivers/google/services/google-email-alias-error-handler.service';
import { GoogleEmailAliasManagerService } from 'src/modules/connected-account/email-alias-manager/drivers/google/services/google-email-alias-manager.service';
import { MicrosoftEmailAliasManagerService } from 'src/modules/connected-account/email-alias-manager/drivers/microsoft/services/microsoft-email-alias-manager.service';
@@ -11,7 +12,7 @@ import { OAuth2ClientManagerModule } from 'src/modules/connected-account/oauth2-
@Module({
imports: [
OAuth2ClientManagerModule,
- TypeOrmModule.forFeature([ConnectedAccountEntity]),
+ TypeOrmModule.forFeature([ConnectedAccountEntity, MessageChannelEntity]),
],
providers: [
EmailAliasManagerService,
diff --git a/packages/twenty-server/src/modules/connected-account/email-alias-manager/services/email-alias-manager.service.spec.ts b/packages/twenty-server/src/modules/connected-account/email-alias-manager/services/email-alias-manager.service.spec.ts
index 757893c28e..749d2e4a59 100644
--- a/packages/twenty-server/src/modules/connected-account/email-alias-manager/services/email-alias-manager.service.spec.ts
+++ b/packages/twenty-server/src/modules/connected-account/email-alias-manager/services/email-alias-manager.service.spec.ts
@@ -4,6 +4,7 @@ import { getRepositoryToken } from '@nestjs/typeorm';
import { ConnectedAccountProvider } from 'twenty-shared/types';
import { ConnectedAccountEntity } from 'src/engine/metadata-modules/connected-account/entities/connected-account.entity';
+import { MessageChannelEntity } from 'src/engine/metadata-modules/message-channel/entities/message-channel.entity';
import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager';
import { GoogleEmailAliasManagerService } from 'src/modules/connected-account/email-alias-manager/drivers/google/services/google-email-alias-manager.service';
import { microsoftGraphMeResponseWithProxyAddresses } from 'src/modules/connected-account/email-alias-manager/drivers/microsoft/mocks/microsoft-api-examples';
@@ -19,6 +20,13 @@ describe('Email Alias Manager Service', () => {
// @ts-expect-error legacy noImplicitAny
update: jest.fn().mockResolvedValue((arg) => arg),
};
+ const mockMessageChannelRepository = {
+ exists: jest.fn().mockResolvedValue(true),
+ };
+
+ afterEach(() => {
+ jest.clearAllMocks();
+ });
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
@@ -36,6 +44,10 @@ describe('Email Alias Manager Service', () => {
provide: getRepositoryToken(ConnectedAccountEntity),
useValue: mockConnectedAccountRepository,
},
+ {
+ provide: getRepositoryToken(MessageChannelEntity),
+ useValue: mockMessageChannelRepository,
+ },
{
provide: GoogleEmailAliasManagerService,
useValue: {},
@@ -102,4 +114,30 @@ describe('Email Alias Manager Service', () => {
);
});
});
+
+ describe('Refresh handle aliases without a mailbox', () => {
+ it('Should preserve existing aliases and skip the update when the account has no message channel', async () => {
+ mockMessageChannelRepository.exists.mockResolvedValueOnce(false);
+
+ const existingAliases = ['existing@domain.com'];
+ const mockConnectedAccount: Partial = {
+ id: 'test-id',
+ provider: ConnectedAccountProvider.GOOGLE,
+ handleAliases: existingAliases,
+ };
+
+ jest.spyOn(microsoftEmailAliasManagerService, 'getHandleAliases');
+
+ const result = await emailAliasManagerService.refreshHandleAliases(
+ mockConnectedAccount as ConnectedAccountEntity,
+ 'test-workspace-id',
+ );
+
+ expect(result).toEqual(existingAliases);
+ expect(
+ microsoftEmailAliasManagerService.getHandleAliases,
+ ).not.toHaveBeenCalled();
+ expect(mockConnectedAccountRepository.update).not.toHaveBeenCalled();
+ });
+ });
});
diff --git a/packages/twenty-server/src/modules/connected-account/email-alias-manager/services/email-alias-manager.service.ts b/packages/twenty-server/src/modules/connected-account/email-alias-manager/services/email-alias-manager.service.ts
index 16bea3cca8..175b41f9aa 100644
--- a/packages/twenty-server/src/modules/connected-account/email-alias-manager/services/email-alias-manager.service.ts
+++ b/packages/twenty-server/src/modules/connected-account/email-alias-manager/services/email-alias-manager.service.ts
@@ -6,6 +6,7 @@ import { assertUnreachable } from 'twenty-shared/utils';
import { Repository } from 'typeorm';
import { ConnectedAccountEntity } from 'src/engine/metadata-modules/connected-account/entities/connected-account.entity';
+import { MessageChannelEntity } from 'src/engine/metadata-modules/message-channel/entities/message-channel.entity';
import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager';
import { buildSystemAuthContext } from 'src/engine/twenty-orm/utils/build-system-auth-context.util';
import { GoogleEmailAliasManagerService } from 'src/modules/connected-account/email-alias-manager/drivers/google/services/google-email-alias-manager.service';
@@ -19,41 +20,25 @@ export class EmailAliasManagerService {
private readonly globalWorkspaceOrmManager: GlobalWorkspaceOrmManager,
@InjectRepository(ConnectedAccountEntity)
private readonly connectedAccountRepository: Repository,
+ @InjectRepository(MessageChannelEntity)
+ private readonly messageChannelRepository: Repository,
) {}
public async refreshHandleAliases(
connectedAccount: ConnectedAccountEntity,
workspaceId: string,
): Promise {
- let handleAliases: string[];
+ const accountHasMailbox = await this.messageChannelRepository.exists({
+ where: { connectedAccountId: connectedAccount.id, workspaceId },
+ });
- switch (connectedAccount.provider) {
- case ConnectedAccountProvider.MICROSOFT:
- handleAliases =
- await this.microsoftEmailAliasManagerService.getHandleAliases(
- connectedAccount,
- );
- break;
- case ConnectedAccountProvider.GOOGLE:
- handleAliases =
- await this.googleEmailAliasManagerService.getHandleAliases(
- connectedAccount,
- );
- break;
- case ConnectedAccountProvider.IMAP_SMTP_CALDAV:
- case ConnectedAccountProvider.OIDC:
- case ConnectedAccountProvider.SAML:
- case ConnectedAccountProvider.EMAIL_GROUP:
- case ConnectedAccountProvider.APP:
- handleAliases = [];
- break;
- default:
- assertUnreachable(
- connectedAccount.provider,
- `Email alias manager for provider ${connectedAccount.provider} is not implemented`,
- );
+ if (!accountHasMailbox) {
+ return connectedAccount.handleAliases ?? [];
}
+ const handleAliases =
+ await this.getHandleAliasesFromProvider(connectedAccount);
+
const authContext = buildSystemAuthContext(workspaceId);
await this.globalWorkspaceOrmManager.executeInWorkspaceContext(async () => {
@@ -67,4 +52,30 @@ export class EmailAliasManagerService {
return handleAliases;
}
+
+ private async getHandleAliasesFromProvider(
+ connectedAccount: ConnectedAccountEntity,
+ ): Promise {
+ switch (connectedAccount.provider) {
+ case ConnectedAccountProvider.MICROSOFT:
+ return this.microsoftEmailAliasManagerService.getHandleAliases(
+ connectedAccount,
+ );
+ case ConnectedAccountProvider.GOOGLE:
+ return this.googleEmailAliasManagerService.getHandleAliases(
+ connectedAccount,
+ );
+ case ConnectedAccountProvider.IMAP_SMTP_CALDAV:
+ case ConnectedAccountProvider.OIDC:
+ case ConnectedAccountProvider.SAML:
+ case ConnectedAccountProvider.EMAIL_GROUP:
+ case ConnectedAccountProvider.APP:
+ return [];
+ default:
+ return assertUnreachable(
+ connectedAccount.provider,
+ `Email alias manager for provider ${connectedAccount.provider} is not implemented`,
+ );
+ }
+ }
}