使用PHPMailer 6.*与PHP7发送2MB以上附件时内存耗尽问题
我之前处理过几乎一模一样的问题,咱们先拆解根源:PHPMailer 6.x在默认配置下,当用mail()或sendmail发送带大附件的邮件时,会把整个邮件内容(包括附件)全部加载到内存里,这就是你看到内存耗尽错误的原因——哪怕你改了php.ini的内存限制,大文件(比如2MB以上)很容易就撑爆分配的内存。而之前低版本PHPMailer+PHP5能正常工作,大概率是旧版本默认用了流式处理或者更节省内存的邮件生成逻辑。
下面给你几个可行的解决方案,按优先级排序:
1. 切换到SMTP模式发送(最推荐)
SMTP模式下,PHPMailer会采用流式上传的方式发送邮件,不需要把整个邮件(包括大附件)加载到内存中,而是逐块发送给SMTP服务器,从根本上解决内存占用问题。
修改你的代码,启用SMTP配置:
// 初始化PHPMailer实例后,切换到SMTP模式 $mail->isSMTP(); $mail->Host = '你的SMTP服务器地址'; // 比如 smtp.example.com $mail->SMTPAuth = true; $mail->Username = '你的SMTP账号'; $mail->Password = '你的SMTP密码'; $mail->SMTPSecure = 'tls'; // 可选ssl,根据服务器要求 $mail->Port = 587; // 对应tls的端口,ssl一般是465
2. 调整PHPMailer配置,使用磁盘缓存替代内存缓存
如果必须使用mail()或sendmail发送,你可以让PHPMailer把邮件内容写到临时文件里,而不是保存在内存中:
// 初始化实例后,添加以下配置 $mail->isSendmail(); // 或者用 $mail->isMail() 如果你用的是PHP内置mail函数 $mail->UseSendmailOptions = false; // 关闭sendmail的额外选项,强制使用磁盘缓存 $mail->TempDir = '/tmp'; // 指定一个PHP有读写权限的临时目录,默认/tmp一般没问题
注意:要确保TempDir指定的目录存在且PHP进程有读写权限,否则会出现新的错误。
3. 确认php.ini内存限制是否真正生效
有时候修改了php.ini但没重启服务,导致配置没生效。你可以在代码里添加一行输出,检查当前生效的内存限制:
echo ini_get('memory_limit'); // 输出类似 20M 或者 256M
如果输出还是20M(对应错误里的20971520字节),说明你修改的php.ini文件不对(比如修改了CLI的php.ini但web用的是另一个),或者没重启web服务器/php-fpm服务。建议把内存限制调到256M或更高,比如在php.ini里设置:
memory_limit = 256M
为什么旧版本能正常工作?
低版本PHPMailer(比如5.x)在处理mail()/sendmail模式下的大附件时,默认会直接通过管道把文件内容传给sendmail进程,不需要把整个文件读进内存。而PHPMailer 6.x调整了默认逻辑,改为先把邮件内容生成到内存中再发送,这就导致了大附件场景下的内存溢出问题。
内容的提问来源于stack exchange,提问作者Ashwini Bhat

