hcengineering/platform · critical

SMTP config is required for custom transporter

Error message

SMTP config is required for custom transporter

What it means

The mail service caches nodemailer transporters per sender/identity (cacheKey). When a cache miss occurs and the request is for a custom (non-default) transporter, a valid smtpConfig must be present to build an SMTP transport; if config.smtpConfig is undefined the service cannot construct the transporter and throws. It is a configuration error, not a transient failure.

Source

Thrown at services/mail/pod-mail/src/mail.ts:81

  getTransporter (email: string, password?: string): Transporter {
    if (config.smtpConfig !== undefined && password != null && password !== '') {
      return this.getCachedTransporter(email, password)
    }
    return this.transporter
  }

  private getCachedTransporter (email: string, password: string): Transporter {
    const cacheKey = this.generateCacheKey(email, password)

    // Check if transporter exists in cache
    const cachedTransporter = this.transporterCache.get(cacheKey)
    if (cachedTransporter !== undefined) {
      return cachedTransporter
    }

    // Create new transporter and cache it
    if (config.smtpConfig === undefined) {
      throw new Error('SMTP config is required for custom transporter')
    }
    const newTransporter = getSmtpTransport(config.smtpConfig, email, password)
    this.transporterCache.set(cacheKey, newTransporter)

    return newTransporter
  }

  private generateCacheKey (email: string, password: string): string {
    const passwordHash = this.generateHash(password)
    return `${email}:${passwordHash}`
  }

  private generateHash (input: string): string {
    return createHash('sha256').update(input).digest('hex')
  }

  close (): void {
    this.transporterCache.clear()

View on GitHub (pinned to 63e28dc964)

Solutions

  1. Provide SMTP configuration (host, port, credentials) to the mail pod via environment/config so config.smtpConfig is defined
  2. Restart/redeploy the pod after adding the SMTP config
  3. If using a default/managed transporter instead, route the send through the default identity rather than a custom one
  4. Check that the code path selecting the custom transporter is intended for this sender

Example fix

// before (env)
// SMTP settings missing
// after (env)
SMTP_HOST=smtp.example.com
SMTP_PORT=587
SMTP_USERNAME=...
SMTP_PASSWORD=...
Defensive patterns

Strategy: validation

Validate before calling

if (config.smtpConfig === undefined) {
  throw new Error('Startup check failed: SMTP config missing for custom transporter')
}

Type guard

function hasSmtpConfig(c: MailConfig): c is MailConfig & { smtpConfig: SmtpConfig } {
  return c.smtpConfig !== undefined && typeof c.smtpConfig.host === 'string' && typeof c.smtpConfig.port === 'number'
}

Try / catch

try {
  await sendEmail(...)
} catch (e) {
  if (e.message.includes('SMTP config is required')) {
    logger.error('SMTP not configured for custom transporter; check SMTP_* env vars')
  } else throw e
}

Prevention

When it happens

Trigger: Calling getTransporter (via getCachedTransporter) with a cache key that maps to a custom SMTP identity while the pod was started without smtpConfig (SMTP_HOST/SMTP_PORT/etc. unset), so the first send after startup fails; cache was cold because the process restarted.

Common situations: Deployed mail pod without SMTP env vars; ops removed SMTP config assuming a managed relay; different configuration between environments (staging had smtpConfig, prod doesn't); transporter cache evicted/restarted process surfacing the previously hidden misconfig.

Related errors


AI-assisted analysis of hcengineering/platform@63e28dc964 (2026-08-29). Data as JSON: /api/errors/9c7756e76ca1ad5f. Report an issue: GitHub.