You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PHP邮件表单无法发送大附件问题求助

大附件邮件发送失败的排查与解决方案

核心问题分析

你的代码能处理小附件但大附件失败,且文件已成功上传($_FILES无错误),说明问题出在邮件发送环节而非文件上传环节,大概率是MTA(邮件传输代理)限制或邮件构建的细节问题。

1. 检查服务器MTA的邮件大小限制

PHP mail() 函数本质是调用系统的MTA服务(如Postfix、Sendmail、Exim),这些服务默认会限制单封邮件的总大小:

  • Postfix:执行postconf message_size_limit查看当前限制,默认可能为10MB,但部分主机可能设得更低(比如1MB),修改后需重启Postfix。
  • Sendmail:检查MaxMessageSize配置,需在sendmail.mc中设置后重新编译配置。
  • Exim:查看配置文件中的message_size_limit参数并调整。

这是最常见的原因——你调了PHP的参数,但MTA的大小限制没改,导致大附件邮件被拦截。

2. 修正邮件头的Boundary格式错误

你的邮件头中Boundary的写法不符合MIME规范:

// 错误写法(多了空格,缺少引号)
"Content-Type: multipart/mixed;" .  
"boundary = $boundary\r\n";

// 正确写法
"Content-Type: multipart/mixed; boundary=\"$boundary\"\r\n";

MIME规范要求boundary值需用双引号包裹,格式错误可能导致MTA无法正确解析邮件结构,大附件场景下这个问题会被放大。

3. 优化内存占用:分段读取文件编码

当前代码一次性将整个文件读入内存并编码,base64会让文件体积增加33%(1.3MB的文件会变成~1.7MB),如果是更大的文件或共享主机内存受限,可能导致内存溢出或被系统终止。改成分段读取:

$body = "--$boundary\r\n" . 
"Content-Type: text/html; charset=ISO-8859-1\r\n" .
"Content-Transfer-Encoding: quoted-printable\r\n\r\n" .  
$textcontent . "\r\n\r\n";

// 分段读取文件并编码
$handle = fopen($filetmpname, "rb");
$body .= "--{$boundary}\r\n" .
"Content-Type: $filetype; name=\"$filename\"\r\n" . 
"Content-Disposition: attachment; filename=\"$filename\"\r\n" . 
"Content-Transfer-Encoding: base64\r\n" . 
"X-Attachment-Id: ".rand(1000, 99999)."\r\n\r\n";

while (!feof($handle)) {
    $chunk = fread($handle, 4096); // 每次读4KB
    $body .= chunk_split(base64_encode($chunk));
}
fclose($handle);
$body .= "\r\n--{$boundary}--\r\n"; // 必须添加结束边界

注意:邮件的multipart结构必须以--boundary--结尾,你的代码里缺少这部分,这也可能导致MTA拒绝处理邮件。

4. 调试mail()的实际执行过程

  • 开启PHP的邮件日志:在php.ini中设置mail.log = /var/log/php_mail.log,重启PHP后查看日志,能看到mail()调用的系统命令及错误信息。
  • 手动测试MTA:直接用系统命令发送带大附件的邮件,比如用sendmail:
    # 构造简单的带附件邮件并发送
    echo -e "From: sender@example.com\nTo: recipient@example.com\nSubject: Test Large Attachment\nMIME-Version: 1.0\nContent-Type: multipart/mixed; boundary=\"testboundary\"\n\n--testboundary\nContent-Type: text/plain\n\nTest body\n\n--testboundary\nContent-Type: image/jpeg; name=\"mapimage1p2.jpg\"\nContent-Disposition: attachment; filename=\"mapimage1p2.jpg\"\nContent-Transfer-Encoding: base64\n\n$(base64 /tmp/phpVwAQJQ)\n\n--testboundary--" | sendmail -t
    

如果手动发送也失败,说明是MTA的问题,直接联系主机商;如果成功,说明是PHP代码的问题。

5. 确认主机的额外限制

  • 共享主机可能在面板(如cPanel、Plesk)中有单独的邮件大小限制,即使你修改了php.ini,面板的配置会覆盖。
  • 部分主机会限制mail()函数的使用频率或单邮件大小,需联系主机商确认是否有这类限制。

内容的提问来源于stack exchange,提问作者Jabbamonkey

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 20:14:50