For testing purpose, I want to send raw mail via Queue.
I can send a raw mail like this:
Mail::raw('bonjour', function($message) {
$message->subject('Email de test')
->to('test#example.org');
});
But is there a way to send a raw mail via Queue (without creating a View nor Mailable)?
You can use dispatch helper function to push Closure onto the Laravel job queue:
dispatch(function () use ($name) {
Mail::raw('bonjour ' . $name, function($message) {
$message->subject('Email de test')
->to('test#example.org');
});
});
I searched the past days without any outcome to accomplish exact this: a raw mail that can be queued.
Unfortunately I didn't found a solution without using Mailables and Views.
I assume you have the same reason as me: You want to send a 100% dynamically generated Mail from a string.
My solution was:
creating a view that only contains one variable: <?php echo $content;
create a mailable, passing the content to the constructor and set it to $this->content
copy everything inside the old mail-closure into the build-method of the mailable and replace every $message-> with $this
queue it ;)
public function send(Request $request) {
$to = "test#example.org";
$subject = "email de test";
$content = "bonjour";
Mail::send(new RawMailable($to, $subject, $content));
}
view (/ressources/view/emails/raw.blade.php):
{!! $content !!}
mailable:
<?php
namespace App\Mail;
use Dingo\Api\Http\Request;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
class RawMailable extends Mailable
{
use Queueable, SerializesModels, ShouldQueue;
private $mailTo;
private $mailSubject;
// the values that shouldnt appear in the mail should be private
public $content;
// public properties are accessible from the view
/**
* Create a new message instance.
*
* #param LayoutMailRawRequest $request
*/
public function __construct($to, $subject, $content)
{
$this->content = $content;
$this->mailSubject = $subject;
$this->mailTo = $to;
}
/**
* Build the message.
*
* #throws \Exception
*/
public function build()
{
$this->view('emails.raw');
$this->subject($this->mailSubject)
->to($this->mailTo);
}
}
Leave the paramaters view and variables with an empty array each one and add the line $mail->setBody($html, 'text/html') inside the function.
Mail::queueOn(
'name_of_queue',
[],
[],
function($mail) use ($destination_email, $destination_name, $html) {
$mail->to($destination_email, $destination_name);
$mail->subject($subject);
$mail->setBody($html, 'text/html');
}
);
Related
I want to send emails to all of the users in my application. I created a separate sample project where the only function is one to add/create new users together with their email and name. I want to email each of my existing users whenever there is a new one who signed up. Like a "Hello, we have a new member!" message.
Controller
public function store()
{
$customer = Customer::create($this->validatedData());
foreach ($customer as $customers) {
Mail::to($customers->email)->send(new WelcomeMail());
}
return redirect('/customers');
}
Here your code is correct but not completely
So I have modified it
Now you need to create one Job file using
php artisan make:job WelcomeMessage and then run
php artisan migrate
to send the mail
use App\Job\WelcomeMessage;
public function store()
{
$customer = Customer::create($this->validatedData());
if ($customer) {
$allUser = Customer::where('id', '!=', $customer->id)->get();
$html = "Your html file with mail content";
$sub = "Welcome Mail";
foreach($allUser as $allUsers){
Mail::to($allUsers->email)->send(new WelcomeMessage($html,$sub));
}
}
return redirect('/customers');
}
If you run this command php artisan make:job WelcomeMessage then it will create the page in the app\Job folder. Then paste the below code on that page.
<?php
namespace App\Emails;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Queue\ShouldQueue;
class UserVerificationMail extends Mailable
{
use Queueable, SerializesModels;
public $subject;
public $file;
/**
* Create a new message instance.
*
* #return void
*/
public function __construct($file,$subject)
{
$this->subject = $subject;
$this->file = $file;
}
/**
* Build the message.
*
* #return $this
*/
public function build()
{
return $this->from(env('MAIL_FROM_ADDRESS'), env('APP_NAME'))
->subject($this->subject)
->markdown($this->file);
}
}
and then run php artisan queue:listen
This will work
Thank You
I have been stuck in this for quite a while now. I am trying to extract messageID of an email through a callback function and store in DB for later use. I simulated the same conditions in a gmail based server and it works. But I don't think the email server has to do with anything. Here is my mailable class where I try to extract the messageID:
<?php
namespace App\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
use App\EmailLog;
use App\EmailLogDetail;
class GenericSendEmailMailable extends Mailable
{
//use Queueable, SerializesModels;
/**
* Create a new message instance.
*
* #return void
*/
private $applicationTemplate;
public $subject;
private $data;
private $emailLogId;
public function __construct(String $applicationTemplate,Array $data,String $subject, $emailLogId)
{
//
$this->applicationTemplate = $applicationTemplate;
$this->data = $data;
$this->subject = $subject;
$this->emailLogId = $emailLogId;
}
/**
* Build the message.
*
* #return $this
*/
public function build()
{
$emailLogId = $this->emailLogId;
$view = $this->applicationTemplate;
$data = $this->data;
$subject = $this->subject;
return $this->subject($subject)
->view($view,$data)
->withSwiftMessage(function ($message) use ($emailLogId){
$emailLog = EmailLog::where('id', $emailLogId)->first();
if(isset($emailLog->email_log_details)){
foreach($emailLog->email_log_details as $emailLogDetail){
$emailLogDetail->message_id = $message->getId();
$emailLogDetail->save();
}
}
});
}
}
Here, the $message->getId(); should be working fine but its not cause when I send mail and check the DB, the message Id is not stored. By the way, the email send operation is dispatched as a job. Any ideas as to why this is not working?
If anybody is interested in the future, this was due to the heavy processing inside the job. I was facing an execution timeout. I did two things, first I did any trivial processing before dispatching the job rather than in the job itself. And finally I increased the timeout by adding
public $timeout = 300;
in the job class. Also, I increased the "retry_after" in the driver I was using to just a bit more than the actual timeout (320 in my case).
The best way to identify the problem for a queue is to observe the worker.log file and determine whether any jobs failed or not. If failed, the reason (or exception) can be caught by creating a failed_jobs table in your database.
I have a Symfony project which (very simplified) looks like this:
Controller/MyToolController.php
namespace App\Controller;
use App\Services\ToolsService;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
class MyToolController extends AbstractController
{
private $toolsService;
/**
* #param ToolsService|null $toolsService
*/
public function __construct(ToolsService $toolsService = null) {
$this->toolsService = $toolsService;
}
public function run() {
// some more code here...
$mailContent = $this->render('site/mail.html.twig', $data)->getContent();
$this->toolsService->sendMail($from, $to, $bcc, $mailContent, $subject);
// if I remove the following line, no emails are sent out!
return $this->render('site/thankyou.html.twig', $data);
}
}
Services/MyToolService.php
namespace App\Services;
class ToolsService
{
/** #var \Swift_Mailer */
private $mailer;
/**
* #param \Swift_Mailer $mailer
*/
public function __construct(\Swift_Mailer $mailer)
{
$this->mailer = $mailer;
}
public function sendMail($from, $to, $bcc, $body, $subject) {
$mail = ( new \Swift_Message() )
->setSubject($subject)
->setFrom($from)
->setTo($to)
->setBcc($bcc)
->addPart($body, 'text/html');
$res = $this->mailer->send($mail);
$this->logger->info('Email sent');
return $res;
}
}
If you look at MyToolController.php you see that I call a service which sends the email.
If I return a Response object in my run() function, everything goes well - but if I omit this, nothing is sent. Same if I send multiple emails in a loop and I run into a timeout.
Strangely $mailer->send() is called in any case - and it returns 1 - and I see an entry in the log I am writing in the sendmail() function. But no email leaves the server.
This is my SwiftMailer configuration:
swiftmailer:
url: '%env(MAILER_URL)%'
spool: { type: 'memory' }
Your mails are being spooled in memory, which means:
When you use spooling to store the emails to memory, they will get sent right before the kernel terminates. This means the email only gets sent if the whole request got executed without any unhandled exception or any errors.
If you do not return a Response object from your controller, there will be an unhandled exception, the whole request won't be executed, and the mails will never be sent.
Controllers need to return a Symfony\Component\HttpFoundation\Response so the request can be handled normally. If you want to return an empty response, you can simply do:
return new Response();
I am trying to pass the value from the request, which is stored as an array, to an email in html format before sending.
$data = array('email' => $request->get('email'), 'name' => $request->get('name'));
Mail::send('emails.email', ['data' => $data], function ($message) use ($data) {
$message->subject('Hello world!');
$message->to($data['email'], $data['name']);
});
This is my email html format file in email.blade.php
<h2>HELLO YOU HAVE A NEW EVENT!</h2>
<h3>TO {{$name}}</h3>
<h4>See more details .... Events</h4>
But it appears that the html file does not receive the variable ($name) that was sent
How to pass data (in array format) to email html?
I tried sending without the $ name variable. It appears that there is no problem. Everything goes smoothly But I really need to use variables Please help me
I can use $name if use this code
$data['name'] = "Guest";
Mail::send('emails.email', $data, function ($message) {
$message->to('email#gmail.com', 'name')
->subject('topic');
});
Why?
Mail::send('emails.email', ['data' => $data], function ($message) use ($data) {
$message->subject('Hello world!');
$message->to($data['email'], $data['name']);
});
You're passing a data variable, not name (['data' => $data]). So get the name from that array:
<h2>HELLO YOU HAVE A NEW EVENT!</h2>
<h3>TO {{ $data['name'] }}</h3>
Or pass the $data variable directly so that you will have access to all its values as separate variables:
Mail::send('emails.email', $data, function ($message) use ($data) {
$message->subject('Hello world!');
$message->to($data['email'], $data['name']);
});
first you have to declare the variable in your mail class like this:
<?php
namespace App\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Queue\ShouldQueue;
class MailForm extends Mailable
{
use Queueable, SerializesModels;
public $fullname;
/**
* Create a new message instance.
*
* #return void
*/
public function __construct($fullname)
{
//
$this->fullname = $fullname;
}
/**
* Build the message.
*
* #return $this
*/
public function build()
{
return $this->view('sendmail');
}
}
then in your view you can now call the variable
{{ $fullname }}
dont forget to call the mail class and mail facades in your controller like:
use App\Mail\MailForm;
use Illuminate\Support\Facades\Mail;
I have created an app using Laravel and uploaded it to the live server (shared hosting). I have programmed it such that emails are sent to clients together with email attachments generated via DOMPDF. The problem is that I receive a phishing error in Gmail inbox concerning the attachment. When I remove the image from the attachment the error disappears. Seems like am not inserting the image properly in the blade file. Please assist me on how to add the image via the controller then parse it to the view (that is sent as an attachment)?
~ Regards
PDF Controller that loads the PDF file
class PDFController extends Controller
{
//Loads the PDF document
public function getPDF(){
$pdf = \PDF::loadView('pdf.customer', ['format' => 'A5-L']);
return $pdf->stream('customer.pdf')->header('Content-Type','application/pdf');
}
}
Email blade
<div class="logo pull-right">
<?php $image_path = '/img/logo.png'; ?>
</div>
PagesController that sends the email
$pdf = PDF::loadView('pdf.customer', $data);
Mail::send('emails.feedback', $data, function($message) use ($data, $pdf){
$message->from('info#*************');
$message->to($data['email']);
$message->subject('Feedback');
//Attach output from PDF doc, customer.pdf is the name of the file attached
$message->attachData($pdf->output(),'customer.pdf');
});
If you are using Laravel inbuilt mailer then, Follow below structure
Crete mail class using
php artisan make:mail MailFileName
MailFileName.php
<?php
namespace App\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Queue\ShouldQueue;
class MailFileName 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('from_email' ,'Title')->view('emails.email_ blade_file')->with(['data' => $this->data])->subject($subject)->attach($this->data['attachment_url']);
}
}
In view you are passing $data variable so you can use all this variable just like normal blade file.
View File - resource/views/emails/email_ blade_file.blade.php
In your controller where you want to call mail function add,
SomeController.php
use use App\Mail\MailFileName;
Inside function,
$data['subject'] = 'New message from';
$data['data'] = ['your data'];
Mail::to($to_email)->send(new MailFileName($data));