'site_mail', 'provider' => 'other', 'sender_name' => '', 'sender_email' => '', 'reply_to_email' => '', 'smtp_host' => '', 'smtp_port' => '', 'smtp_encryption' => 'tls', 'smtp_username' => '', 'smtp_password_enc' => '', 'relay_endpoint' => '', 'relay_token_enc' => '', 'relay_token_hash' => '', 'allow_site_fallback' => '1', 'updated_at' => '', ); } } if (!function_exists('matewa_client_mail_delivery_provider_presets')) { function matewa_client_mail_delivery_provider_presets() { return array( 'google_workspace' => array( 'label' => 'Google Workspace / Gmail', 'host' => 'smtp.gmail.com', 'port' => '587', 'encryption' => 'tls', 'note' => 'Google is best handled by a WordPress SMTP plugin with OAuth, but SMTP/app-password routes can still be recorded here when the client uses them.', ), 'microsoft_365' => array( 'label' => 'Microsoft 365 / Outlook', 'host' => 'smtp.office365.com', 'port' => '587', 'encryption' => 'tls', 'note' => 'Use the client mailbox or authorised SMTP account. Modern Microsoft tenants may require authenticated SMTP to be enabled.', ), 'hostinger' => array( 'label' => 'Hostinger email', 'host' => 'smtp.hostinger.com', 'port' => '465', 'encryption' => 'ssl', 'note' => 'Use the full Hostinger mailbox address and mailbox password.', ), 'other' => array( 'label' => 'Other SMTP provider', 'host' => '', 'port' => '587', 'encryption' => 'tls', 'note' => 'Use the provider details supplied by the client or their IT/email provider.', ), ); } } if (!function_exists('matewa_client_mail_delivery_allowed_routes')) { function matewa_client_mail_delivery_allowed_routes() { return array('site_mail', 'managed_relay', 'client_smtp'); } } if (!function_exists('matewa_client_mail_delivery_normalise_route')) { function matewa_client_mail_delivery_normalise_route($route) { $route = sanitize_key((string) $route); return in_array($route, matewa_client_mail_delivery_allowed_routes(), true) ? $route : 'site_mail'; } } if (!function_exists('matewa_client_mail_delivery_normalise_provider')) { function matewa_client_mail_delivery_normalise_provider($provider) { $provider = sanitize_key((string) $provider); $presets = matewa_client_mail_delivery_provider_presets(); return isset($presets[$provider]) ? $provider : 'other'; } } if (!function_exists('matewa_client_mail_delivery_normalise_encryption')) { function matewa_client_mail_delivery_normalise_encryption($encryption) { $encryption = sanitize_key((string) $encryption); return in_array($encryption, array('tls', 'ssl', 'none'), true) ? $encryption : 'tls'; } } if (!function_exists('matewa_client_mail_delivery_secret_key')) { function matewa_client_mail_delivery_secret_key() { $seed = ''; foreach (array('AUTH_KEY', 'SECURE_AUTH_KEY', 'LOGGED_IN_KEY') as $constant) { if (defined($constant)) { $seed .= constant($constant); } } $seed .= wp_salt('auth') . site_url('/'); return hash('sha256', $seed, true); } } if (!function_exists('matewa_client_mail_delivery_encrypt_password')) { function matewa_client_mail_delivery_encrypt_password($plain) { $plain = (string) $plain; if ('' === $plain || !function_exists('openssl_encrypt') || !defined('OPENSSL_RAW_DATA')) { return ''; } try { $iv_length = openssl_cipher_iv_length('aes-256-cbc'); if (false === $iv_length || $iv_length < 1 || !function_exists('random_bytes')) { return ''; } $iv = random_bytes($iv_length); $encrypted = openssl_encrypt($plain, 'aes-256-cbc', matewa_client_mail_delivery_secret_key(), OPENSSL_RAW_DATA, $iv); if (false === $encrypted) { return ''; } return bin2hex($iv) . ':' . bin2hex($encrypted); } catch (Exception $exception) { return ''; } } } if (!function_exists('matewa_client_mail_delivery_decrypt_password')) { function matewa_client_mail_delivery_decrypt_password($stored) { $stored = (string) $stored; if ('' === $stored || false === strpos($stored, ':') || !function_exists('openssl_decrypt') || !defined('OPENSSL_RAW_DATA')) { return ''; } $parts = explode(':', $stored, 2); if (2 !== count($parts) || !ctype_xdigit($parts[0]) || !ctype_xdigit($parts[1])) { return ''; } $iv = hex2bin($parts[0]); $encrypted = hex2bin($parts[1]); if (false === $iv || false === $encrypted) { return ''; } $plain = openssl_decrypt($encrypted, 'aes-256-cbc', matewa_client_mail_delivery_secret_key(), OPENSSL_RAW_DATA, $iv); return false === $plain ? '' : (string) $plain; } } if (!function_exists('matewa_client_mail_delivery_get_options')) { function matewa_client_mail_delivery_get_options() { $stored = get_option(MATEWA_CLIENT_MAIL_DELIVERY_OPTION, array()); $stored = is_array($stored) ? $stored : array(); $options = array_merge(matewa_client_mail_delivery_default_options(), $stored); $options['route'] = matewa_client_mail_delivery_normalise_route($options['route'] ?? 'site_mail'); $options['provider'] = matewa_client_mail_delivery_normalise_provider($options['provider'] ?? 'other'); $options['smtp_encryption'] = matewa_client_mail_delivery_normalise_encryption($options['smtp_encryption'] ?? 'tls'); $options['sender_email'] = sanitize_email((string) ($options['sender_email'] ?? '')); $options['reply_to_email'] = sanitize_email((string) ($options['reply_to_email'] ?? '')); $options['smtp_username'] = sanitize_text_field((string) ($options['smtp_username'] ?? '')); $options['smtp_host'] = sanitize_text_field((string) ($options['smtp_host'] ?? '')); $smtp_port_value = absint($options['smtp_port'] ?? 0); $options['smtp_port'] = 0 < $smtp_port_value ? (string) $smtp_port_value : ''; $options['smtp_password_set'] = '' !== (string) ($options['smtp_password_enc'] ?? ''); $options['relay_endpoint'] = esc_url_raw((string) ($options['relay_endpoint'] ?? '')); $options['relay_token_set'] = '' !== (string) ($options['relay_token_enc'] ?? ''); $options['allow_site_fallback'] = !empty($options['allow_site_fallback']) ? '1' : '0'; return $options; } } if (!function_exists('matewa_client_mail_delivery_get_route')) { function matewa_client_mail_delivery_get_route() { $options = matewa_client_mail_delivery_get_options(); return $options['route']; } } if (!function_exists('matewa_client_mail_delivery_allow_site_fallback')) { function matewa_client_mail_delivery_allow_site_fallback() { $options = matewa_client_mail_delivery_get_options(); return '1' === (string) ($options['allow_site_fallback'] ?? '1'); } } if (!function_exists('matewa_client_mail_delivery_managed_relay_is_eligible')) { function matewa_client_mail_delivery_managed_relay_is_eligible() { if (function_exists('matewa_agency_client_entitlement_is_active') && matewa_agency_client_entitlement_is_active()) { return true; } if (function_exists('matewa_get_entitlement_state')) { $state = matewa_get_entitlement_state(); $allowed = array(); foreach (array('MATEWA_MODE_PRO', 'MATEWA_MODE_MASTER', 'MATEWA_MODE_TRIAL') as $constant) { if (defined($constant)) { $allowed[] = constant($constant); } } $allowed = array_merge($allowed, array('pro', 'master', 'trial')); if (in_array($state, array_unique($allowed), true)) { return true; } } if (function_exists('matewa_founder_beta_is_active') && matewa_founder_beta_is_active()) { return true; } if (function_exists('matewa_trial_active') && matewa_trial_active()) { return true; } return false; } } if (!function_exists('matewa_client_mail_delivery_sanitise_for_save')) { function matewa_client_mail_delivery_sanitise_for_save($raw, $previous = null) { $raw = is_array($raw) ? $raw : array(); $previous = is_array($previous) ? $previous : matewa_client_mail_delivery_get_options(); $presets = matewa_client_mail_delivery_provider_presets(); $provider = matewa_client_mail_delivery_normalise_provider($raw['provider'] ?? ($previous['provider'] ?? 'other')); $preset = $presets[$provider] ?? $presets['other']; $route = matewa_client_mail_delivery_normalise_route($raw['route'] ?? ($previous['route'] ?? 'site_mail')); $sender_name = sanitize_text_field((string) ($raw['sender_name'] ?? '')); $sender_email = sanitize_email((string) ($raw['sender_email'] ?? '')); $reply_to_email = sanitize_email((string) ($raw['reply_to_email'] ?? '')); $smtp_host = sanitize_text_field((string) ($raw['smtp_host'] ?? '')); $smtp_port = absint($raw['smtp_port'] ?? 0); $smtp_encryption = matewa_client_mail_delivery_normalise_encryption($raw['smtp_encryption'] ?? ''); $smtp_username = sanitize_text_field((string) ($raw['smtp_username'] ?? '')); $smtp_password = isset($raw['smtp_password']) ? trim((string) $raw['smtp_password']) : ''; $relay_endpoint = isset($raw['relay_endpoint']) ? esc_url_raw(trim((string) $raw['relay_endpoint'])) : ''; $relay_token = isset($raw['relay_token']) ? trim((string) $raw['relay_token']) : ''; $clear_password = !empty($raw['clear_password']); $clear_relay_token = !empty($raw['clear_relay_token']); if ('client_smtp' === $route && '' === $smtp_host && '' !== (string) ($preset['host'] ?? '')) { $smtp_host = sanitize_text_field((string) $preset['host']); } if ('client_smtp' === $route && 0 === $smtp_port && '' !== (string) ($preset['port'] ?? '')) { $smtp_port = absint($preset['port']); } if ('client_smtp' === $route && empty($raw['smtp_encryption']) && '' !== (string) ($preset['encryption'] ?? '')) { $smtp_encryption = matewa_client_mail_delivery_normalise_encryption($preset['encryption']); } if ('managed_relay' === $route && '' === $relay_endpoint && defined('MATEWA_MANAGED_MAIL_RELAY_DEFAULT_ENDPOINT')) { $relay_endpoint = esc_url_raw(MATEWA_MANAGED_MAIL_RELAY_DEFAULT_ENDPOINT); } if ('' !== $relay_endpoint) { $relay_parts = wp_parse_url($relay_endpoint); if (!is_array($relay_parts) || empty($relay_parts['host']) || strtolower((string) ($relay_parts['scheme'] ?? '')) !== 'https') { $relay_endpoint = ''; } } $password_enc = (string) ($previous['smtp_password_enc'] ?? ''); if ($clear_password) { $password_enc = ''; } elseif ('' !== $smtp_password) { $next_enc = matewa_client_mail_delivery_encrypt_password($smtp_password); if ('' !== $next_enc) { $password_enc = $next_enc; } } $relay_token_enc = (string) ($previous['relay_token_enc'] ?? ''); $relay_token_hash = (string) ($previous['relay_token_hash'] ?? ''); if ($clear_relay_token) { $relay_token_enc = ''; $relay_token_hash = ''; } elseif ('' !== $relay_token) { $next_relay_enc = matewa_client_mail_delivery_encrypt_password($relay_token); if ('' !== $next_relay_enc) { $relay_token_enc = $next_relay_enc; $relay_token_hash = hash('sha256', $relay_token); } } return array( 'route' => $route, 'provider' => $provider, 'sender_name' => $sender_name, 'sender_email' => is_email($sender_email) ? $sender_email : '', 'reply_to_email' => is_email($reply_to_email) ? $reply_to_email : '', 'smtp_host' => $smtp_host, 'smtp_port' => 0 < $smtp_port ? (string) $smtp_port : '', 'smtp_encryption' => $smtp_encryption, 'smtp_username' => $smtp_username, 'smtp_password_enc' => $password_enc, 'relay_endpoint' => $relay_endpoint, 'relay_token_enc' => $relay_token_enc, 'relay_token_hash' => sanitize_text_field($relay_token_hash), 'allow_site_fallback' => !empty($raw['allow_site_fallback']) ? '1' : '0', 'updated_at' => current_time('mysql'), ); } } if (!function_exists('matewa_client_mail_delivery_save_from_post')) { function matewa_client_mail_delivery_save_from_post($raw) { $options = matewa_client_mail_delivery_sanitise_for_save($raw, matewa_client_mail_delivery_get_options()); update_option(MATEWA_CLIENT_MAIL_DELIVERY_OPTION, $options, false); return $options; } } if (!function_exists('matewa_client_mail_delivery_has_complete_smtp')) { function matewa_client_mail_delivery_has_complete_smtp($options = null) { $options = is_array($options) ? $options : matewa_client_mail_delivery_get_options(); return ( 'client_smtp' === (string) ($options['route'] ?? '') && '' !== (string) ($options['smtp_host'] ?? '') && 0 < absint($options['smtp_port'] ?? 0) && '' !== (string) ($options['smtp_username'] ?? '') && !empty($options['smtp_password_set']) ); } } if (!function_exists('matewa_client_mail_delivery_header_email')) { function matewa_client_mail_delivery_header_email($headers, $header_name) { $headers = is_array($headers) ? $headers : array(); $header_name = strtolower((string) $header_name); foreach ($headers as $header) { $header = (string) $header; if (false === strpos($header, ':')) { continue; } list($name, $value) = explode(':', $header, 2); if (strtolower(trim($name)) !== $header_name) { continue; } if (preg_match('/<([^>]+)>/', $value, $match)) { $email = sanitize_email($match[1]); } else { $email = sanitize_email(trim($value)); } if (is_email($email)) { return $email; } } return ''; } } if (!function_exists('matewa_client_mail_delivery_load_phpmailer')) { function matewa_client_mail_delivery_load_phpmailer() { if (class_exists('PHPMailer\\PHPMailer\\PHPMailer')) { return true; } $base = trailingslashit(ABSPATH . WPINC) . 'PHPMailer/'; $files = array('Exception.php', 'PHPMailer.php', 'SMTP.php'); foreach ($files as $file) { $path = $base . $file; if (is_readable($path)) { require_once $path; } } return class_exists('PHPMailer\\PHPMailer\\PHPMailer'); } } if (!function_exists('matewa_client_mail_delivery_send_via_smtp')) { function matewa_client_mail_delivery_send_via_smtp(array $payload) { $options = matewa_client_mail_delivery_get_options(); if (!matewa_client_mail_delivery_has_complete_smtp($options)) { return array( 'sent' => false, 'method' => 'client_smtp_incomplete', 'error' => 'Client SMTP route is selected but the SMTP details are incomplete.', ); } if (!matewa_client_mail_delivery_load_phpmailer()) { return array( 'sent' => false, 'method' => 'client_smtp_phpmailer_missing', 'error' => 'WordPress PHPMailer could not be loaded.', ); } $password = matewa_client_mail_delivery_decrypt_password((string) ($options['smtp_password_enc'] ?? '')); if ('' === $password) { return array( 'sent' => false, 'method' => 'client_smtp_password_missing', 'error' => 'Saved SMTP password could not be read. Re-enter the password and save again.', ); } try { $mailer_class = 'PHPMailer\\PHPMailer\\PHPMailer'; $mailer = new $mailer_class(true); $mailer->CharSet = get_bloginfo('charset') ? get_bloginfo('charset') : 'UTF-8'; $mailer->isSMTP(); $mailer->Host = (string) $options['smtp_host']; $mailer->SMTPAuth = true; $mailer->Username = (string) $options['smtp_username']; $mailer->Password = $password; $mailer->Port = absint($options['smtp_port']); if ('ssl' === (string) $options['smtp_encryption']) { $mailer->SMTPSecure = 'ssl'; } elseif ('tls' === (string) $options['smtp_encryption']) { $mailer->SMTPSecure = 'tls'; } $from_email = is_email((string) ($options['sender_email'] ?? '')) ? (string) $options['sender_email'] : sanitize_email((string) $options['smtp_username']); if (!is_email($from_email)) { return array( 'sent' => false, 'method' => 'client_smtp_invalid_sender', 'error' => 'Client SMTP sender email is invalid.', ); } $from_name = sanitize_text_field((string) ($options['sender_name'] ?? '')); if ('' === $from_name) { $from_name = sanitize_text_field((string) get_bloginfo('name')); } if ('' === $from_name) { $from_name = 'Website Leads'; } $mailer->setFrom($from_email, $from_name, false); $mailer->addAddress(sanitize_email((string) ($payload['to'] ?? ''))); $reply_to = sanitize_email((string) ($options['reply_to_email'] ?? '')); if (!is_email($reply_to)) { $reply_to = matewa_client_mail_delivery_header_email($payload['headers'] ?? array(), 'Reply-To'); } if (is_email($reply_to)) { $mailer->addReplyTo($reply_to); } $mailer->isHTML(true); $mailer->Subject = wp_specialchars_decode((string) ($payload['subject'] ?? ''), ENT_QUOTES); $mailer->Body = (string) ($payload['message'] ?? ''); $mailer->AltBody = wp_strip_all_tags((string) ($payload['message'] ?? '')); $mailer->send(); return array( 'sent' => true, 'method' => 'client_smtp_' . sanitize_key((string) ($options['provider'] ?? 'other')), 'error' => '', ); } catch (Exception $exception) { return array( 'sent' => false, 'method' => 'client_smtp_failed', 'error' => $exception->getMessage(), ); } } } if (!function_exists('matewa_client_mail_delivery_get_last_test')) { function matewa_client_mail_delivery_get_last_test() { $result = get_option(MATEWA_CLIENT_MAIL_DELIVERY_TEST_OPTION, array()); return is_array($result) ? $result : array(); } } if (!function_exists('matewa_client_mail_delivery_store_last_test')) { function matewa_client_mail_delivery_store_last_test(array $result) { $result['tested_at'] = current_time('mysql'); update_option(MATEWA_CLIENT_MAIL_DELIVERY_TEST_OPTION, $result, false); } } if (!function_exists('matewa_client_mail_delivery_status_label')) { function matewa_client_mail_delivery_status_label() { $options = matewa_client_mail_delivery_get_options(); $last = matewa_client_mail_delivery_get_last_test(); if (!empty($last['sent'])) { return 'Client mail route test passed on ' . sanitize_text_field((string) ($last['tested_at'] ?? 'recently')) . '.'; } if (!empty($last['error'])) { return 'Last client mail route test failed: ' . sanitize_text_field((string) $last['error']); } if ('managed_relay' === (string) ($options['route'] ?? '')) { if (function_exists('matewa_client_mail_delivery_managed_relay_is_eligible') && matewa_client_mail_delivery_managed_relay_is_eligible()) { return '247ChatMate managed sender is active. No relay token is needed for licensed, trial or agency-managed sites.'; } return '247ChatMate managed sender needs an active trial, licence or agency-managed setup before it can send.'; } if ('client_smtp' === (string) ($options['route'] ?? '') && !matewa_client_mail_delivery_has_complete_smtp($options)) { return 'Client SMTP is selected, but the SMTP details are not complete yet.'; } return 'Using this website’s mail setup. SMTP plugins such as WP Mail SMTP, Microsoft 365, Google Workspace or Hostinger SMTP can handle delivery.'; } } if (!function_exists('matewa_client_mail_delivery_handle_test_request')) { function matewa_client_mail_delivery_handle_test_request() { if (!is_admin() || !current_user_can('manage_options')) { return; } $page = isset($_GET['page']) ? sanitize_key(wp_unslash($_GET['page'])) : ''; if ('247chatmate' !== $page || empty($_POST['matewa_client_mail_delivery_action'])) { return; } check_admin_referer('matewa_client_mail_delivery_nonce', 'matewa_client_mail_delivery_nonce'); $action = sanitize_key(wp_unslash($_POST['matewa_client_mail_delivery_action'])); if ('test_route' !== $action) { wp_safe_redirect(admin_url('admin.php?page=247chatmate&matewa_saved_section=setup&matewa_scroll_target=client_mail_delivery&matewa_client_mail_notice=unknown_action#matewa-client-mail-delivery-options')); exit; } $recipient = sanitize_email((string) get_option('matewa_leads_email', '')); if (!is_email($recipient)) { $result = array( 'sent' => false, 'error' => 'Add a valid Lead destination inbox before testing mail delivery.', 'method'=> 'client_mail_test_missing_recipient', ); matewa_client_mail_delivery_store_last_test($result); wp_safe_redirect(admin_url('admin.php?page=247chatmate&matewa_saved_section=setup&matewa_scroll_target=client_mail_delivery&matewa_client_mail_notice=missing_recipient#matewa-client-mail-delivery-options')); exit; } $subject = 'Test: 247ChatMate client mail delivery route'; $message = '
This confirms the selected client-site mail route can send lead alerts and weekly summaries.
' . 'Site: ' . esc_html(wp_parse_url(home_url(), PHP_URL_HOST)) . '
' . 'Most clients can leave this alone. Use the managed sender for simple fallback delivery, or open client SMTP only when their IT/email provider gives SMTP details.
Security: SMTP passwords are never printed back into the page. Blank password fields keep the saved value. Agency-imported client sites can still change these local settings after the setup pack is pushed.