{"record":{"id":"5fafb67309e9b5ae","repo":"Billionmail/BillionMail","slug":"new-smtp-client-w","errorCode":null,"errorMessage":"new SMTP client: %w","messagePattern":"new SMTP client: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/internal/service/mail_service/sending.go","lineNumber":220,"sourceCode":"\te.connected = true\n\treturn nil\n}\n\n// connectWithSSL establishes a secure SMTP connection\nfunc (e *EmailSender) connectWithSSL() error {\n\tconn, err := tls.Dial(\"tcp\", net.JoinHostPort(e.Host, e.Port), &tls.Config{\n\t\tMinVersion:         tls.VersionTLS12,\n\t\tInsecureSkipVerify: true,\n\t\tServerName:         e.SNI,\n\t})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"TLS dial: %w\", err)\n\t}\n\n\tclient, err := smtp.NewClient(conn, e.Host)\n\tif err != nil {\n\t\tconn.Close()\n\t\treturn fmt.Errorf(\"new SMTP client: %w\", err)\n\t}\n\n\tauth := smtp.PlainAuth(\"\", e.UserName, e.Password, e.Host)\n\tif err = client.Auth(auth); err != nil {\n\t\tclient.Close()\n\t\treturn fmt.Errorf(\"SMTP auth: %w\", err)\n\t}\n\n\te.client = client\n\n\treturn nil\n}\n\n// connectPlain establishes a plain SMTP connection\nfunc (e *EmailSender) connectPlain() error {\n\tclient, err := smtp.Dial(net.JoinHostPort(e.Host, e.Port))\n\tif err != nil {\n\t\treturn fmt.Errorf(\"SMTP dial: %w\", err)","sourceCodeStart":202,"sourceCodeEnd":238,"githubUrl":"https://github.com/Billionmail/BillionMail/blob/fc36c76c050c3775c5e899faf7403cf0262d2744/core/internal/service/mail_service/sending.go#L202-L238","documentation":"This error is returned when smtp.NewClient(conn, e.Host) fails after the TLS connection was established. NewClient reads the server greeting (220 banner); it errors if the connection was closed, the greeting is malformed, or the peer is not an SMTP server. The code closes conn before returning to avoid leaking the socket.","triggerScenarios":"connectWithSSL is called (Connect on a secure sender), tls.Dial succeeds, but the server does not send a valid SMTP 220 greeting — e.g. the port hosts HTTP, a non-SMTP TLS service, or a proxy that closes the connection.","commonSituations":"Pointing the client at port 443/993/other TLS service that is not SMTP; a TLS-terminating proxy (HAProxy/nginx) accepting the handshake but closing the backend; server greeting delayed past a timeout causing EOF; connecting implicit-TLS to port 587 so the plain banner arrives corrupted by TLS framing.","solutions":["Confirm the port speaks SMTPS (usually 465); test with openssl s_client -connect host:port and check the banner starts with '220'.","If the server only supports STARTTLS, switch the sender to the plain path (port 587) instead of implicit SSL.","Inspect the wrapped error (errors.Unwrap) — 'EOF' usually means the peer closed immediately; a protocol error means it is not SMTP.","Check TLS-terminating middleboxes/proxies and ensure they pass through to the SMTP backend."],"exampleFix":"// before\nclient, err := smtp.NewClient(conn, e.Host)\n// after\nclient, err := smtp.NewClient(conn, e.Host)\nif err != nil {\n    conn.Close()\n    return fmt.Errorf(\"new SMTP client for %s: %w (is port %s really SMTPS?)\", e.Host, err, e.Port)\n}","handlingStrategy":"validation","validationCode":"func verifySMTPSBanner(host, port string) error {\n    conn, err := tls.DialWithDialer(&net.Dialer{Timeout: 5 * time.Second}, \"tcp\", net.JoinHostPort(host, port), &tls.Config{ServerName: host})\n    if err != nil {\n        return err\n    }\n    defer conn.Close()\n    buf := make([]byte, 256)\n    conn.SetReadDeadline(time.Now().Add(5 * time.Second))\n    n, err := conn.Read(buf)\n    if err != nil || n < 3 || string(buf[:3]) != \"220\" {\n        return fmt.Errorf(\"not an SMTPS endpoint (greeting: %q)\", buf[:n])\n    }\n    return nil\n}","typeGuard":"func isNotSMTPPeer(err error) bool {\n    var protoErr *textproto.Error\n    return errors.Is(err, io.EOF) || errors.As(err, &protoErr)\n}","tryCatchPattern":"if err := sender.Send(msg, rcpts); err != nil {\n    if strings.Contains(err.Error(), \"new SMTP client\") {\n        // peer greeted incorrectly: verify port/protocol, then alert ops\n        log.Printf(\"endpoint %s:%s is not speaking SMTPS\", host, port)\n    }\n}","preventionTips":["Only use implicit TLS against ports that actually speak SMTPS (465).","Verify with openssl s_client that the banner begins with 220 before configuring.","Avoid pointing the sender at TLS-terminating proxies that do not proxy raw SMTP."],"tags":["smtp","tls","protocol"],"backgroundTag":"smtp-greeting-failed","analyzedSha":"fc36c76c050c3775c5e899faf7403cf0262d2744","analyzedAt":"2026-09-05T21:28:54.019Z","contentChangedAt":"2026-09-05T21:28:54.019Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}