fix(07): SMTP test warns when connection passes but no auth configured
Tessera CI/CD / Lint & Type Check (push) Waiting to run
Tessera CI/CD / Tests (push) Blocked by required conditions
Tessera CI/CD / Build & Deploy (push) Blocked by required conditions

Server reachable without credentials (port 25 open relay) returns
{ success: true, warning: 'no_auth' } instead of green success.
Frontend shows red warning: server reachable but emails will fail.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-28 01:29:53 +02:00
parent 853095faef
commit 4de87a8ea2
5 changed files with 22 additions and 13 deletions
+1 -2
View File
@@ -73,7 +73,6 @@ export class SettingsController {
throw new BadRequestException('No tenant context');
}
const success = await this.settingsService.testSmtpConfig(tenantId, dto);
return { success };
return this.settingsService.testSmtpConfig(tenantId, dto);
}
}
+15 -8
View File
@@ -122,14 +122,14 @@ export class SettingsService {
*
* T-07-16: Returns only a boolean — no credentials or transport details in the response.
*/
async testSmtpConfig(tenantId: string, dto: SmtpConfigDto): Promise<boolean> {
async testSmtpConfig(
tenantId: string,
dto: SmtpConfigDto,
): Promise<{ success: boolean; warning?: string }> {
let password: string | undefined = dto.password;
let username: string | undefined = dto.username;
// Fall back to stored credentials for anything not provided in the DTO.
// The form never pre-fills the password field (T-07-17), so we always
// need to load it from storage. Username may also be absent if the form
// field was cleared, so load it too.
// Fall back to stored credentials (form never pre-fills password — T-07-17)
if (!password || !username) {
const stored = await this.getDecryptedSmtpConfig(tenantId);
if (stored) {
@@ -138,6 +138,8 @@ export class SettingsService {
}
}
const hasAuth = !!(username && password);
try {
const transport = nodemailer.createTransport({
host: dto.host,
@@ -153,13 +155,18 @@ export class SettingsService {
});
await transport.verify();
return true;
// T-07-16: connection passed but warn when no auth — server reachable but
// unauthenticated relay will likely be rejected when actually sending.
if (!hasAuth) {
return { success: true, warning: 'no_auth' };
}
return { success: true };
} catch (error) {
// T-07-16: Log only generic message, never credentials
this.logger.warn(
`SMTP connection test failed for tenant ${tenantId}: ${(error as Error).message}`,
);
return false;
return { success: false };
}
}