WordPress · 11 phút đọc · 2026-09-08
WordPress không gửi được email: vì sao wp_mail trả true
wp_mail trả true chưa có nghĩa thư đã tới hộp thư người nhận. Cần khoanh lỗi ở PHPMailer, Mailpit, From và luồng biểu mẫu trước khi đổi sang SMTP.

wordpress không gửi được email nhưng chưa chắc lỗi nằm ở wp_mail. Trước khi sửa, cần biết thư dừng ở lúc tạo nội dung, lúc PHPMailer xử lý, hay sau khi máy chủ nhận thư. Bài này đi theo bằng chứng: kiểm tra kết quả của wp_mail, ghi lỗi wp_mail_failed, bắt thư bằng Mailpit, rồi mới quyết định có sửa From, dùng SMTP hay xem lại luồng biểu mẫu.
wp_mail trả true nhưng không nhận được email: khoanh điểm dừng trước khi sửa
wp_mail trả true nhưng không nhận được email chỉ cho biết WordPress đã gọi quy trình gửi mà không gặp lỗi bị ném ra ở thời điểm đó. Tài liệu WordPress về wp_mail() cũng lưu ý rằng giá trị true không đồng nghĩa thư chắc chắn đến hộp thư người nhận. Vì vậy, đừng bắt đầu bằng việc cài thêm plugin SMTP. Hãy ghi lại địa chỉ người nhận, thời điểm gửi, tiêu đề, địa chỉ From và luồng tạo thư; sau đó kiểm tra lại bằng một địa chỉ hộp thư khác mà bạn kiểm soát. Nếu wp_mail() trả false, chuyển ngay sang hook wp_mail_failed ở mục kế tiếp. Nếu trả true, chưa thể kết luận thư đã rời máy chủ.
Chia phép thử thành ba chặng. Chặng đầu là trước khi WordPress bàn giao thư: biểu mẫu có chạy hàm gửi không, thao tác đặt lại mật khẩu có tạo yêu cầu không, địa chỉ nhận có bị rỗng hoặc sai không. Chặng giữa là mailer: PHPMailer có tạo được kết nối và truyền thư cho máy chủ không. Chặng cuối là sau khi máy chủ nhận: thư có vào hộp thư rác, bị tuyến nhận từ chối, bị bộ lọc doanh nghiệp giữ lại, hay bị trả về. Nút "gửi thư kiểm tra" báo hỏng cũng chưa nói chặng nào hỏng; một nút kiểm tra thường chỉ thử đường gửi cơ bản, không tái hiện đầy đủ điều kiện của biểu mẫu hoặc đặt lại mật khẩu.
Mở nhật ký ứng dụng hoặc thêm ghi nhận tạm thời quanh nơi gọi wp_mail, rồi thực hiện một phép thử có thể lặp lại. Ghi dấu trước khi gọi, kết quả trả về ngay sau khi gọi và địa chỉ nhận đã che bớt phần nhạy cảm; dấu trước có mà dấu sau không có thì lỗi nằm trong luồng gọi hoặc mã bị dừng, còn cả hai dấu đều có nhưng không thấy thư thì kiểm tra log mailer và máy chủ. Nếu wp_mail() trả true, xem tiếp log gửi của nhà cung cấp hoặc máy chủ nhận, rồi kiểm tra thư rác và thư bị trả về. Chỉ khi có bằng chứng thư đã được máy chủ chuyển tiếp mà người nhận không thấy mới chuyển trọng tâm sang bộ lọc hoặc chính sách tuyến nhận.
WordPress không gửi được email: wp_mail trả false và ghi lỗi PHPMailer vào log
Khi wp_mail() trả false, tạo một mu-plugin để bắt lỗi thay vì sửa nhiều nơi cùng lúc. Tạo thư mục wp-content/mu-plugins nếu chưa có, rồi tạo tệp ghi-loi-wp-mail.php. Tài liệu WordPress mô tả wp_mail_failed là hook nhận đối tượng WP_Error khi PHPMailer gặp lỗi; đoạn mã dưới đây ghi thông báo và một phần dữ liệu thư vào debug.log. Không ghi mật khẩu, mã xác thực hoặc toàn bộ nội dung biểu mẫu vào log.
<?php
/**
* Plugin Name: Ghi lỗi wp_mail tạm thời
*/
add_action(
'wp_mail_failed',
function ( $error ) {
if ( ! defined( 'WP_DEBUG' ) || ! WP_DEBUG ) {
return;
}
/*
* CHỈ ghi thông báo lỗi và vài con số. KHÔNG ghi $error->get_error_data():
* WordPress nhét cả mảng thư vào đó, gồm 'message' — tức nội dung thư, và với
* thư đặt lại mật khẩu thì đó là nguyên cái liên kết đặt lại. Ghi nó vào
* debug.log là để lộ khoá cho bất kỳ ai đọc được tệp log.
*/
$du_lieu = $error->get_error_data();
$so_nguoi_nhan = is_array( $du_lieu ) && isset( $du_lieu['to'] )
? count( (array) $du_lieu['to'] )
: 0;
error_log(
'wp_mail_failed: ' . wp_json_encode(
array(
'message' => $error->get_error_message(),
'so_nguoi_nhan' => $so_nguoi_nhan,
'luc' => gmdate( 'c' ),
),
JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES
)
);
}
);Bật ghi log trong wp-config.php nếu hệ thống của bạn chưa bật, đặt các dòng này trước dòng kết thúc cấu hình mà WordPress yêu cầu. Sau đó lưu tệp mu-plugin, thực hiện đúng thao tác gây lỗi và mở wp-content/debug.log. Dấu hiệu đã xong là bạn thấy một dòng bắt đầu bằng wp_mail_failed cùng thông báo PHPMailer; nếu không có dòng nào, wp_mail_failed chưa được kích hoạt trong phép thử đó hoặc log đang ghi sang vị trí khác. Đường lùi: nếu trang bị lỗi sau khi thêm tệp, đổi tên tệp để WordPress không nạp nó, khôi phục bản sao wp-config.php, rồi kiểm tra lỗi cú pháp bằng nhật ký máy chủ.
define( 'WP_DEBUG', true );
define( 'WP_DEBUG_LOG', true );
define( 'WP_DEBUG_DISPLAY', false );Đọc phần message trước khi chọn cách sửa. Lỗi thiếu địa chỉ người nhận hoặc tiêu đề sai thường quay về mã tạo thư; lỗi kết nối, xác thực hoặc máy chủ từ chối mới liên quan đến mailer hoặc tuyến SMTP. Đây là log quan sát, không phải bản sửa; giữ nó lâu dài có thể làm lộ dữ liệu thư trong máy chủ. Sau khi đã có bằng chứng, gỡ mu-plugin hoặc đổi nó thành phiên bản chỉ ghi lỗi tối thiểu theo chính sách lưu log của bạn, rồi tắt chế độ gỡ lỗi trên trang công khai. Nếu wp_mail() vẫn trả false nhưng log không đủ chi tiết, kiểm tra log PHP và log của máy chủ gửi; tôi chưa thể biết thông báo cụ thể nếu chưa thấy cấu hình và phiên bản PHPMailer của hệ thống đó.
Đừng chỉ bấm Email Test: tái hiện reset mật khẩu và Contact Form 7 trong Mailpit
Nút Email Test chỉ trả lời câu hỏi “đường gửi cơ bản có tạo được thư không”. Nó không kiểm tra người dùng có được phép đặt lại mật khẩu, biểu mẫu có chạy hook gửi thư, trường email có được dùng làm Reply-To, hay địa chỉ nhận có bị thay đổi bởi mã tùy biến. Vì vậy, hãy thực hiện hai phép thử riêng: yêu cầu đặt lại mật khẩu từ màn hình đăng nhập, rồi gửi một biểu mẫu Contact Form 7 với dữ liệu giả lập. Nếu thư đặt lại mật khẩu không tới mà thư kiểm tra vẫn đến, lỗi có thể nằm ở luồng đặt lại hoặc bộ lọc người nhận, chưa đủ căn cứ để kết luận SMTP hỏng. Nếu biểu mẫu liên hệ không gửi được mà thư đặt lại mật khẩu vẫn tới, kiểm tra phần Mail của biểu mẫu.
Mailpit là máy chủ SMTP dùng để bắt thư trong môi trường kiểm thử; tài liệu Mailpit mô tả giao diện web để xem thư đã nhận, người gửi, người nhận, tiêu đề và header. Chỉ trỏ môi trường thử nghiệm vào Mailpit, không trỏ trang đang phục vụ khách thật nếu thư đặt lại mật khẩu có thể chứa liên kết thật. Theo tài liệu cài đặt Mailpit, cách chạy phụ thuộc hệ điều hành hoặc môi trường chứa; hãy dùng đúng lệnh trong tài liệu phiên bản bạn cài, rồi cấu hình ứng dụng trỏ đến máy chủ và cổng Mailpit hiển thị. Dấu hiệu đã xong là giao diện Mailpit mở được và có thể nhìn thấy một thư thử; nếu không có thư, kiểm tra lại địa chỉ máy chủ, cổng và firewall trước khi động vào Contact Form 7.
Thực hiện lần lượt việc đặt lại mật khẩu và gửi biểu mẫu, ghi lại thời gian, rồi làm mới Mailpit. Nếu thư xuất hiện trong Mailpit, WordPress và mailer đã tạo được thư; đọc To, From, Reply-To, tiêu đề và nội dung để kiểm tra lỗi nghiệp vụ. Nếu thư không xuất hiện nhưng log wp_mail_failed có lỗi, sửa chặng PHPMailer; nếu không xuất hiện và không có lỗi, quay về điểm gọi hoặc cấu hình log. Nếu Mailpit nhận thư đúng nhưng hộp thư thật không nhận, phép thử đã tách được lỗi sau chặng WordPress; lúc đó kiểm tra máy chủ chuyển tiếp, bộ lọc và chính sách tuyến nhận. Sau phép thử, trả cấu hình môi trường về tuyến gửi thật và xác nhận không còn thư kiểm thử bị giữ trong Mailpit.
![Giao diện Mailpit sau khi tái hiện hai phép thử: hộp thư có 2 thư chưa đọc. Thư trên là "[Cửa hàng mẫu] Thiết lập lại mật khẩu" gửi tới demo@wp-demo.local, kích thước 1,1 kB; thư dưới là thư kiểm tra 583 B. Cả hai đều đến nơi, nghĩa là WordPress đã tạo và giao được thư.](/media/2026/09/mailpit-hop-thu-bat-duoc-eba2c5c4.webp)
Sửa From mặc định bằng mu-plugin, rồi đọc header thay vì đoán Return-Path
Nếu thư bị từ chối vì địa chỉ gửi không phù hợp, thử bản vá nhỏ cho From và tên hiển thị trước khi đổi toàn bộ mailer. Tài liệu WordPress cung cấp các bộ lọc wp_mail_from và wp_mail_from_name; tạo tệp mu-plugin riêng để có thể gỡ dễ dàng. Thay địa chỉ bên dưới bằng hộp thư thuộc miền của bạn, không dùng địa chỉ khách điền biểu mẫu làm From chỉ vì muốn bấm trả lời là tới khách.
<?php
/**
* Plugin Name: Đặt From mặc định cho WordPress
*/
add_filter(
'wp_mail_from',
function () {
return 'no-reply@example.com';
}
);
add_filter(
'wp_mail_from_name',
function () {
return 'Tên cửa hàng';
}
);Lưu tệp vào wp-content/mu-plugins/dat-from-mac-dinh.php, thực hiện lại phép thử trong Mailpit, rồi mở phần header của thư. Dấu hiệu đã xong là From hiển thị đúng địa chỉ và tên bạn đặt; kiểm tra header, không đoán từ tên hiển thị trong giao diện. Return-Path có thể do máy chủ gửi hoặc dịch vụ chuyển tiếp đặt lại, nên bản vá này không đảm bảo thay đổi được nó. Nếu From không đổi, kiểm tra xem plugin khác hoặc một callback khác gắn vào cùng bộ lọc với độ ưu tiên lớn hơn, một plugin SMTP, hoặc mã can thiệp ở phpmailer_init hay không; đường lùi là đổi tên mu-plugin, kiểm tra lại rồi khôi phục tệp cũ.
Bản vá chỉ sửa giá trị mặc định mà WordPress đưa vào thư; nó không cấp quyền gửi cho miền, không tạo bản ghi xác thực miền và không biến PHP mail thành SMTP. Với thư Contact Form 7, khách vẫn nên nằm ở Reply-To để khi bạn bấm trả lời, thư quay về khách mà From vẫn thuộc địa chỉ được phép gửi. Trong phần Mail của biểu mẫu, đặt From là địa chỉ cửa hàng, còn Reply-To là mail-tag của trường email; tên mail-tag tùy cấu hình biểu mẫu, nên đối chiếu đúng tên đang dùng. Gửi lại một biểu mẫu thử và xem header From cùng Reply-To; nếu tuyến gửi loại bỏ hoặc thay đổi header, cần xem tài liệu tuyến đó thay vì tiếp tục sửa mu-plugin.

Chỉ chọn SMTP sau khi biết chặng lỗi: plugin, code và tài khoản Gmail
SMTP phù hợp khi bằng chứng cho thấy WordPress tạo thư nhưng tuyến gửi mặc định không truyền được, hoặc máy chủ yêu cầu xác thực mà cấu hình hiện tại không có. Có hai hướng vận hành. Plugin SMTP cho phép người phụ trách một mình đổi máy chủ, cổng, mã hóa và kiểm tra trong màn hình quản trị; đổi lại, cần kiểm soát quyền quản trị, cập nhật plugin và cách lưu bí mật. Tự cấu hình bằng mã giúp thay đổi nằm trong phiên bản mã của dự án, nhưng bạn phải tự bảo vệ thông tin xác thực và tự xây dựng cách kiểm tra. Một plugin SMTP báo gửi hỏng cũng chưa phải lý do đủ để cài thêm plugin nữa; trước hết phải biết lỗi là kết nối, xác thực, địa chỉ gửi hay chặng nhận.
Nếu chọn plugin, cài từ nguồn bạn kiểm tra được, nhập thông tin do nhà cung cấp tuyến gửi cấp, lưu cấu hình trong môi trường thử nghiệm rồi gửi thư đến hộp thư kiểm soát. Nếu chọn mã, dùng giao diện hoặc hook được thư viện mailer hỗ trợ thay vì sửa trực tiếp tệp lõi WordPress. Trong cả hai hướng, dấu hiệu đã xong không chỉ là nút kiểm tra báo thành công: Mailpit hoặc log tuyến gửi phải cho thấy thư được nhận, header có From đúng, và phép thử đặt lại mật khẩu hoặc Contact Form 7 cũng tạo đúng thư. Đường lùi là khôi phục cấu hình mailer trước đó, tắt plugin mới hoặc đổi tên mu-plugin; đừng để hai cấu hình SMTP cùng can thiệp vì khi đó log khó chỉ ra ai đã thay đổi thư.
Nếu định gửi qua Gmail, đừng coi mật khẩu Gmail thường ngày là thứ điền vào ô mật khẩu SMTP. Tài liệu Google về SMTP và xác thực tài khoản có thể thay đổi theo loại tài khoản, chính sách tổ chức và phương thức xác thực đang được phép; tuyến gửi có thể yêu cầu danh tính, thông tin xác thực hoặc cơ chế riêng. Hãy đọc tài liệu của tuyến gửi, xác nhận tài khoản có quyền gửi, rồi kiểm tra địa chỉ From có được tuyến đó cho phép hay không. Nếu From là địa chỉ khác tài khoản xác thực, Gmail hoặc tuyến gửi có thể thay đổi, từ chối hoặc xử lý khác; tôi chưa thể khẳng định hành vi cụ thể nếu chưa biết loại tài khoản và chính sách hiện tại.
Không đặt bí mật SMTP trực tiếp trong mã chia sẻ hoặc kho mã. Dùng biến môi trường hay cơ chế lưu bí mật mà máy chủ của bạn hỗ trợ, rồi kiểm tra log để chắc chắn không in ra mật khẩu, mã ứng dụng hoặc nội dung liên kết đặt lại mật khẩu. Phần lớn ca WordPress không gửi được email kết thúc ở đây: không phải vì bạn tìm ra plugin đúng, mà vì cuối cùng đã nhìn thấy thư dừng ở chặng nào. Sau khi SMTP hoạt động, giữ lại một phép thử nghiệp vụ cho đặt lại mật khẩu và một phép thử cho Contact Form 7; nếu chỉ Email Test thành công, chẩn đoán vẫn chưa hoàn tất.
- Tác giả
- Quản trị viên
- Đăng ngày
- 2026-09-08
- Cập nhật
- 2026-09-08
- Thời gian đọc
- 11 phút đọc
- Tất cả bài viết