使用 PHP 内置的 mail() 函数
这种方法最底层,可以让你完全控制邮件的构建过程,但代码相对繁琐,容易出错。

(图片来源网络,侵删)
核心原理
发送带附件的邮件,本质上是在邮件的头部添加特殊的 Content-Type 和 Content-Disposition 信息,用以声明邮件包含多个部分(文本内容和附件),这需要使用 MIME (Multipurpose Internet Mail Extensions) 协议。
关键步骤
- 定义邮件头:特别是
MIME-Version、Content-Type和Content-Transfer-Encoding。 - 构建邮件主体:使用
boundary(边界字符串)来分隔邮件的不同部分(如文本和附件)。 - 添加文本部分:在
boundary后添加邮件的正文内容。 - 添加附件部分:为每个附件重复以下步骤:
- 在
boundary后添加附件的头信息。 - 读取附件文件的内容。
- 进行 Base64 编码(因为邮件不能直接传输二进制数据)。
- 添加编码后的内容。
- 在
- 结束邮件:以
--boundary--标志邮件的结束。
完整示例代码
<?php
// 邮件接收者
$to = 'recipient@example.com';
// 邮件主题
$subject = '这是一封带附件的测试邮件';
$message = '您好,<br><br>这封邮件包含一个附件,请查收。<br><br>谢谢!';
// 文件路径
$filename = 'test.pdf'; // 假设附件是当前目录下的 test.pdf
// 读取文件内容
$file_content = file_get_contents($filename);
// 对文件内容进行 base64 编码
$encoded_content = chunk_split(base64_encode($file_content));
// 定义一个随机字符串作为 boundary
$boundary = "-----=" . md5(time());
// 邮件头
$headers = "From: sender@example.com \r\n";
$headers .= "MIME-Version: 1.0 \r\n";
$headers .= "Content-Type: multipart/mixed; boundary=\"$boundary\" \r\n";
// 邮件主体
$body = "--$boundary\r\n";
$body .= "Content-Type: text/html; charset=UTF-8\r\n";
$body .= "Content-Transfer-Encoding: 8bit\r\n\r\n";
$body .= "$message\r\n\r\n";
// 附件部分
$body .= "--$boundary\r\n";
$body .= "Content-Type: application/pdf; name=\"$filename\"\r\n"; // 根据文件类型设置 Content-Type
$body .= "Content-Transfer-Encoding: base64\r\n";
$body .= "Content-Disposition: attachment; filename=\"$filename\"\r\n\r\n";
$body .= "$encoded_content\r\n\r\n";
// 结束 boundary
$body .= "--$boundary--";
// 发送邮件
if (mail($to, $subject, $body, $headers)) {
echo "邮件发送成功!";
} else {
echo "邮件发送失败!";
}
?>
代码解析:
chunk_split(base64_encode($file_content)): Base64 编码后的字符串很长,chunk_split会将其分割成每76个字符一行,这符合 MIME 标准。Content-Type: multipart/mixed: 声明邮件包含多个不同类型的部分。boundary: 一个独特的字符串,用于在邮件流中标记不同部分的开始和结束。Content-Disposition: attachment: 这是告诉邮件客户端(如 Outlook, Gmail)这是一个需要下载的附件的关键指令。
使用 PHPMailer 库(强烈推荐)
使用 PHPMailer 可以让你从繁琐的邮件头构建中解放出来,代码更简洁、更安全、更易于维护,PHPMailer 处理了所有的编码和 MIME 格式化工作。
为什么推荐 PHPMailer?
- 简单易用:提供清晰的面向对象接口。
- 功能强大:支持 SMTP 认证、HTML 邮件、附件、图片嵌入等。
- 安全可靠:能有效防止邮件注入等安全问题。
- 兼容性好:处理了各种服务器环境下的兼容性问题。
步骤 1:安装 PHPMailer
最简单的方式是使用 Composer:

(图片来源网络,侵删)
composer require phpmailer/phpmailer
步骤 2:编写发送带附件的邮件代码
<?php
// 引入 PHPMailer 的自动加载文件
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;
require 'vendor/autoload.php'; // 确保路径正确
// 创建一个 PHPMailer 实例
$mail = new PHPMailer(true); // `true` 启用异常处理
try {
// 服务器设置
// $mail->isSMTP(); // 使用 SMTP
// $mail->Host = 'smtp.example.com'; // SMTP 服务器地址
// $mail->SMTPAuth = true; // 启用 SMTP 认证
// $mail->Username = 'user@example.com'; // SMTP 用户名
// $mail->Password = 'secret'; // SMTP 密码
// $mail->SMTPSecure = PHPMailer::ENCRYPTION_SMTPS; // 启用 TLS/SSL 加密
// $mail->Port = 465; // SMTP 端口
// 如果不需要通过外部 SMTP 服务器发送(本地测试或使用 sendmail),可以注释掉上面的 SMTP 配置。
// 大多数虚拟主机/服务器默认支持 PHP 的 mail() 函数。
$mail->isMail(); // 使用 PHP 的 mail() 函数发送
// 收件人
$mail->setFrom('from@example.com', '发件人名称');
$mail->addAddress('recipient@example.com', '收件人名称'); // 添加一个收件人
// 附件
// 方法1: 添加一个来自文件的附件
$mail->addAttachment('test.pdf', '我的文档.pdf'); // 可选参数:附件的别名(新文件名)
// 方法2: 添加一个来自字符串的附件
// $pdfData = file_get_contents('another_file.pdf');
// $mail->addStringAttachment($pdfData, 'another_file.pdf');
// 内容
$mail->isHTML(true); // 设置邮件格式为 HTML
$mail->Subject = '使用 PHPMailer 发送带附件的邮件';
$mail->Body = '您好,<br>这封邮件是使用 PHPMailer 发送的,并且包含一个 PDF 附件。';
$mail->AltBody = '这是纯文本邮件内容,用于不支持 HTML 的邮件客户端。';
$mail->send();
echo '邮件发送成功!';
} catch (Exception $e) {
echo "邮件发送失败: {$mail->ErrorInfo}";
}
?>
代码解析:
use PHPMailer\PHPMailer\PHPMailer;: 引入 PHPMailer 类。$mail = new PHPMailer(true);: 创建实例,并启用异常捕获。$mail->addAttachment('path/to/file.pdf', 'new_name.pdf');: 这是添加附件的核心方法。- 第一个参数是文件的本地路径。
- 第二个参数是可选的,可以指定附件在邮件中显示的文件名。
$mail->send(): 执行发送操作。try...catch: 使用异常处理来捕获发送过程中可能出现的错误,并通过$mail->ErrorInfo获取错误信息。
总结与对比
| 特性 | PHP mail() 函数 |
PHPMailer 库 |
|---|---|---|
| 易用性 | 低,需要手动构建复杂的 MIME 头。 | 高,提供简单直观的方法,如 addAttachment()。 |
| 灵活性 | 高,可以对邮件头进行完全控制。 | 高,支持 SMTP、HTML、附件、图片嵌入等高级功能。 |
| 可靠性 | 低,容易因编码错误导致邮件格式不正确,被当成垃圾邮件。 | 高,经过充分测试,能正确处理各种编码和边界情况。 |
| 安全性 | 低,需要开发者自己小心处理邮件注入等问题。 | 高,内置了对邮件注入等常见攻击的防护。 |
| 依赖 | 无(PHP 内置) | 需要通过 Composer 安装(推荐)或手动下载文件。 |
对于任何生产环境或稍微复杂一点的邮件发送需求,强烈推荐使用 PHPMailer,它能让你把精力集中在业务逻辑上,而不是底层的邮件协议细节,只有在进行非常简单的、不需要附件的测试时,才考虑直接使用 mail() 函数。
