immich-app/immich · error · BadRequestException

Failed to verify SMTP configuration

Error message

Failed to verify SMTP configuration

What it means

Before sending a test email, Immich calls emailRepository.verifySmtp(dto.transport) to confirm the SMTP server is reachable and credentials work. If that throws (connection refused, auth failure, TLS handshake error, timeout), the service wraps it into 400 BadRequestException 'Failed to verify SMTP configuration' with the original error as cause, so the admin gets actionable feedback without revealing internal details.

Source

Thrown at server/src/services/notification-admin.service.ts:34

      level: dto.level ?? NotificationLevel.Info,
      title: dto.title,
      description: dto.description,
      data: dto.data,
    });

    return mapNotification(item);
  }

  async sendTestEmail(id: string, dto: SystemConfigSmtpDto, tempTemplate?: string) {
    const user = await this.userRepository.get(id, { withDeleted: false });
    if (!user) {
      throw new Error('User not found');
    }

    try {
      await this.emailRepository.verifySmtp(dto.transport);
    } catch (error) {
      throw new BadRequestException('Failed to verify SMTP configuration', { cause: error });
    }

    const { server } = await this.getConfig({ withCache: false });
    const { html, text } = await this.emailRepository.renderEmail({
      template: EmailTemplate.TEST_EMAIL,
      data: {
        baseUrl: getExternalDomain(server),
        displayName: user.name,
      },
      customTemplate: tempTemplate!,
    });
    const { messageId } = await this.emailRepository.sendEmail({
      to: user.email,
      subject: 'Test email from Immich',
      html,
      text,
      from: dto.from,
      replyTo: dto.replyTo || dto.from,

View on GitHub (pinned to 199723261c)

Solutions

  1. Read error.cause for the SMTP-level message (auth error, ECONNREFUSED, etc.).
  2. Verify host, port, and security mode (SSL/465 vs STARTTLS/587) against your provider's docs.
  3. Use a valid app-specific password (e.g. Gmail/Gmail SMTP app password, not the account password).
  4. Confirm outbound SMTP is allowed from the Immich host/container (test with openssl s_client / swaks).
Defensive patterns

Strategy: try-catch

Validate before calling

// before sending, sanity-check SMTP connectivity
import net from 'net';
await new Promise<void>((resolve, reject) => {
  const socket = net.createConnection({ host: smtp.host, port: smtp.port }, () => {
    socket.end();
    resolve();
  });
  socket.on('error', reject);
  setTimeout(() => reject(new Error('SMTP connect timeout')), 5000);
});

Try / catch

try {
  await adminApi.sendTestEmail(userId, smtpDto);
} catch (e) {
  if (e.status === 400 && /Failed to verify SMTP/.test(e.message)) {
    // inspect e.cause for auth/TLS/connection detail and correct config
  } else throw e;
}

Prevention

When it happens

Trigger: POST admin test-email (or saving SMTP settings) where the configured SMTP transport cannot be reached or rejects the connection: wrong host/port, bad credentials, STARTTLS mismatch, firewall blocking outbound SMTP.

Common situations: Typo in SMTP host; port 465/587 blocked by provider/firewall; username or app-password wrong; SMTP server requires TLS but config has plain; reverse DNS / SPF issues causing rejection.

Related errors


AI-assisted analysis of immich-app/immich@199723261c (2026-08-12). Data as JSON: /api/errors/5d6cb3ddbc75574c. Report an issue: GitHub.