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);
Related
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.
We are running on Laravel 6 and we have got the following problem. A job we execute, that counts the number of impressions and clics of certain images triggers the following error, due to a high number of calls to the function:
method_exists(): The script tried to execute a method or access a
property of an incomplete object. Please ensure that the class
definition "App\Jobs\RegisterHouseLog" of the object you are trying to
operate on was loaded before unserialize() gets called or provide an
autoloader to load the class definition
We already increased the number of tries so it executes after sometime, so it's not the actual problem, but it sends an error to our error logs (Slack Channel) and causes a lot of "spam".
I was trying to fix the above error but I wasn't able to fix it, so at least I tried to "mute" the notification through an "failed job exception" but still to it fails.
The best would be to resolve the actual problem, the second best would be to mute it.
Anyone could help?
The Job:
<?php
namespace App\Jobs;
use App\HouseLog;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Log;
use Exception;
class RegisterHouseLog implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public $tries = 20;
public $house_id;
public $user_id;
public $date;
public $type;
/**
* Create a new job instance.
*
* #return void
*/
public function __construct($house_id,$user_id,$type, $date)
{
$this->house_id = $house_id;
$this->user_id = $user_id;
$this->type = $type;
$this->date = $date;
}
/**
* Execute the job.
*
* #return void
*/
public function handle()
{
$log = new HouseLog();
$log->user_id = $this->user_id;
$log->house_id = $this->house_id;
$log->type = $this->type;
$log->date = $this->date;
$log->save();
}
public function failed(Exception $exception)
{
Log::critical('Failed Register House');
}
}
And the call:
<?php
namespace App\Http\Controllers\api;
use App\HouseLog;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\Jobs\RegisterHouseLog;
use Carbon\Carbon;
class HouseLogController extends Controller
{
public function registerLog(Request $request)
{
$date = Carbon::now();
RegisterHouseLog::dispatch($request->house_id, $request->user_id, $request->type, $date);
}
}
Thanks a lot!!
This error is likely due to the job dispatcher not being able to resolve \App\Jobs\RegisterHouseLog when it pulls from the job queue to kick off a job.
Try clearing the class loader cache:
artisan cache:clear
Also try restarting your job dispatcher process.
artisan queue:restart
It may not be the best solution, but you could also fix this by removing implements ShouldQueue from your job class definition; it would make the job kick off right away without going through the queue.
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);
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!
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).