虽然此答案的某些部分仅适用于mail()
函数本身的用法,但这些故障排除步骤可以应用于任何PHP邮件系统。
您的脚本似乎无法发送电子邮件有很多原因。除非存在明显的语法错误,否则很难诊断这些问题。如果没有语法错误,则需要运行以下检查清单以查找可能遇到的任何潜在问题。
确保启用错误报告并设置为报告所有错误
错误报告对于查找代码中的错误和PHP遇到的一般错误至关重要。需要启用错误报告才能接收这些错误。将以下代码放置在您的PHP文件顶部(或主配置文件中)将启用错误报告。
error_reporting(-1);
ini_set('display_errors', 'On');
set_error_handler("var_dump");
请参阅 如何在PHP中获取有用的错误消息? - 本答案,了解更多相关信息。
确保正确调用mail()
函数
这可能看起来很愚蠢,但常见的错误是忘记在代码中实际放置mail()
函数。确保它存在并且未被注释掉。
确保正确调用mail()
函数
bool mail ( string $to, string $subject, string $message [, string $additional_headers [, string $additional_parameters ]] )
mail函数需要三个必需参数和可选的第四个和第五个参数。如果您对mail()
的调用没有至少三个参数,则会失败。
如果mail()
的调用没有按正确顺序使用正确的参数,则也会失败。
检查服务器的邮件日志
你的Web服务器应该记录所有尝试通过它发送电子邮件的操作。这些日志的位置会有所不同(您可能需要询问您的服务器管理员),但通常可以在用户的根目录下的logs文件夹中找到。其中将包含与您发送电子邮件相关的任何服务器报告的错误消息。
检查端口连接失败
端口屏蔽是大多数开发人员在使用SMTP发送电子邮件时遇到的常见问题。这可以很容易地在服务器邮件日志中跟踪(邮件日志的位置因服务器而异,如上所述)。如果您在共享托管服务器上,则默认情况下会阻止25号和587号端口。您的托管提供商有意进行此阻止。即使对于一些专用服务器也是如此。当这些端口被阻止时,请尝试使用2525号端口进行连接。如果您发现该端口也被阻止,则唯一的解决方案是联系您的托管提供商以解除对这些端口的阻止。
大多数托管提供商都会阻止这些电子邮件端口,以保护其网络免受发送垃圾邮件的影响。
使用25号或587号端口进行普通/TLS连接,使用465号端口进行SSL连接。对于大多数用户,建议使用587号端口以避免某些托管提供商设置的速率限制。
不要使用错误抑制运算符
在 PHP 中,如果在表达式前添加错误抑制运算符@
,那么该表达式可能产生的任何错误消息都将被忽略。有些情况下使用此运算符是必要的,但发送邮件则不是其中之一。
如果您的代码包含@mail(...)
,那么您可能正在隐藏重要的错误消息,这些错误消息将帮助您进行调试。请删除@
并查看是否报告了任何错误。
仅当您随后使用error_get_last()
检查具体失败时才建议使用它。
检查mail()
返回值
mail()
函数:
如果邮件成功被接收并投递,则返回
TRUE
,否则返回
FALSE
。需要注意的是,即使邮件已经被接收并投递,也不意味着邮件一定会到达预期的目的地。
这很重要,因为:
- 如果您收到
FALSE
的返回值,则知道错误出现在您的服务器接受您的邮件上。这可能不是编程问题,而是服务器配置问题。您需要与系统管理员联系以找出原因。
- 如果您收到
TRUE
的返回值,并不意味着您的电子邮件一定会被发送。它只是表示PHP将电子邮件成功地发送到服务器上的相应处理程序。仍然有更多的失败点在PHP控制之外,可能导致电子邮件无法发送。
因此,
FALSE
将帮助指引您正确的方向,而
TRUE
并不一定意味着您的电子邮件已成功发送。这很重要!
请确保您的托管提供商允许您发送电子邮件,并且不限制邮件发送。
许多共享网络主机,特别是免费的网络托管提供商,要么不允许从他们的服务器发送电子邮件,要么限制在任何给定时间段内可以发送的数量。这是由于他们努力限制垃圾邮件发送者利用他们更便宜的服务。
如果您认为您的主机有电子邮件限制或阻止发送电子邮件,请查看他们的FAQ以查看是否列出了任何此类限制。否则,您可能需要联系他们的支持人员以验证是否存在任何关于发送电子邮件的限制。
检查垃圾邮件文件夹;防止电子邮件被标记为垃圾邮件
通常,由于各种原因,通过PHP(和其他服务器端编程语言)发送的电子邮件最终会进入收件人的垃圾邮件文件夹。在排除代码故障之前,请始终检查该文件夹。
为避免通过PHP发送的邮件被发送到收件人的垃圾邮件文件夹中,您可以在您的PHP代码和其他方面采取各种措施,以最小化将您的电子邮件标记为垃圾邮件的机会。
Michiel de Mare提供的好建议包括:
请使用电子邮件验证方法,例如
SPF 和
DKIM,以证明您的电子邮件和您的域名属于同一实体,并防止欺诈行为。 SPF 网站提供了生成站点 DNS 信息的向导。
检查您的
反向DNS,确保您的邮件服务器的 IP 地址指向您用于发送邮件的域名。
确保您使用的 IP 地址
未被列入黑名单。
确保答复地址是有效的、存在的地址。
在收件人字段中使用完整的真实姓名,而不仅仅是电子邮件地址(例如
“John Smith”<john@blacksmiths-international.com>
)。
监控您的滥用账户,例如
abuse@yourdomain.example
和
postmaster@yourdomain.example
。这意味着 - 确保这些账户存在,阅读发送到它们的内容,并对投诉作出回应。
最后,请确保取消订阅非常容易。否则,您的用户将通过点击
垃圾邮件按钮来取消订阅,这会影响您的声誉。
请参阅如何确保通过编程发送的电子邮件不会被自动标记为垃圾邮件?了解更多相关信息。
确保提供所有邮件头
一些垃圾邮件软件会拒绝缺少常见邮件头,如“发件人”和“回复地址”的邮件:
$headers = array("From: from@example.com",
"Reply-To: replyto@example.com",
"X-Mailer: PHP/" . PHP_VERSION
);
$headers = implode("\r\n", $headers);
mail($to, $subject, $message, $headers);
确保邮件头没有语法错误
无效的邮件头和没有邮件头一样糟糕。一个不正确的字符可能足以使您的电子邮件出现故障。请仔细检查您的语法是否正确,因为PHP不会为您捕获这些错误。
$headers = array("From from@example.com", // missing colon
"Reply To: replyto@example.com", // missing hyphen
"X-Mailer: "PHP"/" . PHP_VERSION // bad quotes
);
不要使用伪造的From:
发送者
虽然邮件必须有一个发件人,但您不能随意使用任何值。特别是用户提供的发件人地址是被阻止邮件的一种可靠方法:
$headers = array("From: $_POST[contactform_sender_email]"); // No!
原因:您的网站或发送邮件服务器未被SPF / DKIM白名单列入@ hotmail或@gmail地址的负责人。它甚至可能会静默丢弃未配置
From:
发送者域的邮件。
确保收件人值正确
有时问题就像电子邮件的接收者值不正确那么简单。这可能是由于使用了错误的变量导致的。
$to = 'user@example.com';
// other variables ....
mail($recipient, $subject, $message, $headers); // $recipient should be $to
另一种测试方法是将收件人的值硬编码到mail()
函数调用中:
mail('user@example.com', $subject, $message, $headers);
这适用于所有的
mail()
参数。
发送到多个帐户
为了排除电子邮件账户问题,请将您的电子邮件发送至不同电子邮件提供商的多个电子邮件帐户。如果您的电子邮件未到达用户的Gmail帐户,请将相同的电子邮件发送到Yahoo帐户、Hotmail帐户和常规POP3帐户(例如由您的ISP提供的电子邮件帐户)。
如果电子邮件到达所有或某些其他电子邮件帐户,则表明您的代码正在发送电子邮件,但电子邮件帐户提供商可能因某种原因阻止它们。如果电子邮件没有到达任何电子邮件帐户,则问题更可能与您的代码有关。
确保代码与表单方法匹配
如果您将表单方法设置为
POST
,请确保使用
$_POST
查找您的表单值。如果您将其设置为
GET
或根本未设置,则请确保使用
$_GET
查找您的表单值。
确保表单action
值指向正确的位置
请确保您的表单action
属性包含指向您的PHP邮件代码的值。
<form action="send_email.php" method="POST">
确保Web主机支持发送电子邮件
一些Web主机提供商不允许或启用通过其服务器发送电子邮件。原因可能各不相同,但如果他们禁用了邮件发送,则需要使用第三方方法来替代发送这些电子邮件。
在访问在线支持或FAQ后,给他们的技术支持发送一封电子邮件应该可以澄清服务器上是否可用电子邮件功能。
确保localhost
邮件服务器已配置
如果您正在使用WAMP、MAMP或XAMPP在本地工作站上开发,则可能没有安装电子邮件服务器。在没有电子邮件服务器的情况下,默认情况下PHP无法发送邮件。
您可以通过安装基本的邮件服务器来解决此问题。对于Windows用户,您可以使用免费的Mercury Mail。
您还可以使用SMTP发送电子邮件。请参见Vikas Dwivedi的this great answer以了解如何执行此操作。
启用PHP的自定义mail.log
除了您的MTA和PHP日志文件外,您还可以专门启用mail()
函数的记录。它不记录完整的SMTP交互,但至少记录函数调用参数和调用脚本。
ini_set("mail.log", "/tmp/mail.log");
ini_set("mail.add_x_header", TRUE);
请参阅http://php.net/manual/en/mail.configuration.php以了解详情。(最好在php.ini
或.user.ini
或.htaccess
中启用这些选项。)
使用邮件测试服务进行检查
有各种递送和垃圾邮件检测服务可供您测试MTA / webserver设置。通常,您发送一个邮件探针到他们的地址,然后稍后获取递送报告和更具体的故障或分析:
使用不同的邮件发送器
PHP内置的
mail()
函数很方便,通常可以完成工作,但它
存在缺陷。幸运的是,有一些替代方案提供更多的功能和灵活性,包括处理上述问题中的许多问题:
所有这些都可以与专业的SMTP服务器/服务提供商结合使用。(因为典型的08/15共享Web托管计划在电子邮件设置/可配置性方面时好时坏。)
$from
。 - Artem Ilchenkomail()
发送电子邮件到自己的域时,它不会检查 DNS 记录以找到正确的邮件服务器,而只是将电子邮件转发给自己。我写了一篇关于这个问题的文章,详细介绍了解决方法:https://blog.terresquall.com/2021/04/php-mail-fails-send-emails-to-own-domain-email-addresses/ - John Doe