'create', // 'email' => 'johndoe@example.com', // 'metadata' => [ // 'full_name' => 'John Doe', // 'mail_password' => 'securepassword123', // 'email_provider' => 123, // Post ID of the email provider // 'smtp_server' => 'smtp.example.com', // 'smtp_port' => 587, // 'imap_server' => 'imap.example.com', // 'imap_port' => 993, // ], // ]); // // Update an Email Account // $result = RL_MailWarmer_Email_Helper::modify_email_account([ // 'action' => 'update', // 'post_id' => $post_id, // 'metadata' => [ // 'full_name' => 'Jane Doe', // 'mail_password' => 'newsecurepassword123', // 'smtp_status' => 'connected', // ], // ]); // // Delete an Email Account // $result = RL_MailWarmer_Email_Helper::modify_email_account([ // 'action' => 'delete', // 'post_id' => $post_id, // ]); public static function modify_email_account(array $args) { // Validate required arguments if (empty($args['action']) || !in_array($args['action'], ['create', 'update', 'delete'], true)) { throw new InvalidArgumentException('Invalid or missing action.'); } /* * Add validation to only delete email-account posts * */ $action = $args['action']; $post_id = $args['post_id'] ?? null; // Handle delete action if ($action === 'delete') { if (!$post_id) { throw new InvalidArgumentException('Post ID is required for deletion.'); } return wp_delete_post($post_id, true); } // Validate fields for create/update $post_data = [ 'post_type' => 'email-account', 'post_status' => 'publish', ]; // For "create", ensure no existing post with the same title if ($action === 'create') { if (empty($args['email'])) { throw new InvalidArgumentException('Email is required for creating a new account.'); } $existing_post = get_page_by_title($args['email'], OBJECT, 'email-account'); if ($existing_post) { throw new RuntimeException('An email account with this title already exists.'); } $post_data['post_title'] = $args['email']; } elseif ($action === 'update') { if (!$post_id) { throw new InvalidArgumentException('Post ID is required for updates.'); } $post_data['ID'] = $post_id; } // Assemble metadata $meta_args = $args['metadata'] ?? []; // Generate a random password if mail_password is not provided if (empty($meta_args['mail_password'])) { $meta_args['mail_password'] = bin2hex(random_bytes(8)); // 16-character password } $post_data['meta_input'] = array_map('sanitize_text_field', $meta_args); // Save or update the post $post_id = wp_insert_post($post_data); if (is_wp_error($post_id)) { throw new RuntimeException('Failed to save email account post: ' . $post_id->get_error_message()); } return $post_id; } /** * Check mail login credentials for an email account. * * Validates IMAP/SMTP connection settings for the given email account. * * @param mixed $email_account The email-account post object or ID. * @param string|null $protocol Optional. The protocol to validate ('IMAP' or 'SMTP'). Defaults to both. * @return array|WP_Error Validation results for IMAP and/or SMTP or WP_Error on failure. */ public static function check_mail_login($email_account, $protocol = null) { // Get the post object $post = is_numeric($email_account) ? get_post($email_account) : $email_account; if (!$post || $post->post_type !== 'email-account') { return new WP_Error('invalid_post', __('Invalid email account post.', 'rl-mailwarmer')); } // Fetch email provider and override defaults with saved values $email_provider_id = get_post_meta($post->ID, 'email_provider', true); // log_to_file("check_mail_login - "); log_to_file("check_mail_login - Email Provider ID $email_provider_id"); $defaults = $email_provider_id ? self::get_provider_defaults($email_provider_id) : []; log_to_file("check_mail_login - Email Provider Defaults: ", $defaults); // Fetch saved settings $saved_settings = [ 'mail_password' => get_post_meta($post->ID, 'mail_password', true), 'imap_password' => get_post_meta($post->ID, 'imap_password', true), 'imap_server' => get_post_meta($post->ID, 'imap_server', true), 'imap_port' => get_post_meta($post->ID, 'imap_port', true), 'smtp_password' => get_post_meta($post->ID, 'smtp_password', true), 'smtp_server' => get_post_meta($post->ID, 'smtp_server', true), 'smtp_port' => get_post_meta($post->ID, 'smtp_port', true), ]; // Merge saved settings with defaults $settings = array_merge($defaults, array_filter($saved_settings)); log_to_file("check_mail_login - Using settings: ", $settings); $results = []; // Validate IMAP connection if required if ($protocol === null || strtoupper($protocol) === 'IMAP') { $imap_result = self::validate_imap_connection($post->post_title, $settings); log_to_file("check_mail_login - IMAP Result for " . $post->post_title . ": ", $imap_result); $results['IMAP'] = $imap_result ? __('IMAP connection successful.', 'rl-mailwarmer') : __('IMAP connection failed.', 'rl-mailwarmer'); } // Validate SMTP connection if required if ($protocol === null || strtoupper($protocol) === 'SMTP') { $smtp_result = self::validate_smtp_connection($post->post_title, $settings); log_to_file("check_mail_login - SMTP Result for " . $post->post_title . ": ", $imap_result); $results['SMTP'] = $smtp_result ? __('SMTP connection successful.', 'rl-mailwarmer') : __('SMTP connection failed.', 'rl-mailwarmer'); } log_to_file("check_mail_login - Full Results for " . $post->post_title . ": ", $results); return $results; } /** * Fetch default settings for an email provider. * * @param int $email_provider_id The post ID of the email provider. * @return array The default server settings. */ private static function get_provider_defaults($email_provider_id) { return [ 'imap_server' => get_post_meta($email_provider_id, 'default_imap_server', true), 'imap_port' => get_post_meta($email_provider_id, 'default_imap_port', true), 'smtp_server' => get_post_meta($email_provider_id, 'default_smtp_server', true), 'smtp_port' => get_post_meta($email_provider_id, 'default_smtp_port', true), ]; } /** * Validate an IMAP connection for an email account. * * @param string $email The email address. * @param array $settings The server settings (imap_server, imap_port, imap_password). * @return bool True if the connection is successful, false otherwise. */ private static function validate_imap_connection($email, $settings) { if ( empty($settings['imap_server']) || empty($settings['imap_port']) ) { return false; // Missing required settings } if (!empty($settings['imap_password'])) { $password = $settings['imap_password']; } else { $password = $settings['mail_password']; } // Try connecting to the IMAP server $imap_stream = @imap_open( '{' . $settings['imap_server'] . ':' . $settings['imap_port'] . '/imap/ssl}', $email, $password ); if ($imap_stream) { imap_close($imap_stream); // Close connection if successful return true; } return false; // Connection failed } /** * Validate an SMTP connection for an email account using Symfony Mailer. * * @param string $email The email address. * @param array $settings The server settings (smtp_server, smtp_port, smtp_password). * @return bool True if the connection is successful, false otherwise. */ private static function validate_smtp_connection($email, $settings) { if (empty($settings['smtp_server']) || empty($settings['smtp_port']) ) { return false; // Missing required settings } if (!empty($settings['smtp_password'])) { $password = $settings['smtp_password']; } else { $password = $settings['mail_password']; } $test_to_email = "ruben@redlotusaustin.com"; try { // Create the SMTP transport $transport = new Symfony\Component\Mailer\Transport\Smtp\EsmtpTransport( $settings['smtp_server'], $settings['smtp_port'] ); // Set authentication details $transport->setUsername($email); $transport->setPassword($password); // Create the mailer $mailer = new Symfony\Component\Mailer\Mailer($transport); // Send a test email $test_email = (new Symfony\Component\Mime\Email()) ->from($email) ->to($test_to_email) ->subject('SMTP Connection for ' . $email) ->text('This is a test email to verify SMTP connection for ' . $email); $mailer->send($test_email); return true; } catch (Exception $e) { error_log('SMTP validation failed: ' . $e->getMessage()); return false; } } /** * Generate random email accounts for the specified domain. * * @param string $domain The domain name to use for the email accounts. * @param int $qty The number of email accounts to generate. Defaults to 1. * @return array List of generated names and email addresses. * @throws Exception If name pools are empty or post creation fails. */ public static function generate_random_accounts($domain, $qty = 1) { // Fetch name pools from ACF options $first_name_pool = get_field('valid_first_name_pool', 'option'); $last_name_pool = get_field('valid_last_name_pool', 'option'); if (empty($first_name_pool) || empty($last_name_pool)) { throw new Exception(__('Name pools are empty. Please configure them in the ACF options.', 'rl-mailwarmer')); } $first_names = explode(',', $first_name_pool); // Assume comma-separated list $last_names = explode(',', $last_name_pool); $generated_accounts = []; for ($i = 0; $i < $qty; $i++) { // Generate a random name $first_name = trim($first_names[array_rand($first_names)]); $last_name = trim($last_names[array_rand($last_names)]); $full_name = "{$first_name} {$last_name}"; // Generate a semi-random email address $email_formats = [ "{$first_name}{$last_name}", "{$first_name}.{$last_name}", substr($first_name, 0, 1) . ".{$last_name}", "{$first_name}.l", substr($first_name, 0, 1) . $last_name, ]; $email_local_part = strtolower($email_formats[array_rand($email_formats)]); $email_address = "{$email_local_part}@{$domain}"; // Create the email-account post // $post_id = RL_MailWarmer_Email_Helper::modify_email_account([ // 'action' => 'create', // 'email' => $email_address, // 'metadata' => [ // 'full_name' => $full_name, // 'mail_password' => bin2hex(random_bytes(8)), // Generate a secure random password // ], // ]); // if (!$post_id) { // throw new Exception(__('Failed to create email account post.', 'rl-mailwarmer')); // } // Add to results $generated_accounts[] = [ 'full_name' => $full_name, 'email_address' => $email_address, ]; } return $generated_accounts; } /** * Modify an email account on a VirtualMin server. * * @param int $account_id The email-account post ID. * @param string $action The action to perform: 'create', 'update', or 'delete'. * @return bool|WP_Error True on success, WP_Error on failure. */ public static function modify_email_account_on_server($account_id, $action) { // Validate email-account post $email_account = get_post($account_id); if (!$email_account || $email_account->post_type !== 'email-account') { return new WP_Error('invalid_account', __('Invalid email account.', 'rl-mailwarmer')); } // Fetch associated server posts $domain_id = get_post_meta($account_id, 'domain_id', true); if (!$domain_id) { return new WP_Error('missing_domain', __('No associated domain found.', 'rl-mailwarmer')); } $server_ids = get_post_meta($domain_id, 'associated_servers', true); // Assuming this field holds server post IDs if (empty($server_ids) || !is_array($server_ids)) { return new WP_Error('missing_servers', __('No associated servers found.', 'rl-mailwarmer')); } // Fetch email account details $email_address = $email_account->post_title; $password = get_post_meta($account_id, 'mail_password', true); [$username, $domain] = explode('@', $email_address); // Iterate over servers and perform the action foreach ($server_ids as $server_id) { $server = get_post($server_id); if (!$server || $server->post_type !== 'server') { continue; // Skip invalid server posts } $server_ip = get_post_meta($server_id, 'ip_address', true); $server_port = get_post_meta($server_id, 'ssh_port', true); $server_user = get_post_meta($server_id, 'username', true); $server_password = get_post_meta($server_id, 'ssh_private_key', true); // $server_password = get_post_meta($server_id, 'password', true); if (!$server_ip || !$server_user || !$server_password) { return new WP_Error('missing_server_details', __('Missing server credentials.', 'rl-mailwarmer')); } // Build VirtualMin command $command = "virtualmin"; if ($action === 'create') { $command .= " create-user --domain $domain --user $username --pass $password"; } elseif ($action === 'update') { $command .= " modify-user --domain $domain --user $username --pass $password"; } elseif ($action === 'delete') { $command .= " delete-user --domain $domain --user $username"; } else { return new WP_Error('invalid_action', __('Invalid action specified.', 'rl-mailwarmer')); } // Execute the command via SSH // $ssh = new phpseclib\Net\SSH2($server_ip); // $key = new phpseclib\Crypt\PublicKeyLoader::loadPrivateKey($server_password); // Adjust for SSH key or plain password $ssh = new SSH2($server_ip, $server_port); if (!empty($server_password)) { // Load the private key from the postmeta field $key = PublicKeyLoader::loadPrivateKey($server_password); } else { // Fallback to password-based authentication // $key = $server_password; log_to_file("modify_email_account_on_server - Server $$server_id ssh_private_key empty"); return new WP_Error('ssh_login_failed', __('No private key found!', 'rl-mailwarmer')); } if (!$ssh->login($server_user, $key)) { return new WP_Error('ssh_login_failed', __('Failed to log into the server.', 'rl-mailwarmer')); } $output = $ssh->exec($command); if (strpos($output, 'failed') !== false) { return new WP_Error('command_failed', __('Failed to execute VirtualMin command.', 'rl-mailwarmer')); } } return true; // Success } /** * Send or reply to a conversation email. * * @param int $conversation_id The conversation post ID. * @param int $account_id The email account post ID. * @return bool True on success, false on failure. */ public static function send_conversation_mail(int $conversation_id, int $account_id) { // Implementation goes here } }