BindingResolutionException when sending mails in Lumen Jobs - php

I have no problem sending synchronous mails, but the ones that get executed on a queue using Mail::queue throw the next error:
Illuminate\Contracts\Container\BindingResolutionException: Target [Swift_Transport] is not instantiable while building [Illuminate\Mail\Mailer, Swift_Mailer]. in /var/www/myapp.dev/vendor/illuminate/container/Container.php:804
Everything is configured correctly as emails are being sent when I do it synchronously

After having so much trouble with sending emails inside of Lumen Jobs, I encapsulated the email sending in a Job which works with mailables like this:
MailDispatcher.php
<?php
namespace App\Jobs;
use Illuminate\Contracts\Mail\Mailable;
use Illuminate\Support\Facades\Mail;
class MailDispatcher extends Job {
public $mail;
public function __construct(Mailable $mail) {
$this->mail = $mail;
}
public function handle() {
Mail::send($this->mail);
}
}
Then when I want to queue a mail...
$mail = new MyMailableMail($user);
dispatch(new MailDispatcher($mail));
And it works correctly

Related

laravel-notification-channels/apn either isn't sending notification or my iPhone isn't receiving the notification

I am using this package to try and send apn notifications in my Laravel app. However, I have followed the documentation on the main page, and when I try to send an apn notification, I can log on the server that the constructor and via methods are called, but I can't figure out why my notification either isn't being sent or isn't being received. My logs have no info from the package either.
How do I troubleshoot this? What am I missing?
MyNotification.php
<?php
namespace App\Notifications;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
use Illuminate\Support\Facades\Log;
use NotificationChannels\Apn\ApnChannel;
use NotificationChannels\Apn\ApnMessage;
class MyNotification extends Notification
{
use Queueable;
public function __construct()
{
Log::debug('MyNotification constructor called');
}
public function via($notifiable)
{
Log::debug('MyNotification via called');
return [ApnChannel::class];
}
public function toApn($notifiable)
{
Log::debug('MyNotification toApn called');
return ApnMessage::create()
->badge(1)
->title('My title')
->body('My body');
}
public function routeNotificationForApn($notifiable)
{
Log::debug('MyNotification routeNotificationForApn called');
return $notifiable->token;
}
}
usage code in MyController.php
public function sendNotification(MyModel $model)
{
// authorization checks here...
$devices = Device::where('user_id', $model->user_id)->get();
Notification::send($devices, new MyNotification());
return response()->json(null, 200);
}
Here is what my broadcasting.php and .env files look like:
Your notification uses Queueable so your notifications are only send if your queue is correctly setup.
You can run your queue locally by running
$ php artisan queue:work
On your console you would also get a feedback if your queued job (your notification) has been submitted successfully (not if it is delivered successfully).
This is also highlighted inside the Laravel docs
Before queueing notifications you should configure your queue and start a worker.
If you need a queue that is probably sth. you need to decide as only you know how much load is the application, how many notifications should be sent.
Taken from the docs:
Sending notifications can take time, especially if the channel needs to make an external API call to deliver the notification. To speed up your application's response time, let your notification be queued by adding the ShouldQueue interface and Queueable trait to your class.
Personal opinion: Make it work without a queue, f. ex. locally, and then add a queue.
If you configured to run your queue with Redis, I would highly recommend to use Laravel Horizon to monitor the jobs in your queue.
Tips for using APN
Configure the APN service correctly in config/broadcasting.php - see Github docs.
The problem was that the function routeNotificationForApn() belongs in the notifiable model (in my instance, Device), not in the MyNotification class.
Removing the use Queueable; is required as well if you don't have a queue set up.

Laravel mailable subject not working if I queue the mailable

I'm working with laravel 7.0 and for some reason when I write subject in my build method of a mailable and queue it by calling the queue method of the Mail facade the subject isn't changing, it is taking the mailable classname and setting it as the subject. If I hard code the $subject variable in the mailable class it works and if I don't queue it then the subject gets set. Anybody knows how to solve this? I'm using database driver to handle the queue.
Mailable build method
public function build()
{
return $this->subject(config('app.name') . ' OTP')
->markdown('emails.otp');
}
How I'm queuing up the mail to send
\Illuminate\Support\Facades\Mail::to($this->user->email)
->queue(new \App\Mail\Otp($generatedOtp));

How can I send Email in Laravel command instead of controller

I'm working on a project using Laravel where I want to be able to send an email when it is scheduled to send.
So far I've only found solutions to send a mail through a Route but I want to be able to send the mail when cron activates my self made command. I've already made a view of the mail that should be sent and made a page sendMail with php artisan make:mail sendMail that returns the mail view.
sendMail.php
<?php
namespace App\Mail;
use Illuminate\Support\Facades\DB;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
class sendMail extends Mailable
{
use Queueable, SerializesModels;
/**
* Create a new message instance.
*
* #return void
*/
public function __construct()
{
$winnersposts = DB::select('select post_id from winners group by post_id');
$posts = DB::select('select * from posts ');
$this->winnerposts =$winnersposts;
$this->posts=$posts;
}
/**
* Build the message.
*
* #return $this
*/
public function build()
{
return $this ->from('ivanrompa#gmail.com')
->view('emails.template');
}
}
mailAdmin.php
public function handle()
{
}
My command handle is still empty but I previously tried to implement to logic from my controller above in my command but it didn't work.
Am I writing the wrong code and is that the reason it just doesn't work or should I approach it in a different way? It is maybe good to know that I am still learning Laravel and I have never sent an email before through code. Any tips or solutions are welcome.
Assuming you have set your email configuration correctly.
Add this in your mailAdmin.php
use Mail;
use App\Mail\sendMail
public function handle()
{
Mail::to('recipient#gmail.com')->send(new sendMail);
}
Then run the command

Laravel queue stalls when used with sentry

i have a working project written in laravel, i've integrated Sentry to monitor for errors, i followed instructions on their site, basically just
composer require sentry/sentry-laravel
and in my App/Exceptions/Handler.php
if (app()->bound('sentry') && $this->shouldReport($exception)) {
app('sentry')->captureException($exception);
}
Now this works fine, i see errors in sentry.
But at the other end of the app wherever i use queue, for example i have "forgot password" notification and it implements ShouldQueue class, practically:
<?php
namespace App\Notifications\Auth;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
class PasswordResetRequest extends Notification implements ShouldQueue
{
use Queueable;
protected $token;
public function __construct($token)
{
$this->token = $token;
}
public function via($notifiable)
{
return ['mail'];
}
public function toMail($notifiable)
{
$url = url('/password/find/'.$this->token);
return (new MailMessage)
->line('You are receiving this email because we received a password reset request for your account.')
->action('Reset Password', url($url))
->line('If you did not request a password reset, no further action is required.');
}
}
And when triggered works as expected, i have a new record in jobs table (i have database as queue driver)
now when i start my worker
php artisan queue:work
it stalls it works last job over and over
there is no mail sent or received...
By the way this is only when i have reporting in sentry, if i remove those lines in App/Exceptions/Handler.php in report() method it's all good, also if i remove queue from notification it works, only the combinatio of sentry error reporting and notification queuing is making me a big problem.
Unfortunately, Sentry-laravel doesn't work with queues.
Please, see this issue on their GitHub repo to get more info about it:
https://github.com/getsentry/sentry-laravel/issues/18
There is another issue (open) where they are trying to fix it:
https://github.com/getsentry/sentry-laravel/pull/228
If you really need to put these logs on a queue now you should use https://github.com/twineis/raven-php.

Queueing mails in Laravel

I would like to send mail to user after creating account on my website and I would like to use queues to send them. I'm using PHP Laravel framework.
My controller handles the request after clicking on "Create account":
class LoginController extends Controller
{
...
public function register(Request $request) {
...
$mail = (new RegisterRequest($user))->onConnection("database")->onQueue("emailsQueue");
Mail::queue($mail);
...
}
}
Then I have this RegisterRequest (mailable) class:
class RegisterRequest extends Mailable
{
use Queueable, SerializesModels;
protected $user;
public function __construct($user)
{
$this->user = $user;
}
public function build()
{
return $this->from('user#example.com')
->to($this->user->email)
->subject("Confirm your Email Address")
->view('emails.register.request')
->with("registration_token", $this->user->registration_token);
}
}
As you can see, I am using relational database to store jobs. And really, after calling LoginController's register method, a job is saved to database. But it can't be processed. I also start php artisan queue:work but nothing is done with jobs in database. Any help?
EDIT:
So I just found out that picking jobs from queue is done by SQL selecting the 'default' queue name. But I'm sending mails to queue 'emailsQueue'. So I'm now running Queue Worker like this: php artisan queue:work --queue=emailsQueue and everything's working fine for now. But how can I pick jobs from every queue in database? It's probably not the best attempt, right? It wouldn't make any sense to have named queues, right? But let's say I have one queue for processing register account requests, another queue for changing password requests and so on... So I think it does make sense to process every queue. So how can I do this? Can it be done just by listing the queues like this?
php artisan queue:work --queue=registerAccountEmailQueue,changePasswordEmailQueue...
What exactly does running php artisan queue:work? I thought it's the command to run all queues.
Use queue driver database.
In controller you should write
$this->dispatch(new SendNotifyMail($data));
This will pass your $data to queue. here SendNotifyMail is used as Job Class. So you should also use this in Controller like use App\Jobs\SendNotifyMail;.
Then create a file in Folder Jobs, named SendNotifyMail
<?php
namespace App\Jobs;
use App\Jobs\Job;
use DB;
use Mail;
use Artisan;
use Illuminate\Contracts\Mail\Mailer;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
class SendNotifyMail extends Job implements ShouldQueue
{
use InteractsWithQueue, SerializesModels;
public $timeout = 300; // default is 60sec. You may overwrite like this
protected $data;
public function __construct($data)
{
$this->data = $data;
}
public function handle(Mailer $mailer)
{
$data = $this->data; // retrieve your passed data to variable
// your mail code here
}
}
In your command you need to write
php artisan queue:listen
or
php artisan queue:work
Then execute the code.

Categories