在PHP发送的电子邮件中使用HTML格式化

4
我该如何通过PHP脚本发送HTML格式呢?不知为何,它总是显示为<b>Example</b>而不是Example。我确定我需要在某个地方包含HTML标头,但我不知道需要做什么。我完全是一个PHP新手 :)。
以下是我的PHP脚本(相当长,抱歉!):
<?php

if(!$_POST) exit;

        $name     = $_POST['name'];
        $email    = $_POST['email'];
        $phone   = $_POST['phone'];
        $subject  = $_POST['subject'];
        $comments = $_POST['comments'];
        $verify   = $_POST['verify'];

        if(trim($name) == '') {
            echo '<div class="error_message">You must enter your name.</div>';
            exit();
        } else if(trim($name) == 'Name') {
            echo '<div class="error_message">You must enter your name.</div>';
            exit();
        }

        else if(trim($email) == '') {
            echo '<div class="error_message">Please enter a valid email address.</div>';
            exit();
        } else if(trim($email) == 'Email') {
            echo '<div class="error_message">Please enter a valid email address.</div>';
            exit();
        } else if(!isEmail($email)) {
            echo '<div class="error_message">Invalid e-mail address, please try again.</div>';
            exit();
        }

        if(trim($subject) == '') {
            echo '<div class="error_message">Please enter a subject.</div>';
            exit();
        } else if(trim($subject) == 'Subject') {
            echo '<div class="error_message">Please enter a subject.</div>';
            exit();
        }


        if($error == '') {

            if(get_magic_quotes_gpc()) {
                $comments = stripslashes($comments);
            }

         $address = "mynamehere@mydomainnamehere.com";

         $e_subject = '' . $subject . '.';

         $e_body = "<b>Name:</b> $name \n\n<b>Subject:</b> $subject \n\n<b>Email:</b> $email \n\n<b>Message:</b> $comments";
         $e_content = "";
         $e_reply = "";

         $msg = $e_body . $e_content . $e_reply;

         if(mail($address, $e_subject, $msg, "From: $email\r\nReply-To: $email\r\nReturn-Path: $email\r\n")) {

         echo "<div id='success_page'>";
         echo "<h1>Email Sent Successfully.</h1>";
         echo "<p>Thank you <strong>$name</strong>, your message has been sent!</p>";
         echo "</div>";
         //echo "</fieldset>";

         } else {

         echo 'ERROR!';

         }

    }

function isEmail($email) { // Email address verification, do not edit.

return(preg_match("/^[-_.[:alnum:]]+@((([[:alnum:]]|[[:alnum:]][[:alnum:]-]*[[:alnum:]])\.)+(ad|ae|aero|af|ag|ai|al|am|an|ao|aq|ar|arpa|as|at|au|aw|az|ba|bb|bd|be|bf|bg|bh|bi|biz|bj|bm|bn|bo|br|bs|bt|bv|bw|by|bz|ca|cc|cd|cf|cg|ch|ci|ck|cl|cm|cn|co|com|coop|cr|cs|cu|cv|cx|cy|cz|de|dj|dk|dm|do|dz|ec|edu|ee|eg|eh|er|es|et|eu|fi|fj|fk|fm|fo|fr|ga|gb|gd|ge|gf|gh|gi|gl|gm|gn|gov|gp|gq|gr|gs|gt|gu|gw|gy|hk|hm|hn|hr|ht|hu|id|ie|il|in|info|int|io|iq|ir|is|it|jm|jo|jp|ke|kg|kh|ki|km|kn|kp|kr|kw|ky|kz|la|lb|lc|li|lk|lr|ls|lt|lu|lv|ly|ma|mc|md|mg|mh|mil|mk|ml|mm|mn|mo|mp|mq|mr|ms|mt|mu|museum|mv|mw|mx|my|mz|na|name|nc|ne|net|nf|ng|ni|nl|no|np|nr|nt|nu|nz|om|org|pa|pe|pf|pg|ph|pk|pl|pm|pn|pr|pro|ps|pt|pw|py|qa|re|ro|ru|rw|sa|sb|sc|sd|se|sg|sh|si|sj|sk|sl|sm|sn|so|sr|st|su|sv|sy|sz|tc|td|tf|tg|th|tj|tk|tm|tn|to|tp|tr|tt|tv|tw|tz|ua|ug|uk|um|us|uy|uz|va|vc|ve|vg|vi|vn|vu|wf|ws|ye|yt|yu|za|zm|zw)$|(([0-9][0-9]?|[0-1][0-9][0-9]|[2][0-4][0-9]|[2][5][0-5])\.){3}([0-9][0-9]?|[0-1][0-9][0-9]|[2][0-4][0-9]|[2][5][0-5]))$/i",$email));

}
?> 

可能是在电子邮件中包含HTML的重复问题。 - Quentin
5个回答

10

你需要在 $additional_headers 参数中添加 content-type:

$headers  = "From: $email\r\n";
$headers .= "Reply-To: $email\r\n";
$headers .= "Return-Path: $email\r\n";
$headers .= "MIME-Version: 1.0\r\n";
$headers .= "Content-type: text/html; charset=iso-8859-1\r\n";

if(mail($address, $e_subject, $msg, $headers)) {
我的建议是像其他贴子所说的那样,使用外部发送服务或类似Zend_Mail的工具,这可以方便地指定HTML和普通文本版本(有些人真的很讨厌HTML电子邮件;))

你可能想使用UTF-8字符集,但那应该能解决问题。 - typeoneerror
看起来就像我想要的。谢谢! - sudo rm -rf
2
垃圾邮件过滤器也讨厌仅包含HTML的邮件。不要使用此代码示例。请使用一个好的库来完成这项工作。 - Quentin
1
+1 @David Dorward,我也建议你将其作为一个示例而不是一个可行的解决方案,首先请做好研究,并采纳使用一个库的建议。http://stackoverflow.com/questions/1872639/good-php-email-library - RobertPitt
2
地狱,那是我的答案,我建议不要使用它。因此,给出了 Zend_Mail 的链接。 - typeoneerror

5
这可能与您的实际问题无关,但是您的正则表达式太大了而且毫无意义 :/。这是您需要修改的内容: preg_match("/^[-_.[:alnum:]]+@((([[:alnum:]]|[[:alnum:]][[:alnum:]-]*[[:alnum:]]).)+(ad|ae|aero|af|ag|ai|al|am|an|ao|aq|ar|arpa|as|at|au|aw|az|ba|bb|bd|be|bf|bg|bh|bi|biz|bj|bm|bn|bo|br|bs|bt|bv|bw|by|bz|ca|cc|cd|cf|cg|ch|ci|ck|cl|cm|cn|co|com|coop|cr|cs|cu|cv|cx|cy|cz|de|dj|dk|dm|do|dz|ec|edu|ee|eg|eh|er|es|et|eu|fi|fj|fk|fm|fo|fr|ga|gb|gd|ge|gf|gh|gi|gl|gm|gn|gov|gp|gq|gr|gs|gt|gu|gw|gy|hk|hm|hn|hr|ht|hu|id|ie|il|in|info|int|io|iq|ir|is|it|jm|jo|jp|ke|kg|kh|ki|km|kn|kp|kr|kw|ky|kz|la|lb|lc|li|lk|lr|ls|lt|lu|lv|ly|ma|mc|md|mg|mh|mil|mk|ml|mm|mn|mo|mp|mq|mr|ms|mt|mu|museum|mv|mw|mx|my|mz|na|name|nc|ne|net|nf|ng|ni|nl|no|np|nr|nt|nu|nz|om|org|pa|pe|pf|pg|ph|pk|pl|pm|pn|pr|pro|ps|pt|pw|py|qa|re|ro|ru|rw|sa|sb|sc|sd|se|sg|sh|si|sj|sk|sl|sm|sn|so|sr|st|su|sv|sy|sz|tc|td|tf|tg|th|tj|tk|tm|tn|to|tp|tr|tt|tv|tw|tz|ua|ug|uk|um|us|uy|uz|va|vc|ve|vg|vi|vn|vu|wf|ws|ye|yt|yu|za|zm|zw)$|(([0-9][0-9]?|[0-1][0-9][0-9]|[2][0-4][0-9]|[2][5][0-5]).){3}([0-9][0-9]?|[0-1][0-9][0-9]|[2][0-4][0-9]|[2][5][0-5]))$/i",$email) ^^ 这太疯狂了 :/

尝试一些更简单的东西:

return filter_var($email, FILTER_VALIDATE_EMAIL);

1
@RobertPitt:这是一个显著的改进,如果在2011年它是正确的话,那将是一个很好的函数。不幸的是,它已经失效了:bob@example.香港是一个完全有效的电子邮件地址,Медведев@президент.рф也是如此。遗憾的是,英语病毒再次袭击,该函数将其视为无效。 - Piskvor left the building
他的正则表达式怎么样?它能允许这样的域名吗?如果你有完美的最终电子邮件验证正则表达式,请分享一下 :) - RobertPitt
正则表达式不适用于验证电子邮件地址。要检查是否恰好有一个“@”,检查“@”后面部分的 DNS 是否解析,然后尝试向其发送电子邮件。 - Quentin
@RobertPitt:实际上,我刚刚发现了这个问题,所以我提到它。到目前为止,看起来有一个可接受的解决方法:先转换为punycode,然后通过过滤器运行。 Punycode编码的IDN电子邮件地址似乎可以正确地通过过滤器。 - Piskvor left the building
@David Dorward:我已经检查了@RobertPitt建议中的正则表达式,它就是那个两页的正则表达式,可以正确匹配有效的电子邮件地址,而不是无效的电子邮件地址。有了Punycode,这对于IDN也可以正常工作,因此尽管它是一个庞然大物的正则表达式,但它是正确的(请参见此处的第525行:http://svn.php.net/viewvc/php/php-src/trunk/ext/filter/logical_filters.c?view=markup#l501)。 - Piskvor left the building

3
您需要一个HTML头。添加如下内容:
$headers = "MIME-Version: 1.0" . "\r\n";
$headers .= "Content-type:text/html;charset=iso-8859-1" . "\r\n";
$headers .= "From: $email\r\nReply-To: $email\r\nReturn-Path: $email\r\n";

然后在您的发送邮件行中将其重写为:

if(mail($address, $e_subject, $msg, $headers))

此外,如果我是你,我会让它更加跨平台兼容。在*nix系统中,换行符是“\n”,而在Mac系统中则是“\r”。我从未在Mac服务器上工作过,因此我使用以下代码来设置新行定义:
if(strtoupper(substr(PHP_OS, 0, 3)) === 'WIN')
    define('EOL', "\r\n");
else
    define('EOL', "\n");

在我的标题中,我使用EOL而不是 ."\r\n",因此它看起来像这样:

$headers = "MIME-Version: 1.0" . EOL
$headers .= "Content-type:text/html;charset=iso-8859-1" . EOL;
$headers .= "From: $email".EOL."Reply-To: $email".EOL."Return-Path: $email".EOL.EOL;

此外,在您的标题末尾使用两个换行符以防止标题注入攻击。

有趣的是关于两个换行符的注释。很棒的文章。 - typeoneerror
3
不要发送纯 HTML 邮件!它们不够友好,并且被许多过滤器认为是垃圾邮件。如果你必须使用格式化,可以使用多部分 MIME。 - Quentin

1

你肯定需要一些HTML头部

<html>
  <body>
     Your data
  </body>
</html>

设置正确的 MIME 类型

1

与其试图正确发送电子邮件的所有细节(通过垃圾邮件过滤器等),您可以使用诸如http://swiftmailer.org/之类的库。它会为您处理设置所有适当的标头等。

我与swiftmailer没有关系。我只是用过它并喜欢它。


你是SwiftMailer的代表吗?他的问题是如何在PHP中实现,而不是让别人替他完成。很容易正确设置标头,而无需外包给其他类和库。 - Dan Hanly
发送格式良好的HTML邮件很难(因为您必须执行多部分MIME)。重新发明轮子是不好的。GNU Lesser General Public License友好。 - Quentin
1
@Daniel - 不是的,我只是一个使用过并喜欢它的人。我会更新我的答案以使其更清晰,并在将来这样做。至于为什么,当您手动尝试做某事时遇到问题时,为什么要费力呢?如果您要发送几种不同类型的电子邮件,使用库来协助您会更容易。最好将其外包给经过充分测试的库,而不是尝试自己解决(可能会出错但没有意识到)。 - Blair McMillan
阿门。PHP原始的mail()函数对于通常的任务来说非常低级;将其抽象化可以节省您的时间(无论是编写还是调试)和精力。 - Piskvor left the building

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接