这是使用 PHP 发送电子邮件的正确方法吗?
题
我有点担心这个功能发送的电子邮件是否可以在大多数电子邮件和网络邮件客户端上正确识别,特别是我最担心这个疑问:
- 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;
}
解决方案
虽然这应该可行,但我强烈建议使用预构建的 Mail/SMTP 类,例如 Zend_Mail. 。虽然我不认为整个 Zend Framework 都是猫的睡衣,但我确实对他们的邮件处理代码有很好的看法。
编辑:我还应该补充一点,使用预构建的 Mail/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) 内容传输编码。你打电话的地方 trim(strip_tags($message, '<a>'))
和 trim($message)
你会想要将那些与 quoted_printable_encode(trim(...))
.
- 我应该使用
mb_send_mail()
或者mail()
足够的?
如果你知道你是 不是 将处理多字节消息(日语、韩语、中文等) mail()
应该足够了。
现在我已经回答了您最初的问题,让我告诉您存在哪些问题。
- 您指定纯文本和 Html 内容部分的字符集是 UTF-8,但它不会出现,因为您实际上确保它们确实是 UTF-8 编码的。
- 您正在检查
null
在$to
,$bcc
,$attachments
然而,在您进一步处理它们之前,您实际上并没有做任何事情null
. 。因此,如果您碰巧收到null
为了$to
, ,您不处理该变量,但继续发送电子邮件至null
.
截至目前,这就是我要讨论的全部内容,但我仍然强烈推荐预构建的解决方案,因为他们有大量的用户/时间来解决错误。