订单触发后定时发送自定义邮件插件无法正常发送问题排查
问题描述
我正在开发一款WordPress插件,功能是在用户订单状态触发指定条件后,延迟设定时长给客户发送自定义评价请求邮件。目前遇到的问题是邮件既没发送也没被接收——已经确认插件配置项全部正确,且WooCommerce自带的订单确认邮件能正常送达客户。相关代码如下:
public function schedule_review_email($order_id, $old_status, $new_status) { $settings = get_option('fast_reviews_settings'); if (!$settings || empty($settings['trigger_status']) || empty($settings['send_after_value']) || empty($settings['send_after_unit'])) { error_log("Fast Reviews settings are not properly configured."); return; } error_log("schedule_review_email triggered for Order ID: $order_id, Old Status: $old_status, New Status: $new_status"); if ($new_status === $settings['trigger_status']) { $delay = intval($settings['send_after_value']); $unit = sanitize_text_field($settings['send_after_unit']); $valid_units = ['seconds', 'minutes', 'hours', 'days']; if (!in_array($unit, $valid_units)) { error_log("Invalid time unit provided: $unit"); return; } $unit_multiplier = $unit === 'seconds' ? 1 : ($unit === 'minutes' ? 60 : ($unit === 'hours' ? 3600 : 86400)); $schedule_timestamp = time() + $delay * $unit_multiplier; error_log("Scheduling email for Order ID: $order_id to be sent after $delay $unit at timestamp: $schedule_timestamp"); wp_clear_scheduled_hook('fast_reviews_send_email', [$order_id]); wp_schedule_single_event($schedule_timestamp, 'fast_reviews_send_email', [$order_id]); } else { error_log("No action taken for Order ID: $order_id. New status does not match trigger status."); } } public function send_review_email($order_id) { $order = wc_get_order($order_id); if (!$order) { error_log("Order not found for Order ID: $order_id"); return; } $customer_name = $order->get_billing_first_name(); $order_number = $order->get_order_number(); $customer_email = $order->get_billing_email(); if (empty($customer_email)) { error_log("No billing email found for Order ID: $order_id"); return; } error_log("Preparing to send review email for Order ID: $order_id, Customer Name: $customer_name, Order Number: $order_number"); // Retrieve email settings $settings = get_option('fast_reviews_settings'); if (!$settings) { error_log("Fast Reviews settings not found."); return; } $review_url = isset($settings['review_url']) ? esc_url($settings['review_url']) : ''; $trustpilot_url = isset($settings['trustpilot_url']) ? esc_url($settings['trustpilot_url']) : ''; $subject = isset($settings['email_subject']) ? sanitize_text_field($settings['email_subject']) : 'Review Request'; $content = isset($settings['email_content']) ? str_replace( ['{customer_name}', '{order_number}', '{review_url}', '{trustpilot_url}'], [$customer_name, $order_number, $review_url, $trustpilot_url], wpautop($settings['email_content']) // Convert line breaks to HTML <p> tags ) : ''; $headers = [ 'Content-Type: text/html; charset=UTF-8', 'From: Your Company Name <noreply@yourdomain.com>', // Customize From address 'Reply-To: support@yourdomain.com' // Customize Reply-To address ]; $max_attempts = 3; $sent = false; for ($attempts = 1; $attempts <= $max_attempts; $attempts++) { error_log("Attempt $attempts: Sending email to: $customer_email, Subject: $subject"); $sent = wp_mail($customer_email, $subject, $content, $headers); if ($sent) { error_log("Email sent successfully to: $customer_email"); break; } else { error_log("Attempt $attempts: Failed to send email to: $customer_email"); if ($attempts < $max_attempts) { sleep(5); } } } }
排查建议
- 确认定时任务是否执行:WordPress的
wp_schedule_single_event依赖WP-Cron,而WP-Cron是靠网站请求触发的,低访问量网站可能导致任务延迟/不执行。可以用WP Crontrol插件查看fast_reviews_send_email钩子是否被正确调度,或者手动访问wp-cron.php触发任务测试。 - 检查钩子绑定是否遗漏:确保插件初始化时已经把
send_review_email函数和fast_reviews_send_email钩子绑定,比如添加:add_action('fast_reviews_send_email', [$this, 'send_review_email']);,这是最容易遗漏的环节。 - 验证邮件头与内容:
- 发件人地址
noreply@yourdomain.com必须是域名下的有效邮箱,避免被反垃圾系统拦截; - 测试时可以暂时去掉
wpautop,用纯文本内容发送,排除HTML格式导致的问题; - 确保配置的
review_url等变量不为空,避免替换后内容出现异常。
- 发件人地址
- 查看服务器日志:检查PHP错误日志和服务器邮件服务日志(如Postfix/Exim日志),确认
wp_mail是否被正常调用,有没有被服务器防火墙或邮件服务拒绝。 - 替换邮件发送方式:既然系统自带邮件能正常发送,可以临时改用WooCommerce的邮件类发送测试,比如:
$mailer = WC()->mailer(); $mailer->send( $customer_email, $subject, $content, $headers );
内容的提问来源于stack exchange,提问作者Ghassen Larnaout
相关产品推荐
相关产品推荐

