$expected_codes Expected success codes. * * @return array */ public function execute_command( string $name, string $command_string, array $expected_codes = array( 250 ) ): array { $this->last_command_timed_out = false; $this->reset_error_state(); $expected = ! empty( $expected_codes ) ? array_map( 'intval', $expected_codes ) : array( 250 ); $success = parent::sendCommand( $name, $command_string, $expected ); if ( ! $success ) { $this->last_command_timed_out = $this->error_indicates_timeout( parent::getError() ); } return array( 'success' => $success, 'reply' => $this->getLastReply(), 'timed_out' => $this->last_command_timed_out, ); } /** * Indicates whether the last command timed out. * * @return bool */ public function did_last_command_timeout(): bool { return $this->last_command_timed_out; } /** * Initiates STARTTLS while tracking timeout state. * * @return bool */ public function startTLS(): bool { $this->last_command_timed_out = false; $this->reset_error_state(); $result = parent::startTLS(); if ( ! $result ) { $this->last_command_timed_out = $this->error_indicates_timeout( parent::getError() ); } return $result; } /** * Clears the stored error state. */ private function reset_error_state(): void { parent::setError( '' ); } /** * Determines whether an error array represents a timeout. * * @param array $error Error details. * * @return bool */ private function error_indicates_timeout( array $error ): bool { foreach ( array( 'error', 'detail', 'smtp_code_ex' ) as $key ) { if ( empty( $error[ $key ] ) ) { continue; } $value = (string) $error[ $key ]; if ( false !== stripos( $value, 'timed out' ) || false !== stripos( $value, 'timed-out' ) ) { return true; } } return false; } }