提问者:小点点

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 for your submission”页面,Thankyou.PHP,上面的PHP代码就嵌入其中。 代码提交得很完美,但从不发送电子邮件。 我该怎么解决这个问题?


共3个答案

匿名用户

虽然这个答案的某些部分只适用于mail()函数本身的使用,但是这些故障排除步骤中的许多都可以应用于任何PHP邮件系统。

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

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

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

查看如何在PHP中获得有用的错误消息? -此答案可了解更多有关此问题的详细信息。

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

bool mail(字符串$TO,字符串$Subject,字符串$Message[,字符串$ADDITIONAL_HEADERS[,字符串$ADDITIONAL_PARAMETERS]])

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

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

您的web服务器应该记录所有通过它发送电子邮件的尝试。 这些日志的位置会有所不同(您可能需要询问服务器管理员它们的位置),但通常可以在用户的根目录logs下找到它们。 内部将是服务器报告的错误消息,如果有的话,与您发送电子邮件的尝试有关。

端口块是一个非常常见的问题,大多数开发人员在集成代码以使用SMTP传递电子邮件时都面临这个问题。 而且,这可以很容易地在服务器邮件日志中跟踪(邮件日志的服务器位置可能因服务器而异,如上所述)。 如果您在共享主机服务器上,默认情况下,端口25和587将保持阻塞状态。 这个区块是故意做的,由您的主机提供商。 即使对于某些专用服务器也是如此。 当这些端口被阻止时,请尝试使用端口2525进行连接。 如果您发现该端口也被阻塞,那么唯一的解决方案就是联系您的托管提供商来解除这些端口的阻塞。

大多数托管提供商都阻止这些电子邮件端口,以保护他们的网络不被发送任何垃圾邮件。

将端口25或587用于普通/TLS连接,将端口465用于SSL连接。 对于大多数用户来说,建议使用587端口以避免某些托管提供商设置的速率限制。

在PHP中,当错误抑制运算符@前缀到表达式时,该表达式可能生成的任何错误消息都将被忽略。 在某些情况下,使用此操作符是必要的,但发送邮件不是其中之一。

如果您的代码包含@mail(。。。),那么您可能隐藏了有助于您调试的重要错误消息。 删除@并查看是否报告了任何错误。

只有当您在之后立即用error_get_last()检查具体的故障时,才建议这样做。

mail()函数:

如果邮件已成功接受传递,则返回true,否则返回false。 需要注意的是,仅仅因为邮件被接受投递,并不意味着邮件将实际到达预定目的地。

这一点需要注意,因为:

  • 如果您收到false返回值,则说明错误在于您的服务器接受了您的邮件。 这可能不是编码问题,而是服务器配置问题。 您需要与系统管理员联系,以了解发生这种情况的原因。
  • 如果您收到true返回值,并不意味着您的电子邮件一定会被发送。 这仅仅意味着电子邮件已通过PHP成功地发送到服务器上的相应处理程序。 在PHP的控制之外,还有更多的故障点可能导致电子邮件无法发送。

因此false将帮助您指明正确的方向,而true并不一定意味着您的电子邮件发送成功。 这一点需要注意!

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

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

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

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

  • 使用电子邮件身份验证方法,如SPF和DKIM,以证明您的电子邮件和您的域名属于一起,并防止欺骗您的域名。 SPF网站包含一个向导,用于生成站点的DNS信息。
  • 检查反向DNS以确保邮件服务器的IP地址指向用于发送邮件的域名。
  • 确保您使用的IP地址不在黑名单上
  • 请确保答复地址是有效的现有地址。
  • 在“收件人”字段中使用收件人的真实全名,而不仅仅是电子邮件地址(例如“John Smith”)。
  • 监视您的滥用帐户,如abuse@yourdomain.com和postmaster@yourdomain.com。 这意味着--确保这些帐号存在,阅读发送给他们的内容,并对投诉采取行动。
  • 最后,让退订变得非常容易。 否则,您的用户将通过按“垃圾邮件”按钮取消订阅,这将影响您的声誉。

查看如何确保以编程方式发送的电子邮件不被自动标记为垃圾邮件? 更多关于这个主题的信息。

如果邮件缺少“发件人”和“回复到”等常见标题,某些垃圾邮件软件会拒绝邮件:

$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:sender,但不能只使用任何值。 特别是,用户使用的发件人地址是阻止邮件的可靠方法:

$headers = array("From: $_POST[contactform_sender_email]"); // No!

原因:您的web或发送邮件服务器不是SPF/DKIM白名单,以假装对@Hotmail或@Gmail地址负责。 它甚至可能悄无声息地丢弃带有来自:发件人域的邮件。

有时问题就像电子邮件收件人的值不正确一样简单。 这可能是由于使用了不正确的变量。

$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属性包含一个指向PHP邮件代码的值。

<form action="send_email.php" method="POST">

一些Web主机提供商不允许或启用通过其服务器发送电子邮件。 原因可能不同,但如果他们已禁用发送邮件,您将需要使用替代方法,使用第三方为您发送这些电子邮件。

向他们的技术支持发送电子邮件(在访问他们的在线支持或FAQ之后),应该说明您的服务器上是否有电子邮件功能。

如果您正在本地工作站上使用WAMP,MAMP或XAMPP进行开发,那么您的工作站上很可能没有安装电子邮件服务器。 如果没有一个,PHP默认情况下无法发送邮件。

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

您还可以使用SMTP发送电子邮件。 看看Vikas Dwivedi的这个伟大的答案来学习如何做到这一点。

除了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设置。 通常,您将邮件探测发送到:他们的地址,然后获得传递报告和更多具体的故障或分析:

  • mail-tester.com(免费/简单)
  • GlockApps.com(免费/$$$)
  • Senforensics.com(注册/$$$)
  • mailtrap.io(PRO/$$$)
  • UltraTools/…/EmailTest(仅限免费/MX检查)
  • 各种:http://www.verticalresponse.com/blog/7-email-testing-delivery-tools/

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

  • 最受欢迎的是:phpmailer
  • 同样功能:SwiftMailer
  • 甚至是更老的pear::mail.

所有这些都可以与专业的SMTP服务器/服务提供商相结合。 (因为当涉及到电子邮件设置/配置时,典型的08/15共享网络托管计划是命中或未命中的。)

匿名用户

在邮件函数中添加邮件头:

$header = "From: noreply@example.com\r\n";
$header.= "MIME-Version: 1.0\r\n";
$header.= "Content-Type: text/html; charset=ISO-8859-1\r\n";
$header.= "X-Priority: 1\r\n";

$status = mail($to, $subject, $message, $header);

if($status)
{
    echo '<p>Your mail has been sent!</p>';
} else {
    echo '<p>Something went wrong. Please try again!</p>';
}

匿名用户

  1. 始终尝试在邮件函数中发送邮件头。
  2. 如果通过localhost发送邮件,请执行SMTP设置以发送邮件。
  3. 如果通过服务器发送邮件,请检查服务器上是否启用了电子邮件发送功能。