推荐使用 php artisan make:mail --markdown 命令生成 Markdown 邮件类,它自动创建 Mailable 类和对应 Blade 模板(如 resources/views/mails/order/shipped.blade.php),并默认启用 MailMarkdown 渲染器生成 HTML+纯文本双版本;需先运行 php artisan vendor:publish --tag=laravel-mail-markdown 发布布局才能自定义样式。

Markdown 邮件类怎么生成
用 php artisan make:mail 加 --markdown 参数,是唯一推荐的创建方式。不加这个参数,后续手动改视图路径或重写 build() 容易漏掉关键渲染逻辑。
比如要发一份带格式的发货通知,运行:
php artisan make:mail OrderShipped --markdown=mails.order.shipped
这会生成:app/Mail/OrderShipped.php,同时自动在 resources/views/mails/order/shipped.blade.php 创建 Markdown 模板文件(注意不是 emails/ 目录)。
- 路径名
mails.order.shipped会被 Laravel 自动转为resources/views/mails/order/shipped.blade.php,别手误写成emails.order.shipped - 模板内容默认是 Markdown 语法,Laravel 会在发送时用内置的
MailMarkdown渲染器转成 HTML + 纯文本双版本 - 如果目录
resources/views/mails不存在,命令不会自动创建,得先mkdir -p resources/views/mails/order
Markdown 模板里能用哪些语法和变量
支持标准 CommonMark 语法(标题、列表、链接、代码块等),但不支持自定义 HTML 标签或内联样式——所有样式由 Laravel 内置的邮件布局控制。
变量传递方式和普通 Blade 一样,但只认构造函数中声明的 public 属性,或 with() 显式传入的键值对:
@component('mail::message')
# 您的订单已发货
<p>订单号:{{ $order->number }}<br />
预计送达:{{ $order->estimated_delivery }}</p><p>@component('mail::button', ['url' => $trackingUrl])
查看物流
@endcomponent</p><p>谢谢您的信任!<br />
{{ config('app.name') }}
@endcomponent-
@component('mail::button')和@component('mail::panel')是 Laravel 提供的专属组件,不能替换成<button>或<div class="panel"> - 模板里直接访问
$order前,必须确保OrderShipped类的构造函数里有public $order;并赋值 - 别在 Markdown 模板里写
{!! $html !!}—— Markdown 渲染器不处理未转义内容,会原样输出甚至破坏结构
为什么发出去的 Markdown 邮件样式丑或不响应
因为 Laravel 的 Markdown 邮件默认使用 Tailwind CSS 内联样式,但这些样式只在发布默认布局后才可定制。没发布前,你看到的是框架内置的“最小可用”样式,窄屏下可能堆叠错乱。
解决办法是先运行:
php artisan vendor:publish --tag=laravel-mail-markdown
这会把默认布局复制到 resources/views/vendor/mail/html 和 resources/views/vendor/mail/text。之后你才能安全修改:
-
resources/views/vendor/mail/html/layout.blade.php控制整体结构和内联 CSS -
resources/views/vendor/mail/html/themes/default.css可覆盖颜色、字体、断点等 - 改完记得清缓存:
php artisan view:clear,否则旧布局仍被读取 - 不要删
@stack('styles')—— 这是 Laravel 注入内联样式的钩子,删了按钮、面板就没了样式
队列里发 Markdown 邮件要注意什么
Markdown 渲染发生在发送时刻,不是构建 Mailable 实例时。所以只要队列任务本身能序列化成功,渲染就不是问题。
但两个硬限制必须避开:
- 别在
build()里调 Eloquent 查询(如$this->user = User::find($id);)—— 队列延迟执行时模型可能已被软删除或数据变更 - 收件人地址必须在
dispatch()前就绑定好:Mail::to($user->email)->queue(new OrderShipped($order));,而不是在队列 Job 里再调to() - 附件不能用
attach()传相对路径,storage_path('app/invoices/'.$order->id.'.pdf')才安全;中文文件名务必用attachData()显式指定filename
最常被忽略的一点:本地开发用 MAIL_MAILER=log 时,Markdown 邮件的日志里只显示原始 Markdown 文本,不渲染 HTML —— 别因此误判模板写错了。真要预览效果,得切回 smtp 并配 Mailtrap 或用 MAIL_MAILER=array 结合 dd() 看最终 HTML 输出。


















