这是用PHP发送电子邮件的正确方法吗?

时间:2009-05-01 02:08:53

标签: php email encoding utf-8

我有点担心,如果这个功能发送的电子邮件可以在大多数电子邮件和网络邮件客户端上正确识别,特别是我最担心的是这个问题:

  • UTF-8声明和附件是否形成良好?
  • 我需要使用quoted_printable_decode()吗?如果是的话,在哪里?
  • 内容传输编码:7位还是8位?我一直看到7但是因为我发送的是UTF-8编码的邮件,我不确定。
  • 我应该使用mb_send_mail()还是mail()就足够了?

编辑:我不知道为什么但是代码没有正确显示,我已将其设为@ http://gist.github.com/104818

编辑2:我知道电子邮件处理的其他替代方案(库),但为了我自己的好奇心和知识,我只想知道这段代码是否100%好,或者它是否有错误

function Email($name, $from, $to, $subject, $message, $bcc = null, $attachments = null)
{
    ini_set('SMTP', 'localhost');
    ini_set('sendmail_from', $from);

    $name = filter_var($name, FILTER_SANITIZE_STRING);
    $from = filter_var($from, FILTER_SANITIZE_EMAIL);
    $subject = filter_var($subject, FILTER_SANITIZE_STRING);

    $boundary = '_Boundary_' . md5(microtime(true) . mt_rand(0, PHP_INT_MAX));

    $headers = array
    (
        'MIME-Version: 1.0',
        'Content-Type: multipart/mixed; boundary="Mixed' . $boundary . '"',
        'Date: ' . date('r', time()),
        'From: "' . $name . '" <' . $from . '>',
        'Reply-To: "' . $name . '" <' . $from . '>',
        'Return-Path: "' . $name . '" <' . $from . '>',
        'X-Mailer: PHP ' . phpversion(),
        'X-Priority: 2',
        'X-MSMail-Priority: High',
        'X-Originating-IP: ' . $_SERVER['SERVER_ADDR'],
    );

    if (is_null($to) === false)
    {
        if (is_array($to) === false)
        {
            $to = explode(',', $to);
        }

        foreach ($to as $key => $value)
        {
            $to[$key] = filter_var($value, FILTER_SANITIZE_EMAIL);
        }

        $to = implode(', ', array_filter($to));
    }

    if (is_null($bcc) === false)
    {
        if (is_array($bcc) === false)
        {
            $bcc = explode(',', $bcc);
        }

        foreach ($bcc as $key => $value)
        {
            $bcc[$key] = filter_var($value, FILTER_SANITIZE_EMAIL);
        }

        $headers[] = 'BCC: ' . implode(', ', array_filter($bcc));
    }

    if (is_null($attachments) === false)
    {
        settype($attachments, 'array');

        foreach ($attachments as $key => $value)
        {
            if (is_file($value) === true)
            {
                $attachments[$key] = array
                (
                    '',
                    '--Mixed' . $boundary,
                    'Content-Type: application/octet-stream; name="' . basename($value) . '"',
                    'Content-Disposition: attachment; filename="' . basename($value) . '"',
                    'Content-Transfer-Encoding: base64',
                    '',
                    trim(chunk_split(base64_encode(file_get_contents($value)))),
                );

                $attachments[$key] = implode("\n", $attachments[$key]);
            }

            else
            {
                unset($attachments[$key]);
            }
        }

        $attachments = implode("\n", $attachments) . "\n";
    }

    $message = array
    (
        'This is a multi-part message in MIME format.',
        '',
        '--Mixed' . $boundary,
        'Content-Type: multipart/alternative; boundary="Alt' . $boundary . '"',
        '',
        '--Alt' . $boundary,
        'Content-Type: text/plain; charset="UTF-8"',
        'Content-Disposition: inline',
        'Content-Transfer-Encoding: 8bit',
        '',
        trim(strip_tags($message, '<a>')),
        '',
        '--Alt' . $boundary,
        'Content-Type: text/html; charset="UTF-8"',
        'Content-Disposition: inline',
        'Content-Transfer-Encoding: 8bit',
        '',
        trim($message),
        '',
        '--Alt' . $boundary . '--',
        $attachments,
        '--Mixed' . $boundary . '--',
    );

    if (@mail($to, stripslashes($subject), implode("\n", $message), implode("\n", $headers)) === true)
    {
        return true;
    }

    return false;
}

2 个答案:

答案 0 :(得分:27)

虽然这应该有用,但我强烈建议使用预构建的邮件/ SMTP类,例如Zend_Mail。虽然我不认为整个Zend Framework是猫的睡衣,但我对他们的邮件处理代码有很好的看法。

编辑:我还应该补充说,使用预建的邮件/ SMTP类几乎可以抽象出多部分电子邮件的所有复杂性/结构。

更新2009-05-06:直接回答您的问题。

  
      
  • UTF-8声明和附件是否形成良好?
  •   

他们看起来不错。

  
      
  • 我需要使用quoted_printable_decode()吗?如果是的话,在哪里?
  •   

没有。只有在解码电子邮件时才需要使用quoted_printable_decode()。不是在编码时。您应该使用 quoted_printable_encode() 吗?我接下来会讨论这个问题。

  
      
  • 内容传输编码:7位还是8位?我一直看到7但是因为我发送的是UTF-8编码的邮件,我不确定。
  •   

如果您知道目标SMTP服务器可以支持它,则仅使用8位编码。但是,由于您将电子邮件传递给本地MTA,我不建议您设置此值。默认值是7位编码,但它有自己的一组限制:代码范围1-127每行最多998个八位字节,CR和LF只允许作为CRLF行结尾的一部分出现(http://tools.ietf.org/html/rfc2045#section-2.7 )。

我建议您使用Quoted-Printable(http://tools.ietf.org/html/rfc2045#section-6.7)Content-Transfer-Encoding。在您致电trim(strip_tags($message, '<a>'))trim($message)的地方,您需要附上quoted_printable_encode(trim(...))的人。

  
      
  • 我应该使用mb_send_mail()还是mail()就够了?
  •   

如果您知道将处理多字节消息(日语,韩语,中文等),那么mail()就足够了。

现在我已经回答了你的初步问题,让我告诉你哪里存在一些问题。

  1. 您指定纯文本和Html内容部分的字符集是UTF-8,但它不会显示,因为您实际上确保它们确实是UTF-8编码。
  2. 您正在检查null$to$bcc中的$attachments,然后再进一步处理它们,但是,当它们实际可能是{时,您没有做任何事情{1}}。因此,如果您恰好收到null的{​​{1}},则不会处理该变量,但会继续向null发送电子邮件。
  3. 截至目前,这就是我要进行的所有内容,但我仍然强烈建议使用预先构建的解决方案,因为他们有很多用户/时间来解决错误。

答案 1 :(得分:17)

在大多数情况下,我都是为了自己动手,但是当涉及到邮件时,我会衷心地建议让自己更容易并使用Swift MailerPHPMailer之类的内容(在那个订单,我的钱。)

作为副奖金(假设您指定回复等),您被标记为垃圾邮件的可能性也大大降低。