Laravel 5: HTML with variables from DB for Mailable class - laravel

So I need to store my blade email templates in database.
And now I am having problem to use db content with view, because dynamic informations are not rendered.
Here is the code to elaborate a bit more problem which I am facing:
Mailable class:
namespace App\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Queue\ShouldQueue;
use App\User;
class activateUser extends Mailable
{
public $html;
public $user;
use Queueable, SerializesModels;
/**
* Create a new message instance.
*
* #return void
*/
public function __construct(User $user)
{
//this actually is much longer text coming from the DB - basicly coopied blade email template into the db
$this->html = 'Hi {{ $user->first_name }},<br /><br /> Your profile on our site has been activated.<br /><br />';
$this->user = $user;
}
/**
* Build the message.
*
* #return $this
*/
public function build()
{
return $this->view('emails.activateUser')->subject('Your account is activated');
}
}
Then the view emails.activateUser.blade.php looks like this:
{{ $html }}
And Inside of my controller I am calling this:
Mail::to($user->email)->send(new activateUser($user));
Problem is that actual username of the user will not be printed in the email and {{ }} will stay as well in email content.
Any ideas how to solve this, since my email template content needs to come from DB

You can use the Blade template compiler to compile a string:
public function compileBladeString(string $template, $data = []): string
{
$bladeCompiler = app('blade.compiler');
ob_start() && extract($data, EXTR_SKIP);
eval('?>' . $bladeCompiler->compileString($template));
$compiled = ob_get_contents();
ob_end_clean();
return $compiled;
}
You can then simply invoke this method with a string containing your template from the database.

Related

Why html tags are not rendered in laravel sent email?

Sending email with
\Mail::to(
method in laravel 8 app
I have html tags in im my email template
#component('mail::message')
<h3 >
You registered at {{ $site_mame }}
</h3>
Best regards, <br>
...
#endcomponent
and code in my app/Mail/UserRegistered.php :
<?php
namespace App\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
class UserRegistered extends Mailable
{
use Queueable, SerializesModels;
public $site_mame;
public $user;
public $confirmation_code;
public function __construct( $site_mame, $user, $confirmation_code )
{
$this->site_mame = $site_mame;
$this->user = $user;
$this->confirmation_code = $confirmation_code;
}
/**
* Build the message.
*
* #return $this
*/
public function build()
{
return $this->markdown('email.UserRegisteredEmail')
->with('site_mame', $this->site_mame)
->with('user', $this->user)
->with('confirmation_code', $this->confirmation_code);
}
}
With sendgrid options in my .env file I got valid emaul at my google account, but html tags are not rendered.
If there is a way to render all html tags? Does it depend on laravel app/emailing options
or setting in my google(or some other account).
What can I do from my side?
UPDATED :
Modified :
$this->view(
I got error :
No hint path defined for [mail]. (View: project/resources/views/email/UserRegisteredEmail.blade.php)
Pointing to my blade file.
Searching in net I found as possible decision :
php artisan vendor:publish --tag=laravel-mail
and clearing all cache
But I still got the same error.
Did I miss some options ?
Thanks in advance!
You are using the markdown() method, which is a method to utilize the pre-built templates and components of mail notifications in your mailables.
This offers a multitude of advantages:
instead of wrapping headings in h1, h2, etc. tags, you can just put a #, ##, etc. at the beginning of the line
no need to wrap lists in <ul>, and list items in <li> tags. In markdown, you can just use a dash (-) for listing elements
italic/bold font can be achieved by putting */** around the text you want to emphasize
You can read more about this on the official Laravel documentation.
https://laravel.com/docs/8.x/mail#markdown-mailables
If you want to use HTML, you can just render a view:
/**
* Build the message.
*
* #return $this
*/
public function build()
{
return $this->view('email.UserRegisteredEmail')
->with('site_mame', $this->site_mame)
->with('user', $this->user)
->with('confirmation_code', $this->confirmation_code);
}

How can i pass the variables in the Mail body with laravel?

I want to pass the variables in my mail body how can I do that.
I am doing.
I want to send the mail template which is coming from DB, In that template, I have defined the variables to be get replaced when it is sent.
`$record = DB::table('email_templates')->select('content','em_temp_id')->where('em_temp_id',
$request->select_temp)->where('is_active', 1)->first();
$body = htmlspecialchars_decode($record->content);' //the html body
and my mail function
'Mail::send([],[], function($message) use ($Toarray, $ToCCarray, $ToBCCarray, $subject, $body,
$is_plainOrHtml){
$message->to($Toarray, '');
$message->cc($ToCCarray, '');
$message->bcc($ToBCCarray, '');
$message->subject($subject);
$message->setBody($body, 'text/html'); //for plain text email
});'
Template in DB is like:
`<p>Dear {{$userName}},</p>
<p>The {{$service_provider}}, requesting you to join <strong>{{$channel}}</strong> service.
</p>`
Array to pass:
`$arr_pass['userName'] = 'John';
$arr_pass['service_provider'] = 'abc.com';
$arr_pass['channel'] = 'Tom';`
How can i pass this array in the mail body?
You can use Blade::compileString, which will translate the blade template that you read from the database. There is one tricky part when you do so - how to send the variables' data.
Here are some hints:
You could use this library: https://github.com/TerrePorter/StringBladeCompiler
You could use a BladeCompiler similar to Is there any way to compile a blade template from a string?
Roll your own compiler by checking the implementation of https://laravel.com/api/8.x/Illuminate/View/Compilers/BladeCompiler.html
You can create a new Mail class by extending Mailable class and pass your array to the constructor of the Mail class.
Here in the below example, RFIRequestMail is a Mail class created in App\Mail Directory.
RFIRequestMail.php
<?php
namespace App\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Queue\ShouldQueue;
class RFIRequestMail extends Mailable
{
use Queueable, SerializesModels;
public $verifierData;
/**
* Create a new message instance.
*
* #return void
*/
public function __construct($data)
{
$this->data = $data;
}
/**
* Build the message.
*
* #return $this
*/
public function build()
{
return $this->view('mail-view-template');
}
}
MailController
$sendData = User::find($id);
$data = User::find($company_id);
$sendData["link"] = env("APP_URL");
$sendData["year"] = $request->get("year");
$sendData["user"] = $data->first_name.' '.$data->last_name;
Mail::to($data->email)->send(new RFIRequestMail($sendData));

Attaching PDF generated through Laravel to Mailable

At the moment I currently use laravel-snappy to generate my PDFs from pages, I do this primarily because it plays really nice with some JavaScript scripts I have on a few of my generated pages.
I know it's possible to attach an attachment of sorts to a mailable, which is what I have been using at the suggestions of others until the notifiables get a few more things worked on with them.
But I am stuck as to whether or not it's possible to attach a generated PDF to a mailable.
At the moment, I send the PDFs to generate through a route:
Route::get('/shipments/download/{shipment}','ShipmentController#downloadPDF');
Which is then sent to here in the controller:
public function downloadPDF(Shipment $shipment){
$shipment_details = $shipment->shipment_details;
$pdf = PDF::loadView('shipments.pdf', compact('shipment','shipment_details'))
->setOption('images', true)
->setOption('enable-javascript', true)
->setOption('javascript-delay', 100);
return $pdf->download('shipment'.$shipment->url_string.'.pdf');
}
My mailable is defined as such:
<?php
namespace App\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Queue\ShouldQueue;
use App\Shipment;
class newFreightBill extends Mailable
{
use Queueable, SerializesModels;
/**
* Create a new message instance.
*
* #return void
*/
public $shipment;
public function __construct(Shipment $shipment)
{
$this->shipment = $shipment;
$this->attachmentURL = $shipment->url_string;
$this->proNumber = $shipment->pro_number;
}
/**
* Build the message.
*
* #return $this
*/
public function build()
{
return $this->from('billing#cmxtrucking.com')
->subject('New Freight Bill Created - '. $this->proNumber)
->view('emails.shipments.created');
}
}
So, is it possible to attach a generated PDF?
You can use attach to send files via mail. For example:-
public function build()
{
return $this->from('billing#cmxtrucking.com')
->subject('New Freight Bill Created - '. $this->proNumber)
->view('emails.shipments.created')
->attach($your_pdf_file_path_goes_here);
}
This worked for me while i was trying. Hope it works for you too.
Here i am using laravel package "vsmoraes/laravel-pdf" for pdf generation
steps :
1) render view with dynamic data
2) load this view to pdf
3) attach pdf data to the mail
$html = view('pdf',compact('result','score'))->render();
$pdf = PDF::Load($html);
\Mail::send('mail.analysis',['user'=>$data],function($message) use($pdf,$user){
$message->to($user->email)->subject("Page Speed Aanlysis Generated");
$message->attachData($pdf->output(),'pdf_name.pdf');
});

laravel 5.4 embed image in mail

I have just upgraded my 5.2 install of laravel to 5.3 and then to 5.4 following the official upgrading methods.
I am now trying to use one of the new features, to create a markdown formated email.
According to the documentation found at: https://laravel.com/docs/5.4/mail#view-data
To embed an inline image, use the embed method on the $message
variable within your email template. Laravel automatically makes the
$message variable available to all of your email templates, so you
don't need to worry about passing it in manually:
However, this:
<img src="{{ $message->embed(public_path().'/img/official_logo.png') }}">
will produce the following error:
Undefined variable: message
Am I missing something? Or is there something undocumented in the upgrading guides?
Later edit:
I am calling the email function with:
\Mail::to($user)->send(new WelcomeCandidate($user, $request->input('password')));
And WelcomeCandidate looks like:
<?php
namespace App\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Queue\ShouldQueue;
use App\Models\User;
class WelcomeCandidate extends Mailable
{
use Queueable, SerializesModels;
public $user;
public $password;
/**
* Create a new message instance.
*
* #return void
*/
public function __construct(User $user, $password)
{
//
$this->user = $user;
$this->password = $password;
}
/**
* Build the message.
*
* #return $this
*/
public function build()
{
$this->subject('Welcome!');
return $this->markdown('emails.welcome-candidate');
}
}
It seems that the older $message->embed doesn't work nicely with Markdown emails. Like you mentioned in the comments it seems broken since 5.4
But you could just try it like this inside your markdown email:
This is your logo
![Some option text][logo]
[logo]: {{asset('/img/official_logo.png')}} "Logo"
Like shown here:
https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet#images
Asset function reference: https://laravel.com/docs/5.4/helpers#method-asset
Try this:
<img src="data:image/png;base64,{{base64_encode(file_get_contents(resource_path('img/email/logo.png')))}}" alt="">
or
![](data:image/png;base64,{{base64_encode(file_get_contents(resource_path('img/email/logo.png')))}})
You can also use this useful package
https://github.com/eduardokum/laravel-mail-auto-embed
Taken from the readme
Its use is very simple, you write your markdown normally:
#component('mail::message')
# Order Shipped
Your order has been shipped!
#component('mail::button', ['url' => $url])
View Order
#endcomponent
Purchased product:
![product](https://example.com/products/product-1.png)
Thanks,<br>
{{ config('app.name') }}
#endcomponent
When sending, it will replace the link that would normally be generated:
<img src="https://example.com/products/product-1.png">
by an embedded inline attachment of the image:
<img src="cid:3991f143cf1a86257f8671883736613c#Swift.generated">
Solved my issue!
<img src="{{ $message->embed(base_path() . '/img/logo.png') }}" />
Controller:
\Mail::send(['html' =>'mail'],
array(
'name' => $r->name,
'email' => $r->email,
'user_message' => $r->message,
// 'telephone'=>$r->telephone,
// 'subject'=>$r->subject
), function($message) use ($r) {
$message->to('abc#gmail.com')->subject('Contact Form || abc.com');
$message->from($r->email);
// ->setBody($r->user_message); // assuming text/plain
});
If you are in localhost , you can use public_path instead of base_path function
I just encountered the same issue and found a solution.
Before rendering images you have to create a symbolic link from "public/storage" to "storage/app/public" using this command:
php artisan storage:link
In "storage/app/public" you should have a folder "images"
Now you can render this code in your markdown.blade.php:
!['alt_tag']({{Storage::url('/images/your_image.png')}})
Second option is similar:
!['alt_text']({{Storage::url($comment->user->image->path)}})
Both work fine
You could try the following:
class WelcomeCandidate extends Mailable
{
use Queueable, SerializesModels;
public $message;
public function __construct(User $user)
{
$this->user = $user;
$this->message = (object) array('image' => '/path/to/file');
}
}
The below solution works for me.
<img src="{{ $message->embed(asset('img/logo.png')) }}"/>
In .env file.
For local: APP_URL=http://localhost/project_name
For Production: APP_URL=https://www.example.com
Reference: https://laravel.com/docs/7.x/mail#inline-attachments
In backend i created endpoint for showing images. And put image that i need in resource/img. Laravel code looks like:
public function getImage($name)
{
return response()->file(base_path() . '/resources/img/' . $name . '.png');
}
Then in my html email template i created div with background-image.
<div style='background: url("https://mysite1.com/api/v1/get_image/logo")'></div>
And it's works for me.

Laravel mail Invalid view

I have a command in my code that is run daily by cron that sends emails to all new users. It used to work ok, but after I have swithched the queue driver to SQS and upgraded Laravel 5.2 to 5.3 it started throwing an error.
InvalidArgumentExceptionvendor/laravel/framework/src/Illuminate/Mail/Mailer.php:379
Invalid view.
I don't know what might cause the error, because I have not deleted the view. Also when I run the command manually it does not throw any errors.
Here is the command code:
public function handle()
{
$subscriptions = Purchase::where('created_at', '>=', Carbon::now()->subDay())
->groupBy('user_id')
->get();
$bar = $this->output->createProgressBar(count($subscriptions));
foreach ($subscriptions as $subscription) {
$user = $subscription->user;
// if ($user->is_active_customer) {
Mail::to($user)->bcc(env('BCC_RECEIPTS_EMAIL'))->send(new NeedHelp());
// }
$bar->advance();
}
$bar->finish();
$this->info("\nSuccess! " . number_format(count($subscriptions)) . ' emails were sent.');
}
Here is the NeedHelp class code (I have changed the email and sender name for this thread):
<?php
namespace App\Mail;
use App\User;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Queue\ShouldQueue;
class NeedHelp extends Mailable
{
use Queueable, SerializesModels;
/**
* Create a new message instance.
*
*/
public function __construct(){
}
/**
* Build the message.
*
* #return $this
*/
public function build()
{
return $this->subject('Need help?')
->from('default#mail.com', 'Sender')
->view('emails.need-help');
}
}
I have found the error. The reason was that I have accidentally connected two applications to the same queue, which caused them to process jobs and emails of each other which resulted in this error.

Resources