ellite/Wallos · error · Exception

$message (getSmtpErrorMessage('connect_host'))

Error message

$message (getSmtpErrorMessage('connect_host'))

What it means

Thrown inside smtpConnect()'s host loop when STARTTLS negotiation fails: $this->smtp->startTLS() returns false after a plain connection with the server advertising STARTTLS. The message comes from getSmtpErrorMessage('connect_host') (typically 'SMTP connect() failed' plus debug info). Note the generic message can be misleading — the real cause is the TLS handshake, visible only with SMTPDebug.

Solutions

  1. Enable SMTPDebug = DEBUG_SERVER to see the actual TLS handshake error behind the generic message.
  2. Fix certificates: use a valid cert on the server or add its CA to the trust store / set $mailer->SMTPOptions['ssl']['cafile'].
  3. For dev/test relays only, relax verification: SMTPOptions = ['ssl' => ['verify_peer' => false, 'verify_peer_name' => false, 'allow_self_signed' => true]].
  4. Update the system CA bundle (apt-get install ca-certificates / update-ca-certificates).
  5. If TLS is optional, disable it (SMTPSecure = '') only when the server genuinely permits plain sessions.

Example fix

// before (self-signed internal relay)
$mailer->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS; // startTLS() fails
// after
$mailer->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;
$mailer->SMTPOptions = [
    'ssl' => [
        'verify_peer' => true,
        'cafile' => '/etc/ssl/certs/internal-ca.pem', // trust the relay's CA
    ],
];
Defensive patterns

Strategy: try-catch

Validate before calling

$ctx = stream_context_create(['ssl' => ['capture_peer_cert' => true]]);
if (@stream_socket_client("tcp://{$mailer->Host}:{$mailer->Port}", $errno, $errstr, 5, STREAM_CLIENT_CONNECT, $ctx) === false) {
    error_log("Pre-check: cannot reach {$mailer->Host}:{$mailer->Port}: $errstr");
}
// also confirm CA trust: openssl s_client -starttls smtp -connect host:port -CApath /etc/ssl/certs

Try / catch

try {
    $mailer->send();
} catch (PHPMailer\PHPMailer\Exception $e) {
    if (str_contains($mailer->ErrorInfo, 'connect_host')) {
        error_log('STARTTLS likely failed: rerun with SMTPDebug=DEBUG_SERVER for handshake detail');
        // fix CA trust or relax SMTPOptions for trusted internal relays only
    }
}

Prevention

When it happens

Trigger: Calling send() with isSMTP() when the server advertises STARTTLS but startTLS() fails: bad/mismatched certificates, untrusted self-signed cert, missing CA bundle (cafile not set), cipher mismatch, or server advertises TLS but is misconfigured.

Common situations: Self-signed or expired certificates on internal SMTP relays, missing/update ca-certificates package, localhost/test SMTP servers (MailHog) without valid certs, SMTPOptions ssl verify_peer settings blocking the handshake.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


AI-assisted analysis of ellite/Wallos@52820e87ca (2026-09-13). Data as JSON: /api/errors/73c3ec093ba4f9b6. Report an issue: GitHub.

Appendix: source

Thrown at libs/PHPMailer/PHPMailer.php:2210

                    //Automatically enable TLS encryption if:
                    //* it's not disabled
                    //* we are not connecting to localhost
                    //* we have openssl extension
                    //* we are not already using SSL
                    //* the server offers STARTTLS
                    if (
                        $this->SMTPAutoTLS &&
                        $this->Host !== 'localhost' &&
                        $sslext &&
                        $secure !== 'ssl' &&
                        $this->smtp->getServerExt('STARTTLS')
                    ) {
                        $tls = true;
                    }
                    if ($tls) {
                        if (!$this->smtp->startTLS()) {
                            $message = $this->getSmtpErrorMessage('connect_host');
                            throw new Exception($message);
                        }
                        //We must resend EHLO after TLS negotiation
                        $this->smtp->hello($hello);
                    }
                    if (
                        $this->SMTPAuth && !$this->smtp->authenticate(
                            $this->Username,
                            $this->Password,
                            $this->AuthType,
                            $this->oauth
                        )
                    ) {
                        throw new Exception($this->lang('authenticate'));
                    }

                    return true;
                } catch (Exception $exc) {
                    $lastexception = $exc;

View on GitHub (pinned to 52820e87ca)