Currently Available: Need a skilled Software Developer for your next project?
Categories
Laravel

Passing Dynamic Data to Laravel Mail Templates

In Laravel, a mailable is a class that defines an email’s content and settings. Your code gives values to the mailable, which exposes selected values to a Blade template; the template prints them in the email.

For example, an order-shipping email might need a customer’s name and the order total. In Laravel 13, you can make data available through public mailable properties or pass selected values in the mailable’s Content definition. Use Blade’s escaped {{ ... }} syntax for ordinary text. Validate values and confirm the requester has permission before constructing the mailable.

How data reaches the Blade template

Your code first gets the needed values, such as an order from the database or data checked from a request. It passes those values to the mailable’s constructor. The mailable names the Blade view and makes values available to it. When Laravel renders the email, the template uses each value’s variable name.

Laravel 13 documents two ways to expose data to the email view: public mailable properties are made available automatically, and you can pass specific data through Content’s with array. See the mail documentation.

Choose how the mailable exposes data

A public property is concise when the template should have access to that property as-is:

class OrderShipped extends Mailable
{
    public function __construct(
        public Order $order,
    ) {}

    public function content(): Content
    {
        return new Content(
            view: 'mail.orders.shipped',
        );
    }
}

The Blade view can then use $order, for example:

Your order total is {{ $order->total }}.

The view can use every public property on the mailable. To expose only selected values to the template, keep the order in a protected property and list the values the template needs in with:

class OrderShipped extends Mailable
{
    public function __construct(
        protected Order $order,
    ) {}

    public function content(): Content
    {
        return new Content(
            view: 'mail.orders.shipped',
            with: [
                'customerName' => $this->order->customer_name,
                'orderTotal' => $this->order->total,
            ],
        );
    }
}

The view receives $customerName and $orderTotal:

Hello, {{ $customerName }}.

Your order total is {{ $orderTotal }}.

Pass an order to the mailable when you send it, for example with Mail::to($recipient)->send(new OrderShipped($order)). Make properties public when the template needs their full contents. Use with to choose or format the values the template receives.

Keep template input safe

Validate request data before passing it to a mailable, and check separately whether the requester has permission to take the action. Validation checks whether a value meets the expected rules, while a separate permission check establishes whether the requester may use it. Laravel lets you retrieve validated values with validated() or select specific values with safe()->only(...). See the validation documentation.

For ordinary text in an HTML email, use Blade’s {{ ... }} syntax. Blade escapes this output through PHP’s htmlspecialchars; {!! ... !!} outputs content without that escaping. Laravel’s Blade documentation cautions against using unescaped output for user-supplied content.

Escaping HTML text does not make every value safe everywhere. For example, validate a dynamic URL and allow only an approved scheme. When you put a URL in an HTML attribute, follow OWASP’s context-specific output guidance for URL and attribute handling. Consult the same guidance separately for user-authored HTML. When possible, give the template only the values it needs instead of exposing a full object.

Check rendered content and queued mail

Test that the mailable passes the expected values into the view and that the rendered HTML contains the intended text. If the email has a plain-text view, check its output too. Laravel provides mailable content assertions and a way to render a mailable for inspection without sending it, as described in its mail documentation.

When you put a mailable on a queue, Laravel renders and sends the email later, but Blade receives its variables the same way. If the queued mailable runs inside a database transaction, its job can run before the transaction commits. When the email depends on those database changes, Laravel’s afterCommit option waits to dispatch the job until the transaction commits.

What I'm building

Delegate tasks. Get software.

Give Vroni a GitHub issue, bug report, spec, or rough idea. It reads the repo, plans the change, writes code, runs checks, and works toward a review-ready pull request.

Take a look at vroni.com

Email updates

Usually a new article and a few links I found interesting.

No spam. Unsubscribe with one click.

Leave a Reply

Your email address will not be published. Required fields are marked *