附件失败主因是路径错误、驱动未生效或收件人缺失;须用绝对路径如storage_path(),避免相对路径;中文名需用attachdata()绕过rfc2231编码;nova路径需转磁盘绝对路径;务必用log驱动验证附件头并确认send()调用链完整。

附件加不上,八成不是代码写错了,而是路径、驱动或收件人链没走完。
attach() 传的路径必须是绝对路径
相对路径如 ./storage/app/invoice.pdf 或 storage/app/invoice.pdf 会失败——Laravel 不会在当前目录或视图目录里找文件。它只认操作系统层面的真实路径。
- 正确写法用
storage_path('app/invoices/invoice-123.pdf'),返回类似/var/www/myapp/storage/app/invoices/invoice-123.pdf - 如果文件存在
public盘,且路径存的是invoices/report.pdf,得先用Storage::disk('public')->path('invoices/report.pdf')拿绝对路径 - 用
file_exists()打印检查:在build()方法里加dd(file_exists($absPath)),别靠猜
中文文件名在 Outlook 里显示乱码怎么办
直接传中文名给 attach() 会触发 RFC 2231 编码,老客户端(比如 Outlook 2010/2013)不兼容,显示成 filename*=UTF-8''%E6%8A%A5%E8%A1%A8.pdf 这种。
- 绕过编码:改用
attachData(),把文件内容读出来再塞进去:$this->attachData(file_get_contents($path), 'baobiao.pdf', ['mime' => 'application/pdf']) - 不要依赖
basename($path)提取原名,尤其是路径含中文时;显式指定英文as名更稳 - 测试时别只看 Gmail 或 Apple Mail,一定要用 Outlook 桌面版实测
从 Nova 或数据库读出的文件路径怎么转成可 attach 的路径
Nova 的 File 字段默认只存相对路径(如 public/abc.jpg),而 attach() 要的是磁盘根目录下的绝对系统路径。
- 先确认字段存的是什么:查数据库,看
file字段值是abc.jpg还是public/abc.jpg - 如果是
public/xxx,用Storage::disk('public')->path($dbPath) - 如果是纯文件名(无目录),且确定在
public盘,就拼:public_path($dbPath) - 千万别直接拼字符串,比如
storage_path('app/' . $dbPath)—— 这假设了所有文件都在app盘,实际可能错配到public盘
为什么调了 attach() 却没收到附件
最常被忽略的三个断点:驱动没生效、收件人漏了、Mailable 实例没真正 send。
- 先切
MAIL_MAILER=log,发一次,去storage/logs/laravel.log里搜Content-Disposition: attachment,确认日志里真写了附件头 - 确保调用了
Mail::to($email)->send(new MyMailable()),而不是new MyMailable()->send()—— 后者跳过了 Laravel 的消息构建流程 -
to()必须在send()前完成,且参数只能是字符串或字符串数组,不能传User::first()这种模型实例
附件逻辑本身很简单,难的是路径来源、磁盘配置、客户端兼容性这三块咬合不上。每加一个附件,最好都用 file_exists() 和 log 驱动双重验证,别让“看起来能跑”骗过自己。











