PHP使用原生mail函数发送带附件邮件的方法

方予
方予
发布时间:2026-10-15 | 4人浏览过
原创

在无需依赖第三方邮件库的情况下,利用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 后,即可在主脚本中实例化该类进行发送。以下是关键参数的定义及调用示例:

  1. 初始化配置:定义邮件主题、收件人、发件人邮箱、邮件正文以及附件路径。
  2. 实例化对象:传入相应参数,类内部会自动完成文件的读取与编码。
  3. 执行发送:调用对象的 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邮件开发的技术资料请关注本站其它相关文章!

相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表