Billionmail/BillionMail · error

failed to connect to SMTP server: %v

Error message

failed to connect to SMTP server: %v

What it means

sendTestEmailWithMailService builds an SMTP sender from the submitted settings and calls sender.Connect(); any connection error is wrapped as 'failed to connect to SMTP server'. This happens before any email is sent — it is a TCP/TLS/handshake-level failure.

Source

Thrown at core/internal/controller/settings/settings_v1_set_blacklist_alert_settings.go:133

	return nil
}

func sendTestEmailWithMailService(ctx context.Context, settings *v1.SetBlacklistAlertSettingsReq) error {
	//g.Log().Infof(ctx, "Sending test email to %v", settings.RecipientList)

	subject := "Blacklist Alert Test - BillionMail"
	body := buildTestEmailHTML(settings)

	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 test email to %s: %v", recipient, err)
			failedRecipients = append(failedRecipients, recipient)
		} else {
			g.Log().Infof(ctx, "Test email sent successfully to %s", recipient)
		}

View on GitHub (pinned to fc36c76c05)

Solutions

  1. Inspect the wrapped %v error for the root cause (dial timeout, refoused, x509, auth).
  2. Confirm host:port with telnet/openssl s_client from the server running BillionMail.
  3. Match the port to the encryption mode (465 = implicit TLS, 587 = STARTTLS).
  4. If sending via the local mail service, point SMTPServer at the internal hostname (e.g. the mail container) instead of an external relay.

Example fix

// before
{"smtpServer":"smtp.example.com","smtpPort":25} // blocked by provider
// after
{"smtpServer":"smtp.example.com","smtpPort":587}
Defensive patterns

Strategy: retry

Validate before calling

// dial check before saving
conn, err := net.DialTimeout("tcp", net.JoinHostPort(smtpServer, strconv.Itoa(smtpPort)), 5*time.Second)
if err != nil { return fmt.Errorf("SMTP server unreachable: %w", err) }
conn.Close()

Try / catch

if err := SetBlacklistAlertSettings(ctx, req); err != nil {
  var netErr net.Error
  if errors.As(err, &netErr) || strings.Contains(err.Error(), "failed to connect") {
    // transient? retry with backoff; otherwise surface host/port guidance
  }
}

Prevention

When it happens

Trigger: SetBlacklistAlertSettings (non-relay test path) where sender.Connect() fails: wrong SMTPServer host, wrong SMTPPort, server unreachable, TLS handshake failure, or auth rejection at connect time.

Common situations: Firewall/egress rules block the port; DNS cannot resolve the host; server expects implicit TLS on 465 but code uses STARTTLS on 587 (or vice versa); credentials wrong so the server drops the session.

Related errors


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