Mailables

Markdown Mailables, Attachments, and Headers

A Markdown mailable uses the <x-mail::message>, button, panel and table components; Laravel 2,157 renders it with CommonMark, inlines the CSS, and derives the plain-text part:

resources/views/mail/orders/shipped.blade.phpXML
<x-mail::message>
# Your order is on its way
Hi {{ $order->customer->name }}, order **#{{ $order->id }}** left the warehouse today.
<x-mail::table>
| Title | Qty | Price |
|:------|:---:|------:|
@foreach ($order->products as $book)
| {{ $book->title }} | {{ $book->pivot->quantity }} | ${{ $book->pivot->unit_price }} |
@endforeach
</x-mail::table>
<x-mail::button :url="route('orders.show', $order)" color="success">
Track your parcel
</x-mail::button>
Thanks,<br>
{{ config('app.name') }}
</x-mail::message>
The rendered HTML of OrderShipped for order 1, captured in headless Chrome
The rendered HTML of OrderShipped for order 1, captured in headless Chrome 1

Keep the template flush left (indented Markdown becomes a code block); vendor:publish --tag=laravel-mail exposes the components for restyling. Attachments come from one more method:

OrderShipped: the invoice from the private disk as an attachmentPHP
public function attachments(): array
{
    return [Attachment::fromStorageDisk('local', "invoices/{$this->order->id}.pdf")
        ->as("invoice-{$this->order->id}.pdf")->withMime('application/pdf')];
}

fromPath(), fromStorage() and fromData() cover other sources, and a model implementing Attachable attaches itself. A headers() method returning new Headers(text: ['X-Bookshop-Order' => (string) $this->order->id]) adds a custom header, and Headers also sets messageId and references, which thread replies in the customer's inbox.