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
- Inspect the wrapped %v error for the root cause (dial timeout, refoused, x509, auth).
- Confirm host:port with telnet/openssl s_client from the server running BillionMail.
- Match the port to the encryption mode (465 = implicit TLS, 587 = STARTTLS).
- 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
- Match port to TLS mode: 465 implicit TLS, 587 STARTTLS
- Open firewall egress for the SMTP port from the app server
- Use resolvable internal hostnames when relaying via the local mail service
- Verify credentials with openssl s_client before saving settings
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.