Get Message-ID from Swift Mailer callback function Laravel Error - php

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.

Related

Laravel: Cannot access empty property when trying to send an email

I'm trying to send an email using laravel however I keep getting the cannot access empty property error whenever I run my code.
I've done my research on the error and it seems to be usually caused by using a $ before the property name, example $this->$username instead of $this->username. However, that isn't the case in my code.
I can't really tell what's causing it nor do I have great experience in Laravel
Here's my mailable class:
<?php
namespace App\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Queue\ShouldQueue;
class VerificationMail 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()
{
$data2 = ['companyName' => $this->data['name'], 'verificationCode' => $this->data['verificationCode']];
return $this->from('noreply#REMOVED.com')
->$this->view('emails.verification', $data2);
}
}
My view is saved in resources/views/emails/verification.blade.php
I saw also that this error can sometimes be caused by using $message as variable name inside the views, however that isn't the case with me. I tried loading the view with a normal route without any mail sending involved and it loaded normally.
Can anyone spot it? Thanks.
You have error here:
return $this->from('noreply#REMOVED.com')
->$this->view('emails.verification', $data2);
Use following instead: (remove second $this->)
return $this->from('noreply#REMOVED.com')
->view('emails.verification', $data2);

laravel mail attach() method returns error about null argument

Hello, I'm making a mail service in laravel, that supports attachment upload, when the user send me the file, I store it in a Amazon S3 driver for further attachment.
Here's my Mail class witch I send the mail object with the copies of email and attachments.
<?php
namespace App\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Storage;
use Illuminate\Contracts\Queue\ShouldQueue;
class Mail extends Mailable
{
use Queueable, SerializesModels;
public $email;
public $attachments;
public $copies;
/**
* Create a new message instance.
*
* #return void
*/
public function __construct($email, $copies = [], $attachments = [])
{
$this->email = $email;
$this->copies = $copies;
$this->attachments = $attachments;
}
/**
* Build the message.
*
* #return $this
*/
public function build()
{
$m = $this->from($this->email->sender->email, $this->email->sender->name)
->replyTo($this->email->sender->email, $this->email->sender->name)
->subject($this->email->subject);
foreach ($this->copies as $copy) {
if ($copy->type == 'CC') {
$m->cc($copy->destiny->email);
} else {
$m->bcc($copy->destiny->email);
}
}
if (!empty($this->attachments)) {
foreach ($this->attachments as $attachment) {
$attachmentParameters = [
"as" => $attachment->name,
"mime" => $attachment->mime
];
$m->attach(Storage::disk('s3Attachments')->url($attachment->path), $attachmentParameters);
}
}
return $m->view('emails.text-plain');
}
}
I've already used the dd(Storage::disk('s3Attachments')->url($attachment->path)) and confirmed that it is a string with the full path of the file like the documentation asks.
To add attachments to an email, use the attach method within the
mailable class' build method. The attach method accepts the full path
to the file as its first argument:
Then When I run the code, it brings this error:
[2018-05-05 20:58:52] testing.ERROR: Type error: Argument 2 passed to Illuminate\Mail\Message::attach() must be of the type array, null given, called in /home/lefel/Sites/happymail/vendor/laravel/framework/src/Illuminate/Mail/Mailable.php on line 311
I've tried using attach(), with just one argument:
$m->attach(Storage::disk('s3Attachments')->url($attachment->path));
But Same Error, I'm Using Laravel 5.5 with Amazon SES Driver, and already confirmed that I installed the following dependencies in my package.json:
composer require guzzlehttp/guzzle
"aws/aws-sdk-php": "~3.0"
I've searched the web and didn't find the solution, I need Help Please.
Regards.
I have just faced the exact same issue.
The problem is that you override the $attachments property.
Use another name for this variable and it will work!

Laravel/Lumen | Failing to dispatch event

This is my first time using events in Laravel/Lumen.
I am actually using Lumen and I am trying to dispatch an instance of Mailable when a new user signs up in order to send an email in the background.
I believe I have set it up right, but I keep getting this error...
Type error: Argument 1 passed to Illuminate\Mail\Mailable::queue() must implement interface Illuminate\Contracts\Queue\Factory, instance of Illuminate\Queue\DatabaseQueue given
I can't actually see within the error message itself where the issue is coming from e.g. there is no line numbers.
However, this is my code...
AuthenticationContoller.php
$this->dispatch(new NewUser($user));
NewUser.php
<?php
namespace App\Mail;
use App\Models\User;
use Illuminate\Mail\Mailable;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Queue\ShouldQueue;
class NewUser extends Mailable implements ShouldQueue
{
use Queueable, SerializesModels;
protected $user;
public function __construct(User $user)
{
$this->user = $user;
}
/**
* Build the message.
*
* #return $this
*/
public function build()
{
return $this->view('test')->to('test#test.com', 'Test')
->from('test#test.com', 'test')->replyTo('test#test.com', 'test')
->subject('Welcome to the blog!');
}
}
I ran into the same issue. It seems like Lumen and Illuminate/Mailer don't work together all that well.
However I found quite an easy fix in a Github thread.
Basically you just have to create a new service provider in your app/Providers directory.
MailServiceprovider.php
<?php
namespace App\Providers;
use Illuminate\Mail\Mailer;
use Illuminate\Mail\MailServiceProvider as BaseProvider;
class MailServiceProvider extends BaseProvider
{
/**
* Register the Illuminate mailer instance.
*
* #return void
*/
protected function registerIlluminateMailer()
{
$this->app->singleton('mailer', function ($app) {
$config = $app->make('config')->get('mail');
// Once we have create the mailer instance, we will set a container instance
// on the mailer. This allows us to resolve mailer classes via containers
// for maximum testability on said classes instead of passing Closures.
$mailer = new Mailer(
$app['view'], $app['swift.mailer'], $app['events']
);
// The trick
$mailer->setQueue($app['queue']);
// Next we will set all of the global addresses on this mailer, which allows
// for easy unification of all "from" addresses as well as easy debugging
// of sent messages since they get be sent into a single email address.
foreach (['from', 'reply_to', 'to'] as $type) {
$this->setGlobalAddress($mailer, $config, $type);
}
return $mailer;
});
$this->app->configure('mail');
$this->app->alias('mailer', \Illuminate\Contracts\Mail\Mailer::class);
}
}
And then you just have to register this service provider in your bootstrap/app.php instead of the default one by adding the following line:
$app->register(\App\Providers\MailServiceProvider::class);

Send raw mail via queue Laravel

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');
}
);

Laravel 5.4 unable to set email from option

I am using global from option in config/mail.php as mentioned in the documentation to use the same from address for all of my emails being sent. This works as expected. However, when I attempt to explicitly set a from address within the build function of a Mailable class, the global address is still used. Is there something I could be missing, all of this seems to come straight from the documentation for 5.4. My Mailable class is as follows (there is definitely a value in the $this->email property as it is displayed when echoed):
namespace App\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Queue\ShouldQueue;
class ContactMessage extends Mailable
{
use Queueable, SerializesModels;
public $user_email;
public $user_message;
/**
* Create a new message instance.
*
* #return void
*/
public function __construct($user_email, $user_message)
{
$this->user_email = $user_email;
$this->user_message = $user_message;
}
/**
* Build the message.
*
* #return $this
*/
public function build()
{
// echo '<pre>';
// echo var_export($this->user_email, true);
// echo '<br/><br/>';
// echo var_export($this->message, true);
// die;
return $this->from($this->user_email)
->subject('Contact Message')
->view('mail.contactMessage');
}
}
Your code is correct. Thing is, setting the From header is a privileged operation in most MTA.
If you use sendmail, postfix, or other similars on a local machine you can usually set the From. However, when using an authenticated account at a third party, you usually cannot.
To change the From header with a third party, you need to either use an authenticated account that matches your From (eg with GMail), or configure the allowed From in your account (eg at AWS SES).

Categories