_name = 'SMTP'; $this->_desc = __('Connect any SMTP server', 'ai-copilot-content-generator'); $this->setIntegration($integration); } public function getSettings() { if (empty($this->_settings)) { $this->setSettings(); } return $this->_settings; } public function setSettings() { $this->_settings = array( 'name' => array( 'type' => 'input', 'label' => __('Profile name', 'ai-copilot-content-generator'), 'plh' => __('Internal name to identify this configuration', 'ai-copilot-content-generator'), 'default' => '', ), 'host' => array( 'type' => 'input', 'label' => __('SMTP Host', 'ai-copilot-content-generator') . ' *', 'plh' => 'smtp.gmail.com', 'default' => '', ), 'port' => array( 'type' => 'input', 'label' => __('Port', 'ai-copilot-content-generator') . ' *', 'default' => 587, ), 'encryption' => array( 'type' => 'select', 'label' => __('Encryption', 'ai-copilot-content-generator'), 'options' => array('TLS' => 'TLS', 'SSL' => 'SSL'), 'default' => '', ), 'username' => array( 'type' => 'input', 'label' => __('Username', 'ai-copilot-content-generator'), 'plh' => 'your-email@domain.com', 'default' => '', ), 'password' => array( 'type' => 'input', 'label' => __('Password', 'ai-copilot-content-generator'), 'encrypt' => true, 'default' => '', ), ); } public function doTest( $need = false ) { $params = $this->getParams(); if (!$need && !empty($params['_status'])) { return true; } $error = $this->doConnect(); if (empty($error)) { $this->addParam('_status', 1); $this->addParam('_status_error', ''); } else { $this->addParam('_status', 7); $this->addParam('_status_error', $error); } } public function doConnect( $close = true ) { $error = ''; $host = $this->getParam('host'); $port = $this->getParam('port'); $encryption = $this->getParam('encryption'); $username = $this->getParam('username'); $password = $this->getDecryptedParam('password'); if (empty($host)) { $error = 'SMTP Host needed'; } else if (empty($port)) { $error = 'Port needed'; } else if (empty($encryption)) { $error = 'Encryption needed'; } $socket = false; if (empty($error)) { $isSSL = 'SSL' == $encryption; //$protocol = ( 'TLS' == $encryption ? 'tls://' : 'ssl://' ); $protocol = ( $isSSL ? 'ssl://' : '' ); /*$context = stream_context_create(array( 'ssl' => array( 'verify_peer' => false, 'verify_peer_name' => false, 'allow_self_signed' => true ) ));*/ //$socket = stream_socket_client($protocol . $host . ':' . $port, $errno, $errstr, 20, STREAM_CLIENT_CONNECT, $context); $socket = @stream_socket_client($protocol . $host . ':' . $port, $errno, $errstr, 60); if (!$socket) { $error = 'Connection failed: ' . $errstr . '(' . $errno . ')'; } } if (empty($error)) { stream_set_timeout($socket, 10); $greeting = fgets($socket); if (!$greeting || stripos($greeting, '220') !== 0) { $error = 'Invalid server greeting: ' . trim($greeting); } } if (empty($error)) { $ehloHost = wp_parse_url(home_url(), PHP_URL_HOST); fwrite($socket, "EHLO $ehloHost\r\n"); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fwrite $ehloSuccess = false; while ($line = fgets($socket)) { if (strpos($line, '250 ') === 0) { $ehloSuccess = true; break; } if (preg_match('/^5\d{2}/', $line)) { $error = 'EHLO error: ' . trim($line); break; } } if (empty($error) && !$ehloSuccess) { $error = 'EHLO failed or no valid response.'; } } if (empty($error) && !$isSSL) { fwrite($socket, "STARTTLS\r\n"); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fwrite $tlsResponse = fgets($socket); if (stripos($tlsResponse, '220') !== 0) { $error = 'STARTTLS failed: ' . trim($tlsResponse); } else { stream_socket_enable_crypto($socket, true, STREAM_CRYPTO_METHOD_TLS_CLIENT); fwrite($socket, "EHLO $ehloHost\r\n"); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fwrite } while ($line = fgets($socket)) { if (strpos($line, '250 ') === 0) break; } } if (empty($error)) { fwrite($socket, "AUTH LOGIN\r\n"); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fwrite $authPrompt = fgets($socket); if (stripos($authPrompt, '334') !== 0) { $error = 'AUTH LOGIN not accepted: ' . trim($authPrompt); } else { fwrite($socket, base64_encode($username) . "\r\n"); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fwrite $userResponse = fgets($socket); if (stripos($userResponse, '334') !== 0) { $error = 'Username rejected: ' . trim($userResponse); } else { fwrite($socket, base64_encode($password) . "\r\n"); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fwrite $passResponse = fgets($socket); if (stripos($passResponse, '235') !== 0) { $error = 'Authentication failed: ' . trim($passResponse); } } } } if ($socket) { if ($close) { fwrite($socket, "QUIT\r\n"); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fwrite fclose($socket); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fclose } else { $this->_socket = $socket; } } return $error; } public function doSendEmail( $data ) { $error = $this->doConnect(false); $result = array(); if (empty($error)) { if (!$this->_socket) { $error = 'Socket Error'; } else { $socket = $this->_socket; $from = $this->getParam('username'); fwrite($socket, "MAIL FROM:<$from>\r\n"); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fwrite $resp = fgets($socket); if (stripos($resp, '250') !== 0) { $error = 'MAIL FROM failed: ' . trim($resp); } $headers = "From: <$from>\r\n"; $result['from'] = $from; } } if (empty($error) && !empty($data['to'])) { $to = explode(',', $data['to']); foreach ($to as $addr) { $addr = trim($addr); fwrite($socket, "RCPT TO:<$addr>\r\n"); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fwrite $resp = fgets($socket); if (stripos($resp, '250') !== 0) { $error = "RCPT TO failed ($addr): " . trim($resp); break; } } $headers .= 'To: ' . ( empty($data['to_name']) ? '' : $data['to_name'] . ' ' ) . $data['to'] . "\r\n"; } if (empty($error) && !empty($data['cc'])) { $cc = explode(',', $data['cc']); foreach ($cc as $addr) { $addr = trim($addr); fwrite($socket, "RCPT TO:<$addr>\r\n"); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fwrite $resp = fgets($socket); if (stripos($resp, '250') !== 0) { $error = "RCPT TO CC failed ($addr): " . trim($resp); break; } } $headers .= "Cc: " . $data['cc'] . "\r\n"; } if (empty($error) && !empty($data['bcc'])) { $bcc = explode(',', $data['bcc']); foreach ($bcc as $addr) { $addr = trim($addr); fwrite($socket, "RCPT TO:<$addr>\r\n"); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fwrite $resp = fgets($socket); if (stripos($resp, '250') !== 0) { $error = "RCPT TO BCC failed ($addr): " . trim($resp); break; } } } if (empty($error)) { fwrite($socket, "DATA\r\n"); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fwrite $resp = fgets($socket); if (stripos($resp, '354') !== 0) { $error = "DATA not accepted: " . trim($resp); } } if (empty($error) && !empty($data['reply'])) { $headers .= 'Reply-To: ' . $data['reply'] . "\r\n"; } if (empty($error)) { $headers .= 'Subject: ' . $data['subject'] . "\r\n"; $headers .= "Content-Type: text/plain; charset=UTF-8\r\n"; fwrite($socket, $headers . "\r\n" . $data['message'] . "\r\n.\r\n"); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fwrite $resp = fgets($socket); if (stripos($resp, '250') !== 0) { $error = 'Message not accepted: ' . trim($resp); } } if (!empty($error) && $socket) { fgets($socket); fwrite($socket, "QUIT\r\n"); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fwrite fclose($socket); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fclose } $result['error'] = $error; return $result; } }