skip to content

In Laravel, what is a Markdown mailable, how do you generate one, and how do you customise its components and theme?

level: middleimportance: should knowfreq 36%

answer

  1. prebuilt, responsive email components
  2. make:mail --markdown=mail.orders.confirmed
  3. <x-mail::message>, button, panel, table
  4. HTML plus a plain-text part
  5. vendor:publish --tag=laravel-mail

basics

~20 s

A Markdown mailable renders a Markdown template built from Laravel's mail components (message, button, panel, table) into a responsive HTML email plus a plain-text version. Generate it with make:mail --markdown; restyle it by publishing the laravel-mail components and editing the theme CSS.

solid answer

~30 s

`php artisan make:mail OrderConfirmed --markdown=mail.orders.confirmed` creates the class, with `content()` returning `new Content(markdown: 'mail.orders.confirmed')`, and a template at `resources/views/mail/orders/confirmed.blade.php`. The template mixes Markdown with Blade components: `<x-mail::message>` wraps the email, `<x-mail::button :url="$url">` renders a button (`color` of `primary`, `success` or `error`), `<x-mail::panel>` a highlighted block and `<x-mail::table>` a Markdown table. From that one template Laravel renders a styled HTML part, with the theme's CSS inlined, and a plain-text part. To change the look, `php artisan vendor:publish --tag=laravel-mail` copies the components to `resources/views/vendor/mail`; edit `html/themes/default.css`, or add a theme file and select it with `mail.markdown.theme` (`MAIL_MARKDOWN_THEME`) or a mailable's `$theme` property.

code

bash · 2 lines
bash
php artisan make:mail OrderConfirmed --markdown=mail.orders.confirmed
php artisan vendor:publish --tag=laravel-mail

go deeper

for a junior

Recall the --markdown option, the Content(markdown: ...) line it creates, and the four components: message, button, panel and table.

for a middle

Explain that one template yields HTML with inlined CSS plus plain text, why indentation breaks it, and how publishing laravel-mail and MAIL_MARKDOWN_THEME change the look.

for a senior

Show judgment on when components suffice and when a hand-built view is justified, and how you keep published components maintainable across framework upgrades.

for a principal

Treat transactional email design as a shared asset: one published theme, a review path for copy, and a policy for which messages may diverge from it.

## Why Markdown mailables exist HTML email is notoriously hostile: table layouts, inline styles, clients that strip `<style>` blocks. Laravel's **Markdown mailables** hide that. You write a short Blade template in Markdown using a handful of prebuilt mail components, and Laravel produces a responsive, table-based HTML email with inlined CSS **and** a plain-text alternative from the same source. ## Generating one ```bash php artisan make:mail OrderConfirmed --markdown=mail.orders.confirmed ``` This writes two files: 1. `app/Mail/OrderConfirmed.php`, whose `content()` returns `new Content(markdown: 'mail.orders.confirmed')`. 2. `resources/views/mail/orders/confirmed.blade.php`, a starter template. You can also convert an existing mailable by changing `view:` to `markdown:` in its `Content`. ## Writing the template ```html <x-mail::message> # Order #{{ $order->number }} confirmed Thanks for your purchase. Your receipt is attached. <x-mail::table> | Item | Qty | Price | |:-----|:---:|------:| @foreach ($order->lines as $line) | {{ $line->name }} | {{ $line->quantity }} | {{ $line->price }} | @endforeach </x-mail::table> <x-mail::button :url="route('orders.show', $order)" color="success"> View your order </x-mail::button> Thanks,<br> {{ config('app.name') }} </x-mail::message> ``` The components: | Component | Renders | |---|---| | `<x-mail::message>` | the outer layout with header, body and footer | | `<x-mail::button>` | a call-to-action; props `url`, `color` (`primary`, `success`, `error`) and `align` (default `center`) | | `<x-mail::panel>` | a block with a different background, for callouts | | `<x-mail::table>` | converts a Markdown table into an email-safe HTML table | One rule trips people up: **do not indent** the Markdown. Markdown treats indented lines as code blocks, so a nicely indented template renders as monospaced text. ## HTML and plain text from one source When the mailable is built, Laravel renders the template twice: once through the `html` component set (then inlines the theme's CSS) and once through the `text` component set. The resulting message carries both parts, so clients that prefer plain text get a sensible version without you maintaining a second template. ## Customising components and theme 1. **Publish the components:** `php artisan vendor:publish --tag=laravel-mail` copies them to `resources/views/vendor/mail`, with an `html` and a `text` directory. Laravel looks there first, so edits override the framework's versions. 2. **Restyle:** edit `resources/views/vendor/mail/html/themes/default.css`. The CSS is inlined into the HTML at render time, which is what most email clients need. 3. **Add a theme:** drop `brand.css` into the same `themes` directory and set `MAIL_MARKDOWN_THEME=brand`. The skeleton's `config/mail.php` omits the `markdown` block; the framework's default (theme `default`, read from `MAIL_MARKDOWN_THEME`) is merged in, and you can add the block to your file to change it. 4. **Per mailable:** set `public $theme = 'brand';` on one mailable to override the configured theme for that message only. ## Details that bite in practice - **The header comes from config.** The default `message` layout prints `config('app.name')` linked to `config('app.url')`, so an unset `APP_NAME` shows "Laravel" at the top of every customer email. - **Images need absolute URLs.** The email is read outside your site, so a relative `/img/logo.png` breaks; use `asset()` with a correct `APP_URL`, or embed the image. - **Escaping still applies.** The template is Blade, so `{{ $order->note }}` is escaped as usual; only switch to unescaped output for trusted HTML. - **Preview before sending.** Returning the mailable from a local route renders the HTML exactly as sent, which is the fastest way to tune a theme. - **Published files are yours to maintain.** Once published, framework updates to the components no longer reach you, so publish only when you actually need to change them. ## When to prefer a plain Blade view - A design team supplies finished HTML that must be pixel-exact. - The email is mostly images and custom layout, where the components add little. For transactional mail such as order confirmations and receipts, Markdown mailables give consistent branding with far less effort. ## Summary - `make:mail --markdown=...` scaffolds class and template; `Content(markdown: ...)` wires them. - `x-mail::message`, `button`, `panel` and `table` build the body; do not indent. - Publish with `--tag=laravel-mail`, edit `default.css` or add a theme via `MAIL_MARKDOWN_THEME` or `$theme`.

  • Why did a Markdown email render part of its body as monospaced code?
    The template was indented. Markdown treats indented lines as a code block, so nested indentation inside `<x-mail::message>` turns paragraphs into code. Keep Markdown content flush left.
  • How do you give one mailable a different look without changing all mail?
    Publish the components, add a CSS file such as `brand.css` under `resources/views/vendor/mail/html/themes`, and set `public $theme = 'brand';` on that mailable. The configured `mail.markdown.theme` still applies to every other Markdown mailable.

saying these in an interview costs you the question

  • A Markdown mailable sends only an HTML part; plain text needs a second template.
  • You must write your own inline CSS for Markdown emails to look styled.
  • Indenting Markdown inside <x-mail::message> is harmless.
  • Customising the mail layout means editing files inside vendor/laravel/framework.
  • Any CSS colour name, such as purple, styles the mail button component.