PHP使用原生mail函数发送带附件邮件的方法
在无需依赖第三方邮件库的情况下,利用PHP原生 mail 函数配合 MIME 协议即可实现发送带附件的邮件。核心在于构造 multipart/mixed 类型的 HTTP 头,将纯文本正文与 Base64 编码的文件数据分段组合。
实现原理:MIME 多部分内容结构
标准邮件仅支持文本传输,要发送附件必须遵循 RFC 2046 标准构建多部分混合(multipart/mixed)内容。邮件由多个“部分组成”,各部分之间通过唯一的边界符(Boundary)分隔。典型的组成逻辑如下:
- MIME 头部信息:声明邮件类型及边界符格式。
- 文本正文段:指定 Content-Type 为 text/plain,存放用户输入的文字。
- 附件段:指定 Content-Type 为文件实际类型(如 image/jpeg),Content-Transfer-Encoding 为 base64,并将二进制文件转换为字符串嵌入其中。
代码实现:封装 CMailFile 类
以下代码展示了一个名为 CMailFile 的 PHP 类,它负责组装上述各个部分并最终调用 mail 函数。该类完全基于原生函数实现,不引入任何外部依赖。
<?php
class CMailFile {
var $subject;
var $addr_to;
var $text_body;
var $text_encoded;
var $mime_headers;
var $mime_boundary = "--==================_846811060==_";
var $smtp_headers;
/**
* 构造函数:初始化参数并生成各部分内容
*/
function CMailFile($subject, $to, $from, $msg, $filename, $downfilename, $mimetype = "application/octet-stream", $mime_filename = false) {
$this->subject = $subject;
$this->addr_to = $to;
// 生成标准的 SMTP 头部
$this->smtp_headers = $this->write_smtpheaders($from);
// 格式化文本正文
$this->text_body = $this->write_body($msg);
// 处理附件,进行编码并拼接
$this->text_encoded = $this->attach_file($filename, $downfilename, $mimetype, $mime_filename);
// 生成 MIME 协议头部
$this->mime_headers = $this->write_mimeheaders($filename, $mime_filename);
}
/**
* 读取文件并转换为 Base64 编码字符串,拼接到 MIME 结构中
*/
function attach_file($filename, $downfilename, $mimetype, $mime_filename) {
$encoded = $this->encode_file($filename);
if ($mime_filename) $filename = $mime_filename;
// 开始新的部分
$out = "--" . $this->mime_boundary . "\n";
$out .= "Content-type: " . $mimetype . "; name=\"$filename\";\n";
$out .= "Content-Transfer-Encoding: base64\n";
$out .= "Content-disposition: attachment; filename=\"$downfilename\"\n\n";
$out .= $encoded . "\n";
// 结束该部分的标记
$out .= "--" . $this->mime_boundary . "--" . "\n";
return $out;
}
/**
* 对文件内容进行 Base64 编码,并使用 chunk_split 分割长行以适应 SMTP 限制
*/
function encode_file($sourcefile) {
if (is_readable($sourcefile)) {
$fd = fopen($sourcefile, "r");
$contents = fread($fd, filesize($sourcefile));
fclose($fd);
}
// base64_encode 后必须进行切分,否则邮件服务器可能拦截超长行
return isset($contents) ? chunk_split(base64_encode($contents)) : "";
}
/**
* 发送组装好的邮件
*/
function sendfile() {
// 合并头部:SMTP基础头 + MIME协议头
$headers = $this->smtp_headers . $this->mime_headers;
// 合并主体:文本内容 + 附件内容
$message = $this->text_body . $this->text_encoded;
mail($this->addr_to, $this->subject, $message, $headers);
}
/**
* 生成文本正文块
*/
function write_body($msgtext) {
$out = "--" . $this->mime_boundary . "\n";
$out .= "Content-Type: text/plain; charset=\"us-ascii\"\n\n";
$out .= $msgtext . "\n";
return $out;
}
/**
* 生成 MIME 根头部
*/
function write_mimeheaders($filename, $mime_filename) {
if ($mime_filename) $filename = $mime_filename;
$out = "MIME-version: 1.0\n";
$out .= "Content-type: multipart/mixed; boundary=\"$this->mime_boundary\"\n";
$out .= "Content-transfer-encoding: 7BIT\n";
$out .= "X-attachments: $filename;\n\n";
return $out;
}
/**
* 生成基础的 SMTP From/Reply-To 头部
*/
function write_smtpheaders($addr_from) {
$out = "From: $addr_from\n";
$out .= "Reply-To: $addr_from\n";
$out .= "X-Mailer: PHP\n";
$out .= "X-Sender: $addr_from\n";
return $out;
}
}
?
调用步骤与参数说明
将上述代码保存为 emailclass.php 后,即可在主脚本中实例化该类进行发送。以下是关键参数的定义及调用示例:
- 初始化配置:定义邮件主题、收件人、发件人邮箱、邮件正文以及附件路径。
- 实例化对象:传入相应参数,类内部会自动完成文件的读取与编码。
- 执行发送:调用对象的
sendfile()方法触发系统底层mail接口。
<?php
require_once('emailclass.php');
// 主题
$subject = "Test Email with Attachment";
// 收件人地址
$sendto = 'recipient@example.com';
// 发件人地址(需与 SMTP Headers 中的 from 保持一致)
$replyto = 'sender@example.com';
// 邮件正文内容
$message = "This is the test body content.";
// 附件本地文件路径
$filename = 'test.jpg';
// 附件显示的下载文件名
$downloadname = 'my_photo.jpg';
// MIME 类型,常见值如 image/jpeg, application/pdf 等
$mimetype = "image/jpeg";
try {
// 创建实例,注意参数顺序对应类定义
$mailfile = new CMailFile($subject, $sendto, $replyto, $message, $filename, $downloadname, $mimetype);
// 执行发送
if ($mailfile->sendfile()) {
echo "Email sent successfully with attachment.";
} else {
echo "Failed to send email.";
}
} catch (Exception $e) {
echo "Error: " . $e->getMessage();
}
注意事项
- 环境依赖:此方法依赖 Web 服务器(如 Apache/Nginx)配置的 Mail 服务(通常是 Sendmail 或 Postfix)。若服务器未安装或未正确配置 MTAs(邮件传输代理),
mail函数将无法发出邮件。 - 附件安全:确保
$filename指向的路径可读且文件存在。在生产环境中,应严格校验上传的文件类型与 MIME 类型是否匹配,防止恶意文件上传。 - 编码规范:务必使用
chunk_split()对 Base64 编码后的数据进行切分(默认每 76 个字符插入一个换行符),否则某些邮件客户端或服务器可能会丢弃长行的内容。
以上就是使用原生PHP实现邮件发送并带有附件的详细内容,更多关于PHP邮件开发的技术资料请关注本站其它相关文章!
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









