PHP 邮件函数没有完成电子邮件的发送

新手上路,请多包涵
<?php
    $name = $_POST['name'];
    $email = $_POST['email'];
    $message = $_POST['message'];
    $from = 'From: yoursite.com';
    $to = 'contact@yoursite.com';
    $subject = 'Customer Inquiry';
    $body = "From: $name\n E-Mail: $email\n Message:\n $message";

    if ($_POST['submit']) {
        if (mail ($to, $subject, $body, $from)) {
            echo '<p>Your message has been sent!</p>';
        } else {
            echo '<p>Something went wrong, go back and try again!</p>';
        }
    }
?>

我试过创建一个简单的邮件表单。表单本身在我的 index.html 页面上,但它提交到一个单独的“感谢您提交”页面 thankyou.php ,其中嵌入了上述 PHP 代码。代码完美提交,但从不发送电子邮件。我怎样才能解决这个问题?

原文由 user3818620 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 546
1 个回答

尽管此答案的某些部分仅适用于 mail() 函数本身的使用,但其中许多故障排除步骤可应用于任何 PHP 邮件系统。

您的脚本似乎没有发送电子邮件的原因有多种。除非有明显的语法错误,否则很难诊断这些东西。如果没有,您需要通过下面的清单来查找您可能遇到的任何潜在陷阱。

确保错误报告已启用并设置为报告所有错误

错误报告对于根除代码中的错误和 PHP 遇到的一般错误至关重要。需要启用错误报告才能接收这些错误。将以下代码放在 PHP 文件的顶部(或主配置文件中)将启用错误报告。

 error_reporting(-1);
ini_set('display_errors', 'On');
set_error_handler("var_dump");

请参阅 如何在 PHP 中获取有用的错误消息? - 这个答案 有关此的更多详细信息。

确保调用了 mail() 函数

这可能看起来很愚蠢,但一个常见的错误是忘记在您的代码中实际放置 mail() 函数。确保它在那里并且没有被注释掉。

确保 mail() 函数被正确调用

布尔邮件(字符串\(to,字符串\)subject,字符串\(message \[,字符串\)additional_headers [,字符串$additional_parameters]])

邮件函数采用三个必需参数以及可选的第四个和第五个参数。如果您对 mail() 的调用没有至少三个参数,它将失败。

如果您对 mail() 的调用没有正确顺序的正确参数,它也会失败。

检查服务器的邮件日志

您的网络服务器应该记录所有通过它发送电子邮件的尝试。这些日志的位置会有所不同(您可能需要询问您的服务器管理员它们位于何处),但它们通常可以在用户根目录下的 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 并不 一定意味着您的电子邮件已成功发送。这一点很重要!

确保您的托管服务提供商允许您发送电子邮件并且不限制邮件发送

许多共享虚拟主机,尤其是免费虚拟主机提供商,要么不允许从他们的服务器发送电子邮件,要么限制在任何给定时间段内可以发送的邮件数量。这是由于他们努力限制垃圾邮件发送者利用他们更便宜的服务。

如果您认为您的主机有电子邮件限制或阻止发送电子邮件,请查看他们的常见问题解答,看看他们是否列出了任何此类限制。否则,您可能需要联系他们的支持人员,以验证发送电子邮件是否存在任何限制。

检查垃圾邮件文件夹;防止电子邮件被标记为垃圾邮件

通常,出于各种原因,通过 PHP(和其他服务器端编程语言)发送的电子邮件最终会进入收件人的垃圾邮件文件夹。在对您的代码进行故障排除之前,请始终检查那里。

为避免通过 PHP 发送的邮件被发送到收件人的垃圾邮件文件夹,您可以在 PHP 代码和其他方面执行多种操作,以最大限度地减少电子邮件被标记为垃圾邮件的可能性。 Michiel de Mare 的好建议包括:

  • 使用 SPFDKIM 等电子邮件身份验证方法来证明您的电子邮件和您的域名属于同一类,并防止您的域名被盗用。 SPF 网站包含一个向导,用于为您的站点生成 DNS 信息。
  • 检查 您的 反向 DNS 以确保您的邮件服务器的 IP 地址指向您用于发送邮件的域名。
  • 确保您使用的 IP 地址 不在黑名单中
  • 确保回复地址是有效的现有地址。
  • 在“收件人”字段中使用收件人的完整真实姓名,而不仅仅是电子邮件地址(例如 "John Smith" <john@blacksmiths-international.com> )。
  • 监控您的滥用账户,例如 abuse@yourdomain.examplepostmaster@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 托管提供商不允许或不允许通过其服务器发送电子邮件。这样做的原因可能各不相同,但如果他们禁止发送邮件,您将需要使用另一种方法,即使用第三方为您发送这些电子邮件。

给他们的技术支持的电子邮件(在访问他们的在线支持或常见问题解答之后)应该说明您的服务器上是否提供电子邮件功能。

确保配置了 localhost 邮件服务器

如果您使用 WAMP、MAMP 或 XAMPP 在本地工作站上进行开发,则您的工作站上可能没有安装电子邮件服务器。没有一个,PHP 默认不能发送邮件。

您可以通过安装一个基本的邮件服务器来克服这个问题。对于 Windows,您可以使用免费的 Mercury Mail

您还可以使用 SMTP 发送电子邮件。请参阅 Vikas Dwivedi精彩回答,了解如何执行此操作。

启用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/网络服务器设置。通常,您将邮件探测发送至:他们的地址,然后获得送达报告和更具体的故障或稍后分析:

使用不同的邮件程序

PHP 的内置 mail() 函数很方便,经常可以完成工作,但它 也有缺点。幸运的是,有一些替代方案可以提供更多的功能和灵活性,包括处理上面列出的许多问题:

所有这些都可以与专业的 SMTP 服务器/服务提供商结合使用。 (因为在电子邮件设置/可配置性方面,典型的 08/15 共享虚拟主机计划受到打击或失败。)

原文由 John Conde 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题