private function connect()
    {
        if (!$this->stream) {
            $errorNum = 0;
            $errorMsg = "";
            $context = @stream_context_create($this->streamOptions);
            $this->stream = @stream_socket_client(
                sprintf('%1$s:%2$d', $this->host, $this->port),
                $errorNum,
                $errorMsg,
                $this->timeOut,
                STREAM_CLIENT_CONNECT,
                $context
            );

            if (!$this->stream) {
                throw SMTPException::connectionError($errorNum, $errorMsg);
            }

            $this->read(); // Read response from server
            if ($this->lastResponseCode() !== 220) {
                throw SMTPException::unexpectedResponse("CONNECT", 220, $this->lastResponseCode());
            }

            // Build specs/options available at remote SMTP server
            $this->smtpServerOptions(
                $this->command("EHLO", $this->serverName)
            );

            // Use TLS?
            if ($this->secure === true) {
                if ($this->options["startTLS"] !== true) {
                    throw SMTPException::tlsNotAvailable();
                }

                $this->command("STARTTLS", null, 220);
                $tls = @stream_socket_enable_crypto($this->stream, true, STREAM_CRYPTO_METHOD_TLS_CLIENT);
                if (!$tls) {
                    throw SMTPException::tlsNegotiateFailed();
                }

                $this->command("EHLO", $this->serverName); // Resend EHLO command
            }

            // Authenticate
            if ($this->options["authLogin"] === true) {
                try {
                    $this->command("AUTH LOGIN", null, 334);
                    $this->command(base64_encode($this->username ?? " "), null, 334);
                    $this->command(base64_encode($this->password ?? " "), null, 235);
                } catch (SMTPException $e) {
                    throw SMTPException::authFailed($this->lastResponse);
                }
            } elseif ($this->options["authPlain"] === true) {
                // Todo: plain authentication
                throw SMTPException::authUnavailable();
            } else {
                throw SMTPException::authUnavailable();
            }
        } else {
            try {
                if (!stream_get_meta_data($this->stream)["timed_out"]) {
                    throw new SMTPException(__METHOD__, "Timed out");
                }

                $this->command("NOOP", null, 250);
            } catch (SMTPException $e) {
                $this->stream = null;
                $this->connect();
                return;
            }
        }
    }