fix(messaging): honor IMAP/SMTP encryption setting instead of inferring it from the port (#21562)

This pull request makes the IMAP and SMTP encryption setting actually
honor what the user selects.

As per spec there's 3 modes: SSL/TLS (implicit TLS from the start),
STARTTLS (it will attempt TLS but if the server doesn't support it, it
gracefully falls back to plaintext), NONE (plaintext)

Current implementation had a boolean flag for this, this replaces it
with the 3 modes

Upgrade command to migrate all existing accounts, to not risk breaking
anyone's existing account in production we map each account to the mode
that matches its current behavior, so nothing changes on the wire

/closes #21300

<!-- This is an auto-generated description by cubic. -->
<a
href="https://cubic.dev/pr/twentyhq/twenty/pull/21562?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>
<!-- End of auto-generated description by cubic. -->

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
neo773
2026-06-16 21:39:04 +05:30
committed by GitHub
parent ff03e935ef
commit d8d5991977
33 changed files with 943 additions and 487 deletions
@@ -0,0 +1,65 @@
import { DataSource, QueryRunner } from 'typeorm';
import { RegisteredInstanceCommand } from 'src/engine/core-modules/upgrade/decorators/registered-instance-command.decorator';
import { SlowInstanceCommand } from 'src/engine/core-modules/upgrade/interfaces/slow-instance-command.interface';
// Replaces the legacy `secure` boolean with the `connectionSecurity` enum,
// preserving the previously deployed on-wire behavior exactly. SMTP used
// implicit TLS on port 465 (-> SSL_TLS) and opportunistic STARTTLS elsewhere
// (-> STARTTLS); IMAP used implicit TLS when secure (-> SSL_TLS) and
// opportunistic STARTTLS otherwise (-> STARTTLS); CalDAV is TLS over its https
// host (-> SSL_TLS). STARTTLS stays opportunistic so no account is forced onto
// a stricter handshake than it already used.
@RegisteredInstanceCommand('2.15.0', 1781461753981, { type: 'slow' })
export class BackfillConnectionSecuritySlowInstanceCommand
implements SlowInstanceCommand
{
async runDataMigration(dataSource: DataSource): Promise<void> {
await dataSource.query(
`UPDATE "core"."connectedAccount"
SET "connectionParameters" = jsonb_set(
"connectionParameters" #- '{SMTP,secure}',
'{SMTP,connectionSecurity}',
to_jsonb(
CASE WHEN "connectionParameters"->'SMTP'->>'port' = '465'
THEN 'SSL_TLS' ELSE 'STARTTLS' END
)
)
WHERE "connectionParameters" ? 'SMTP'
AND NOT "connectionParameters"->'SMTP' ? 'connectionSecurity'`,
);
await dataSource.query(
`UPDATE "core"."connectedAccount"
SET "connectionParameters" = jsonb_set(
"connectionParameters" #- '{IMAP,secure}',
'{IMAP,connectionSecurity}',
to_jsonb(
CASE WHEN "connectionParameters"->'IMAP'->>'secure' = 'false'
THEN 'STARTTLS' ELSE 'SSL_TLS' END
)
)
WHERE "connectionParameters" ? 'IMAP'
AND NOT "connectionParameters"->'IMAP' ? 'connectionSecurity'`,
);
await dataSource.query(
`UPDATE "core"."connectedAccount"
SET "connectionParameters" = jsonb_set(
"connectionParameters" #- '{CALDAV,secure}',
'{CALDAV,connectionSecurity}',
to_jsonb('SSL_TLS'::text)
)
WHERE "connectionParameters" ? 'CALDAV'
AND NOT "connectionParameters"->'CALDAV' ? 'connectionSecurity'`,
);
}
public async up(_queryRunner: QueryRunner): Promise<void> {
return;
}
public async down(_queryRunner: QueryRunner): Promise<void> {
return;
}
}
@@ -70,6 +70,7 @@ import { RenameIsUiReadOnlyToIsUiEditableFastInstanceCommand } from 'src/databas
import { BackfillNonUiCreatableStandardSystemObjectsSlowInstanceCommand } from 'src/database/commands/upgrade-version-command/2-13/2-13-instance-command-slow-1781277480000-backfill-non-ui-creatable-standard-system-objects';
import { CommandMenuItemOverridableEntityFastInstanceCommand } from 'src/database/commands/upgrade-version-command/2-13/2-13-instance-command-fast-1781253016028-command-menu-item-overridable-entity';
import { SetTableWidgetViewsVisibilityToWorkspaceSlowInstanceCommand } from 'src/database/commands/upgrade-version-command/2-14/2-14-instance-command-slow-1781515653781-set-table-widget-views-visibility-to-workspace';
import { BackfillConnectionSecuritySlowInstanceCommand } from 'src/database/commands/upgrade-version-command/2-15/2-15-instance-command-slow-1781461753981-backfill-connection-security';
export const INSTANCE_COMMANDS = [
AddViewFieldGroupIdIndexOnViewFieldFastInstanceCommand,
@@ -142,4 +143,5 @@ export const INSTANCE_COMMANDS = [
BackfillNonUiCreatableStandardSystemObjectsSlowInstanceCommand,
CommandMenuItemOverridableEntityFastInstanceCommand,
SetTableWidgetViewsVisibilityToWorkspaceSlowInstanceCommand,
BackfillConnectionSecuritySlowInstanceCommand,
];