Variables aren't working when using them inside the Markdown Mailable templates files. You get a 'undefined variable' message.
When following the guide on https://laravel.com/docs/5.4/mail#markdown-mailables to create a Markdown email you can customise the template files by using the code below:
php artisan vendor:publish --tag=laravel-mail
When adding a variable into the Mailable, the variable isn't available on the template files to e.g. be used inside the header or footer of the message.
E.g. Mailable
class ReviewInvite extends Mailable
{
use Queueable, SerializesModels;
public $visit;
/**
* Create a new message instance.
*
* @return void
*/
public function __construct(Visit $visit)
{
$this->visit = $visit;
}
/**
* Build the message.
*
* @return $this
*/
public function build()
{
return $this->markdown('emails.review-invite');
}
}
We can use the $visit variable inside the emails.review-invite file, but when using the $visit variable inside any of the /resources/views/vendor/mail/html files, you get a "Undefined variable: visit" message.
Yes all variables are only available in the mailable view, this is by design since mail templates uses components, a blade component doesn't have the same scope as its main slot.
Check: https://laravel.com/docs/5.4/blade#components-and-slots
Thanks @themsaid!
Is there a way to overwrite e.g. the header and footer blade components through the mailable view?
I'm asking since I would like to add an image logo to the header and include a company name through $visit->company->title to the footer.
Or would this currently only be possible by using an html mail template instead of the Markdown template?
Check Passing Additional Data To Components
https://laravel.com/docs/5.4/blade#components-and-slots, you can use that to pass data to the main layout.
Closing since it's not a bug report but please feel free to ping me if you need further help.
For anyone who faced this problem. Pass the second value as array please
@Qbixx Pass data with with($name,$value)
, and _$value_ just has to be an array :)
For example:
in class Welcome extends Mailable
public $customer;
public function __construct(User $user)
{
//
$this->customer = $user->toArray();
}
/**
* Build the message.
*
* @return $this
*/
public function build()
{
return $this->markdown('emails.welcome')
->with('customer', $this->customer);
}
PLEASE note: if you have a variable that you made it a global via view composer, in your CSP, then it gonna override your array.
Dear @themsaid it seems like blade components don't have a _REAL_ different scope than normal views after all?! I mean it got effected with view composer, anyways, thanks!
Yes, i did it... First the Mailable Class
`class ContactNew extends Mailable {
use Queueable, SerializesModels;
/**
* Create a new message instance.
*
* @return void
*/
public function __construct() {
}
/**
* Build the message.
*
* @return $this
*/
public function build(Request $request) {
$email = $request->email;
return $this->from($request->email)
->markdown('auth.mail.contactNew')
->with('email', $request->email);
}
}
Then... the Blade file
@component('mail::message')
{{$email}}
The body of your message.
@component('mail::button', ['url' => ''])
Button Text
@endcomponent
Thanks,
{{ config('app.name') }}
@endcomponent
`
Hi
Does anyone know if you can get blade variables working in the vendor/mail/html/layout.blade.php file ? This is the html file that the markdown appears to be generated in.
I wanted to put a " ---- Please reply above this line ---" into the output but it has to be straight after the body tag before any of the components are created and only for emails that are coming from our support ticket system (otherwise I could just code the words directly in the file).
I wanted to use markdown because its easy to create tables and buttons etc but the above code for using ->with() doesn't seem to work in the actual layout.blade.php file - I wonder if this is what @themsaid was referring to
@clausche @mkwsra did you guys do anything special for this to work? Still doesn't work for me, whether with ->with('invoice', $invoice)
or ->with(['invoice' => $invoice])
.
@godbout Pass the second value as array please, and I edited my comment so I hope it's more descriptive 😉 . best of luck 🍀
@mkwsra thanks! actually I was doing it right. I discovered that when I stopped queueing the mail and it got sent without issues. Then I remember I should probably restart horizon when I change the code. And yes, I do have to. 🤦🏻️ 😂️
Hi everyone!
I'm trying to add a variable to the /vendor/mail/html/message.blade.php
template kind of like how @qbixx was describing. I'm sending markdown emails through Laravel's Notifications, but I always get undefined variable
when I try and pass it to the main message.blade.php template. Does anyone have any suggestions? Here is my message.blade.php:
@component('mail::layout')
{{-- Header --}}
@slot('header')
@component('mail::header', ['url' => config('app.url')])
Test
{{ $my_testing_var }}
@endcomponent
@endslot
{{-- Body --}}
{{ $slot }}
{{-- Subcopy --}}
@isset($subcopy)
@slot('subcopy')
@component('mail::subcopy')
{{ $subcopy }}
@endcomponent
@endslot
@endisset
{{-- Footer --}}
@slot('footer')
@component('mail::footer')
© {{ date('Y') }} {{ config('app.name') }}. All rights reserved.
@endcomponent
@endslot
@endcomponent
and here is my toMail() function in my notification:
public function toMail($notifiable)
{
return (new MailMessage)
->subject( 'testing' )
->markdown('mail.test', [
'test_user' => 'test',
])->with( 'my_testing_var', [ 'my_testing_var' => 'testing' ] );
}
As you can see I'm using with() on the MailMessage, but this still results in an undefined variable upon the notification call.
Anyone have any ideas?
Thanks!
public
for the data you're passing in.<?php
namespace App\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
class InsuranceBought extends Mailable
{
use Queueable, SerializesModels;
public $data;
/**
* Create a new message instance.
*
* @return void
*/
public function __construct($data)
{
$this->data = $data;
}
/**
* Build the message.
*
* @return $this
*/
public function build()
{
return $this->from('[email protected]')
->subject('Insurance bought for tripname trip!')
->markdown('trips.email.students')
->with(['data', $this->data]);
}
}
And then for sending:
$data = array('test' => 'bla');
Mail::to($student)->send(new InsuranceBought($data));
I had the exact same requirement that @qbxx had. I needed to dynamically pass the company name and logo to the header and some other customizations in the footer in the mail in Laravel 5.4. Based on what @themsaid pointed out, it seems you can't pass data from the "subview" to the "parent view". What I did was to expand the scope of the subview to include all markdown components that need dynamic data and that solved the problem.
For anybody looking at providing variables to the templates header and footer here is the solution.
Step 1: Publish the view files using Laravel's publish tool
php artisan vendor:publish --tag=laravel-mail
Step 2: Make a variable available to your Mailable view by making it public (no need to use with
method).
<?php
namespace App\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
class InsuranceBought extends Mailable
{
use Queueable, SerializesModels;
public $header_url, $header_title;
/**
* Create a new message instance.
*
* @return void
*/
public function __construct()
{
$this->header_url = 'https://example.com';
$this->header_title = 'My title';
}
/**
* Build the message.
*
* @return $this
*/
public function build()
{
return $this->from('[email protected]')
->subject('Insurance bought for tripname trip!')
->markdown('trips.email.students');
}
}
Step 3: Update the vendor/mail/html/message.blade.php
and vendor/mail/markdown/message.blade.php
files to be the following:
@component('mail::layout')
{{-- Header --}}
@slot('header')
@component('mail::header', ['url' => isset($header_url) ? $header_url : config('app.url')])
{{ isset($header_title) ? $header_title : config('app.name') }}
@endcomponent
@endslot
{{-- Body --}}
{{ $slot }}
{{-- Subcopy --}}
@if (isset($subcopy))
@slot('subcopy')
@component('mail::subcopy')
{{ $subcopy }}
@endcomponent
@endslot
@endif
{{-- Footer --}}
@slot('footer')
@component('mail::footer')
© {{ date('Y') }} {{ config('app.name') }}. All rights reserved.
@endcomponent
@endslot
@endcomponent
Last step is to give the blade component access to the variable as explained by @themsaid
The following is your mailable view file:
@component('mail::message', ['header_url' => $header_url, 'header_title' => $header_title])
Hey {{ $user->first_name }},
Here is the message you are sending.
@component('mail::button', ['url' => $url])
Create Account
@endcomponent
Thanks,<br>
{{ $account->name }}
@endcomponent
Thank You @warren32
Ok, typical as most Laravel community issues people just throw around ideas without following the stack and investigating them selfs - and perhaps learning along the way... Also if your giving example dont just paste code from your own use-case / application. Make it generic and readable for the community. This is Open Source Software.
@themsaid Your answer is actually incorrect. Sorry. May you please update it as it's the highest comment on this thread that Google picks up.
return (new MailMessage)
->subject('Hello world')
->markdown('emails.hello-world', [
'firstName' => $notifiable->firstName,
'lastName' => $notifiable->lastName,
]);
You may pass view data as second param to markdown()
function.
Thanks.
Ok, typical as most Laravel community issues people just throw around ideas without following the stack and investigating them selfs - and perhaps learning along the way... Also if your giving example dont just paste code from your own use-case / application. Make it generic and readable for the community. This is Open Source Software.
@themsaid Your answer is actually incorrect. Sorry. May you please update it as it's the highest comment on this thread that Google picks up.
Solution
return (new MailMessage) ->subject('Hello world') ->markdown('emails.hello-world', [ 'firstName' => $notifiable->firstName, 'lastName' => $notifiable->lastName, ]);
You may pass view data as second param to
markdown()
function.Thanks.
fixed my error
@warren32 i will add to your solution that you can name your variables to use them later in any part of your html code :
// vendor/mail/html/message.blade.php
@slot('anyNameYouWantForYourVariable')
{{ $header_title }}
@endslot
and then, you can use it in your layout :
// vendor/mail/html/layout.blade.php
{{ $anyNameYouWantForYourVariable }}
Controller
$email = new welcomemail($user);
Mail::to(Auth::user()->email)->send($email);
mail controller
namespace App\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
class welcomemail extends Mailable
{
use Queueable, SerializesModels;
public $stu;
/**
* Create a new message instance.
*
* @return void
*/
public function __construct($stu)
{
$this->stu = $stu;
}
/**
* Build the message.
*
* @return $this
*/
public function build()
{
return $this->markdown('emails.welcome')->with($this->stu);
}
}
view
@component('mail::message')
# Introduction
The body of your message {{$stu}}.
@component('mail::button', ['url' => ''])
Button Text
@endcomponent
Thanks,<br>
{{ config('app.name') }}
@endcomponent
this works 100% correct
Most helpful comment
For anybody looking at providing variables to the templates header and footer here is the solution.
Step 1: Publish the view files using Laravel's publish tool
php artisan vendor:publish --tag=laravel-mail
Step 2: Make a variable available to your Mailable view by making it public (no need to use
with
method).Step 3: Update the
vendor/mail/html/message.blade.php
andvendor/mail/markdown/message.blade.php
files to be the following:Last step is to give the blade component access to the variable as explained by @themsaid
The following is your mailable view file: