Mailable classes and why the view is not the email

An email assembled in a controller — subject here, view there, attachments in a third place — cannot be tested without sending it, and the subject line ends up somewhere different from the body.

class OrderShipped extends Mailable
{
    public function build()
    {
        return $this->subject('Your order is on its way')
                    ->markdown('emails.orders.shipped')
                    ->attachData($this->pdf, 'invoice.pdf', ['mime' => 'application/pdf']);
    }
}

// and it renders in the browser without sending anything
Route::get('/preview', function () { return new OrderShipped($order); });

The preview route is the reason to bother: email templates are otherwise edited blind, or tested by sending to yourself and waiting. Returning the mailable from a route renders it as HTML. Mail::fake() then asserts it was queued with the right recipient without a mail server being involved at all.