Billionmail/BillionMail · error

failed to connect to SMTP server: %v

Error message

failed to connect to SMTP server: %v

What it means

sendAlertEmail builds an SMTP sender from the alert settings (host, port, sender email, password) and calls sender.Connect(); a failed connection is wrapped as 'failed to connect to SMTP server: %v'. This is a transport-level failure reaching/authenticating the TCP SMTP endpoint before any message is sent.

Source

Thrown at core/internal/service/domains/blacklist.go:485

	if err != nil {
		return nil, fmt.Errorf("failed to parse alert settings: %v", err)
	}

	return &settings, nil
}

func sendAlertEmail(ctx context.Context, settings *BlacklistAlertSettings, subject, body string) error {

	sender := mail_service.NewEmailSender()
	sender.Host = settings.SMTPServer
	sender.Port = fmt.Sprintf("%d", settings.SMTPPort)
	sender.Email = settings.SenderEmail
	sender.UserName = settings.SenderEmail
	sender.Password = settings.SMTPPassword

	err := sender.Connect()
	if err != nil {
		return fmt.Errorf("failed to connect to SMTP server: %v", err)
	}
	defer sender.Close()

	var failedRecipients []string
	for _, recipient := range settings.RecipientList {

		message := mail_service.NewMessage(subject, body)
		message.SetRealName(settings.Name)
		messageId := sender.GenerateMessageID()
		message.SetMessageID(messageId)

		err = sender.Send(message, []string{recipient})
		if err != nil {
			g.Log().Errorf(ctx, "Failed to send alert email to %s: %v", recipient, err)
			failedRecipients = append(failedRecipients, recipient)
		} else {
			g.Log().Infof(ctx, "Alert email sent successfully to %s", recipient)
		}

View on GitHub (pinned to fc36c76c05)

Solutions

  1. Test connectivity from the server: nc -vz <smtp-host> <port> or openssl s_client -connect host:port -starttls smtp
  2. Confirm host/port/encryption mode match the provider (465=implicit TLS, 587=STARTTLS, 25=relay)
  3. Re-enter the SMTP username/password in alert settings to rule out stored-credential typos
  4. Check firewall/security-group egress rules for the SMTP port and verify the local Postfix service if using localhost

Example fix

// before
err := sender.Connect()
if err != nil {
	return fmt.Errorf("failed to connect to SMTP server: %v", err)
}
// after
err := sender.Connect()
if err != nil {
	return fmt.Errorf("failed to connect to SMTP server %s:%d as %s: %v", settings.SMTPHost, settings.SMTPPort, settings.SenderEmail, err)
}
Defensive patterns

Strategy: try-catch

Validate before calling

// verify reachability and credentials before triggering alerts
conn, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%d", settings.SMTPHost, settings.SMTPPort), 5*time.Second)
if err != nil {
	return fmt.Errorf("SMTP host %s:%d unreachable", settings.SMTPHost, settings.SMTPPort)
}
conn.Close()

Type guard

func smtpSettingsUsable(s *BlacklistAlertSettings) bool {
	return s.SMTPHost != "" && s.SMTPPort > 0 && s.SenderEmail != "" && s.SMTPPassword != ""
}

Try / catch

err := sendAlertEmail(ctx, settings, subject, body)
if err != nil && strings.Contains(err.Error(), "failed to connect to SMTP server") {
	// transport failure: check host/port/TLS mode and queue or retry later
}

Prevention

When it happens

Trigger: Called from sendBlacklistAlert when: the configured SMTP host is wrong or unreachable, the port is blocked by a firewall, TLS negotiation fails, credentials are rejected during connect/handshake, or DNS for the SMTP host fails.

Common situations: Using port 465 (implicit TLS) with a client expecting STARTTLS on 587 or vice versa; password with special characters mis-stored; outbound port 25/465/587 blocked by cloud provider; SMTP relay requires auth the settings lack; internal mail server (Postfix) not running.

Related errors


AI-assisted analysis of Billionmail/BillionMail@fc36c76c05 (2026-09-05). Data as JSON: /api/errors/45f6627d18b69393. Report an issue: GitHub.