Laravel邮件模板路径必须显式指定,不能依赖类名自动映射;需在build()中调用view('emails.welcome'),否则抛ViewNotFoundException;默认查找逻辑脆弱,推荐统一存放于resources/views/emails/并显式声明。

邮件模板路径必须显式指定,不能依赖类名自动推导
Laravel 的 Mailable 类不会把 WelcomeEmail 自动映射成 resources/views/welcome-email.blade.php,也不会按驼峰转短横线去猜路径。一旦没写 $this->view('emails.welcome'),就会抛出 ViewNotFoundException。
常见错误是把模板扔进 resources/views/mail/ 或 resources/views/emails/welcome.blade.php 却忘了在 build() 方法里调用 view()。Laravel 默认只查 resources/views/ 下的同名文件(如 WelcomeEmail 类默认找 welcome-email.blade.php),但这个“默认”非常脆弱,不推荐依赖。
- 统一用
resources/views/emails/目录存放所有邮件视图 - 在
build()中显式写$this->view('emails.welcome') - 避免用
mail::welcome这类自定义命名空间,除非你已注册了视图组件前缀
Blade 组件在邮件中可用,但 Markdown 邮件不支持原生 @component
你在 resources/views/components/button.blade.php 里写的普通 Blade 组件,只要通过 @include('components.button') 或 <x-button></x-button> 引入,就能在 HTML 邮件模板中正常渲染。但 Laravel 内置的 Markdown 邮件(mail::message)是另一套系统,它用的是自己的解析器,不是标准 Blade 编译流程。
比如你写 @component('mail::button', ['url' => $url]),这本质是调用 Laravel 提供的 Markdown 组件类,不是加载你自定义的 components.button。想复用自己写的按钮样式?得重写 resources/views/vendor/mail/html/components/button.blade.php,或改用纯 Blade 模板 + <x-button></x-button>。
- HTML 邮件:可自由使用
@include、<x-xxx></x-xxx>、@props等全部 Blade 功能 - Markdown 邮件:
@component('mail::xxx')只认vendor/mail下的组件,不识别自定义路径 - URL 插值在 Markdown 模板里会出错(如
{{ $user->id }}被 URL 编码),务必用{{ $user->id }}原样传参,不要拼在字符串里
邮件中复用组件要小心数据传递和 CSS 兼容性
邮件客户端对 CSS 支持极差,Gmail 会剥离 <style> 标签,Outlook 不认 Flexbox,而 Blade 组件若带内联样式或 JS,很可能直接失效。你封装了一个 <x-card>,里面用了 class="bg-blue-50 p-4",但 Tailwind 的类名不会被自动内联——邮件里只会看到未定义的 class。
更隐蔽的问题是数据作用域:组件里用 $slot 或 $attributes 接收内容时,父模板传进来的变量若没提前 with() 或声明为 public 属性,组件内部就拿不到。
- 邮件组件必须用内联
style属性,别依赖外部 CSS 或 Tailwind 类名 - 用
with()显式传参,比如$this->with(['user' => $user, 'cta_url' => $url]) - 避免在组件里调用模型方法(如
$user->fullName()),队列发送时可能反序列化失败 - 测试时重点看 Gmail、Apple Mail、Outlook Desktop 三端渲染效果,别只信浏览器预览
多语言邮件必须手动设 locale,Blade 翻译函数不自动感知上下文
{{ __('Welcome') }} 在邮件里不会根据收件人语言自动切换,因为 Laravel 的本地化上下文(App::getLocale())在队列任务中是空的,或者沿用发信进程的默认 locale。你看到所有用户都收到英文邮件,不是翻译文件没写,而是没设。
正确做法是在 Mailable 构造函数里接收 $locale,然后在 build() 中调用 $this->setLocale($locale);或者用 __('Welcome', [], $locale) 显式指定语言包。否则 trans('emails.welcome') 这类调用全按 config('app.locale') 走。
- 数据库里存用户偏好语言(如
users.locale),构造Mailable时传进去 - 不要在 Blade 模板里写
@if(app()->getLocale() === 'zh'),那判断的是服务器 locale,不是目标用户 - 邮件模板里的图片路径、日期格式、货币符号都要随 locale 变,不能硬编码


















