Yii2中attach()加附件必须用绝对路径(如Yii::getAlias('@webroot/uploads/file.pdf')),并校验is_file()和is_readable();显式指定MIME类型更可靠;内存内容用attachContent();多附件需循环调用;发送前检查总大小并设超时。

Yii2里用attach()加附件,文件路径必须是绝对路径
相对路径在命令行或异步任务中大概率失效,因为工作目录不固定。Yii2的SwiftMailer底层调用file_get_contents()读取附件,路径一错就报Failed to open stream。
- 正确做法:用
Yii::getAlias('@runtime')、Yii::getAlias('@webroot')拼出绝对路径,比如Yii::getAlias('@webroot/uploads/report.pdf') - 别直接写
./uploads/report.pdf或uploads/report.pdf——Web服务器和console应用的当前目录不同 - 发邮件前先用
is_file()和is_readable()校验,避免静默失败
attach()的第二个参数控制MIME类型,不填会自动探测但不可靠
自动探测依赖finfo_open()扩展,部分生产环境没开,或者碰到.zip/.xlsx这类易误判的格式,可能变成application/octet-stream,导致邮箱客户端不识别。
- 显式传
['mime' => 'application/pdf']更稳,尤其对自定义后缀或无后缀文件 - 常见类型可查
yii\helpers\BaseFileHelper::$mimeTypes,比如pdf对应application/pdf - 如果附件是内存字符串(比如动态生成的CSV),用
attachContent()替代,它不走文件系统
多个附件要逐个调用attach(),不能传数组
attach()只接受单个文件路径,传数组会触发ArgumentCountError或静默忽略后续项。循环调用才是正解。
- 错误写法:
$message->attach(['a.pdf', 'b.xlsx']) - 正确写法:
foreach ($files as $file) { $message->attach($file); } - 注意顺序:附件按
attach()调用顺序排列,收件端看到的顺序也如此
大附件容易超时或被SMTP服务器拒绝
多数邮件服务商限制单封邮件总大小(如Gmail 25MB,腾讯企业邮30MB),Yii2本身不限制,但SwiftMailer默认不设超时,PHP执行时间或内存不足也会中断。
- 发送前用
filesize()检查总附件大小,超过20MB建议改用网盘链接+文字说明 - 在
config/mail.php里配'transport' => ['timeout' => 60]防卡死 - 日志里加
Yii::info("Attached {$file}: " . filesize($file), 'mail'),排查漏传或空文件
附件路径权限、MIME类型、调用方式、大小边界——这四点串起来才真正跑得通。少一个,邮件就可能发出去但收不到附件,或者根本发不出去。


















