send multiple emails using custom job in laravel - laravel

I tried to create a job in order to send emails to all users in the database I have done everything and connected successfully with Mailtrip but still have a problem : (Failed) when implementing the command:
PHP artisan queue:work
this is my ProductEmail class:
class ProductMail extends Mailable implements ShouldQueue
{
use Queueable, SerializesModels;
public $product;
public $user;
/**
* Create a new message instance.
*
* #return void
*/
public function __construct(Product $product, User $user)
{
$this->product = $product;
$this->user = $user;
}
/**
* Build the message.
*
* #return $this
*/
public function build()
{
return $this->subject($this->product->name)
->view('email.product');
}
}
and i have created the view for it>>>>
and here the job class
class NotifyUsersForProduct implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
/**
* Create a new job instance.
*
* #return void
*/
public $product;
public function __construct(Product $product)
{
$this->$product = $product;
}
/**
* Execute the job.
*
* #return void
*/
public function handle()
{
$users = User::all();
$users->map(function(User $user){
Mail::to($user)->send(new ProductMail($this->product, $user));
});
}
}
and here i have use it
try {
$product = Product::create([
'name' => $request->input('name'),
'price' => $request->input('price'),
'quantity' => $request->input('quantity'),
'user_id' => Auth::id(),
]);
NotifyUsersForProduct::dispatch($product);
the error message:

public function __construct(Product $product)
{
$this->$product = $product;
}
This should be:
public function __construct(Product $product)
{
$this->product = $product;
}
Remove $
and also i recommend to do this but not necessary:
public function handle()
{
$users = User::all();
foreach($users as $user){
Mail::to($user)->send(new ProductMail($this->product, $user));
});
}
Hope it helps.

Related

How to add queue in sending mails in Laravel?

I already edited my .env to QUEUE_CONNECTION=database and tried to replace from send to queue. I also tried to add implements ShouldQueue to my CertificatEmail but not working. I don't know what's missing.
SendMail Controller
public function sendEmail(Request $request)
{
$users = StudentApplicants::whereIn("id", $request->ids)->get();
foreach ($users as $key => $user) {
$data = [
'fname' => $user->users->first_name,
'mname' => $user->users->middle_name,
'lname' => $user->users->last_name,
'gwa' => $user->gwa,
'sy' => $user->school_year
];
$qrcode = base64_encode(QrCode::format('svg')->color(128, 0, 0)->size(200)->errorCorrection('H')->generate($user->users->stud_num));
$pdf = app('dompdf.wrapper');
$pdf->loadView('admin.send-awardees-certificates.certificate', $data, array('qrcode' => $qrcode));
$pdf->setPaper('A4', 'landscape');
Mail::to(config('mail.notification_recipient'))->queue(new CertificateEmail($user, $pdf));
}
return response()->json(['success' => 'Send email successfully. Refresh the page']);
}
CertificateEmail from mail
class CertificateEmail extends Mailable implements ShouldQueue
{
use Queueable, SerializesModels;
public $pdf;
public $user;
/**
* Create a new message instance.
*
* #return void
*/
public function __construct($user, $pdf)
{
$this->pdf = $pdf;
$this->user = $user;
}
/**
* Build the message.
*
* #return $this
*/
public function build()
{
// return $this->view('view.name');
return $this->from(env('info#gmail.com'))
->subject('Certificate from ABC EFG')
->view('email.certificate-email')
->attachData($this->pdf->output(), 'stock_report.pdf');
}
}
Run these two queries in command
php artisan queue:table # creates a table for queued jobs
php artisan migrate # migrates the table
Then run
php artisan queue:work
In from env I think it doesn't write right please review it should be USER_EMAIL or something like that

How to add PDF attachment in queue mails In Laravel?

I was able to send an email but when I put the attachData() in the UserMail there was an error. I think because of the parameter $this->pdf that should be declared in UserEmailJob, and I don't know how to fix it.
UserEmailJob
public $details;
/**
* Create a new job instance.
*
* #return void
*/
public function __construct($details)
{
$this->details = $details;
}
/**
* Execute the job.
*
* #return void
*/
public function handle()
{
$email = new UserEmail();
Mail::to($this->details['email'])->send($email);
}
UserEmail - mail class
I'm having error with this line $this->pdf->output()
public function __construct()
{
}
/**
* Build the message.
*
* #return $this
*/
public function build()
{
return $this->from('info#gmail.com', 'Mailtrap')
->subject('Stock Report - Laravel Tutorial')
->view('emails.userEmail')
->attachData($this->pdf->output(), 'stock_report.pdf');
}
UserController
public function mailClass()
{
$users = User::all();
$data['name'] = 'Hi';
$pdf = app('dompdf.wrapper');
$pdf->loadView('cert', $data);
$pdf->setPaper('A4', 'landscape');
$details = ['email' => 'abc#gamil.com'];
UserEmailJob::dispatch($details);
return response()->json(['status' => 'success', 'message' => 'Report has been sent successfully.']);
}
Because $this->pdf is not defined in your class.
try this:
private $pdf;
public function __construct($pdf) {
$this->pdf = $pdf;
}
public function build(){
return $this->from('info#gmail.com', 'Mailtrap')
->subject('Stock Report - Laravel Tutorial')
->view('emails.userEmail')
->attach($this->pdf);
}
and in your UserController
UserEmailJob::dispatch($details, $pdf->output());
So modify it
public $details;
public $pdfStream;
/**
* Create a new job instance.
*
* #return void
*/
public function __construct($details, $pdfStream)
{
$this->details = $details;
$this->pdfStream = $pdfStream;
}
public function handle()
{
$email = new UserEmail($this->pdfStream);
Mail::to($this->details['email'])->send($email);
}
EDIT: it is probably not recommended to stream the pdf via json
UserEmailJob
public $details;
public $data;
/**
* Create a new job instance.
*
* #return void
*/
public function __construct($details, $data)
{
$this->details = $details;
$this->data = $data;
}
/**
* Execute the job.
*
* #return void
*/
public function handle()
{
$email = new UserEmail($this->data);
Mail::to($this->details['email'])->send($email);
}
UserEmail
private $data;
public function __construct($data)
{
$this->data = $data;
}
/**
* Build the message.
*
* #return $this
*/
public function build()
{
$pdf = app('dompdf.wrapper');
$pdf->loadView('cert', $this->data);
$pdf->setPaper('A4', 'landscape');
return $this->from('info#gmail.com', 'Mailtrap')
->subject('Stock Report - Laravel Tutorial')
->view('emails.userEmail')
->attachData($pdf->output(), 'stock_report.pdf');
}
UserController
public function mailClass()
{
$users = User::all();
$data['name'] = 'Hi';
$details = ['email' => 'abc#gamil.com'];
UserEmailJob::dispatch($details, $data);
return response()->json(['status' => 'success', 'message' => 'Report has been sent successfully.']);
}

Laravel - cannot send message without a sender address

I have trouble with sending multiple jobs in Laravel.
Sometimes it working all right.
Sometimes I got this message cannot send message without a sender address in failed_job table and just 1 one worked.
Sometimes both not working.
And that's in my local but on the server it not working at all.
I'm trying to clear cache, config, everything but it just not work at all.
And I don't think it because my setting on .env cause it not always got errors.
Just sometimes got errors sometimes work.
The most common error is 1 working and 1 not.
It just running 1 job and 1 job will throw fail in failed_job table
JOBS
class SendContactContentEmail implements ShouldQueue
{
use Batchable, Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public $data;
public $emails;
public $tries = 5;
/**
* Create a new job instance.
*
* #param array $_data
*/
public function __construct(
$_data
)
{
$this->data = $_data;
$this->emails = config('email.admin');
}
/**
* Execute the job.
*
* #return void
*/
public function handle()
{
$content = new ContactContentEmail($this->data);
if (!empty($this->emails)){
foreach ($this->emails as $email){
Mail::to($email)->send($content);
}
}
}
}
class SendContactEmail implements ShouldQueue
{
use Batchable, Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected $email_address;
public $tries = 5;
/**
* Create a new job instance.
*
* #param string $_email_address
*/
public function __construct(
string $_email_address
)
{
$this->email_address = $_email_address;
}
/**
* Execute the job.
*
* #return void
*/
public function handle()
{
$email = new ContactEmail();
Mail::to($this->email_address)->send($email);
}
}
Mails
class ContactContentEmail extends Mailable
{
use Queueable, SerializesModels;
protected $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->view('contact.emails.contact_content')->with([
'data' => $this->data
]);
}
}
class ContactEmail extends Mailable
{
use Queueable, SerializesModels;
/**
* Create a new message instance.
*
* #return void
*/
public function __construct()
{
}
/**
* Build the message.
*
* #return $this
*/
public function build()
{
return $this->view('contact.emails.contact');
}
}
Controller
public function send(ContactFormRequest $request){
$data = $request->validated();
dispatch(new SendContactContentEmail($data));
dispatch(new SendContactEmail($data['mail_address']));
}
Config Email
return [
'admin' => [
'kuriyama' => 'xxxx#gmail.com',
'negishi' => 'aaaa#gmail.com',
]
];
ENV
MAIL_MAILER=smtp
MAIL_HOST=smtp.gmail.com
MAIL_PORT=587
MAIL_USERNAME=contact#xxx.com.vn
MAIL_PASSWORD=xxxxxx
MAIL_ENCRYPTION=tls
MAIL_FROM_ADDRESS=xxx#xxx.com
MAIL_FROM_NAME="${APP_NAME}"
Can you call this command?
php artisan config:cache

Socialite is not working in Laravel Middleware, How can i resolve this issue?

I am using Socialite for Google Authentication, i have an middleware for check that if user exist in my local database by their google_id, it can redirect to /home page otherwise it will redirect back to Google Authentication page, while doing this i am facing issue in middle and the error is:
Client error: POST https://www.googleapis.com/oauth2/v4/token resulted in a 400 Bad Request response: { "error": "invalid_request", "error_description": "Missing required parameter: code" }
Middleware
<?php
namespace App\Http\Middleware;
//use Socialite;
use App\GmailAccount;
use Closure;
use Laravel\Socialite\Facades\Socialite;
use Illuminate\Support\Facades\Auth;
class GoogleAuth
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
$user = Socialite::driver('google')->stateless()->user();
$finduser = GmailAccount::where('google_id', $user->id)->first();
if($finduser){
return $next($request);
}
else{
return route('/logingoogle');
}
}
}
Routes
Route::group(['middleware' => 'App\Http\Middleware\GoogleAuth'], function()
{
Route::get('/home', 'HomeController#index')->name('home');
});
Route::get('/logingoogle', 'GoogleController#google_login');
Route::get('auth/google', 'GoogleController#redirectToGoogle');
Route::get('auth/google/callback', 'GoogleController#handleGoogleCallback');
HomeController
class HomeController extends Controller
{
/**
* Create a new controller instance.
*
* #return void
*/
public function __construct()
{
$this->middleware('auth');
$this->middleware('googleauth');
}
/**
* Show the application dashboard.
*
* #return \Illuminate\Contracts\Support\Renderable
*/
public function index()
{
$user_id=Auth::user()->id;
$user_messages=DB::table('user_message')
->join('messages', 'user_message.message_id', '=', 'messages.id')
->where([
'user_message.user_id' => $user_id,
'user_message.placeholder' => 'inbox'
])
->select('messages.*', 'user_message.message_id', 'user_message.user_id','user_message.is_read')
->orderBy('messages.id', 'DESC')
->paginate(10);
return view('website_pages.home',compact('user_messages'));
}
}
GoogleController
class GoogleController extends Controller
{
/**
* Create a new controller instance.
*
* #return void
*/
public function __construct()
{
$this->middleware('auth');
}
public function google_login(){
return view('website_pages.login_google');
}
public function redirectToGoogle()
{
return Socialite::driver('google')->stateless()->redirect();
}
/**
* Create a new controller instance.
*
* #return void
*/
public function handleGoogleCallback()
{
$login_user_id = Auth::user()->id;
try {
$user = Socialite::driver('google')->stateless()->user();
$finduser = GmailAccount::where('google_id', $user->id)->first();
if($finduser){
return redirect('/home');
}
else{
$newUser = DB::table('gmail_accounts')->updateOrInsert(
[
'email' => $user->email,
],
[
'user_id' => $login_user_id,
'email' => $user->email,
'google_id'=> $user->id,
'remember_token'=> $user->token
]
);
if ($newUser){
return redirect('/home');
}
else{
return redirect()->back();
}
Auth::login($newUser, true);
}
} catch (Exception $e) {
dd($e->getMessage());
}
}
}
GmailAccount Model
class GmailAccount extends Model
{
protected $table = 'gmail_accounts';
protected $fillable = [
'email', 'password', 'google_id', 'user_id', 'remember_token'
];
public function user()
{
return $this->belongsTo('App\User');
}
}
Can you try this?
if($finduser) {
auth()->login($finduser), true);
}
else {
return redirect('/logingoogle');
}
And include these:
use Illuminate\Foundation\Auth\AuthenticatesUsers;
use Socialite;
Follow this which is a working example:
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use App\Providers\RouteServiceProvider;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
use Socialite;
use App\User;
class LoginController extends Controller
{
use AuthenticatesUsers;
public function redirectToProvider()
{
return Socialite::driver('google')->redirect();
}
public function handleProviderCallback()
{
try {
$user = Socialite::driver('google')->user();
} catch (\Exception $e) {
return redirect('/login');
}
// check if they're an existing user
$existingUser = User::where('email', $user->email)->first();
if ($existingUser) {
// log them in
auth()->login($existingUser, true);
} else {
// create a new user
$newUser = new User;
$newUser->name = $user->name;
$newUser->email = $user->email;
$newUser->google_id = $user->id;
$newUser->avatar = $user->avatar;
$newUser->avatar_original = $user->avatar_original;
$newUser->lastlogin_at = \Carbon\Carbon::now();
$newUser->save();
auth()->login($newUser, true);
}
session(['user_name' => $user->name]);
session(['user_email' => $user->email]);
session(['user_avatar' => $user->avatar]);
return redirect()->to('/home');
}
}
Route::get('/redirect', 'Auth\LoginController#redirectToProvider');
Route::get('/callback', 'Auth\LoginController#handleProviderCallback');

Error when try to sending email in Laravel

I was try to make some email to send email acticvation code when someone register. so i make it an event called UserRegistered. here's my RegisterController that call the event
public function store(Request $request){
$this->validate( $request,
[
'name' => 'required|min:3',
'username' => 'required|unique:users|min:3',
'email' => 'required|email|unique:users',
'password' => 'required|confirmed|min:12'
]
);
$user = User::create([
'name' => request('name'),
'email' => request('email'),
'username' => request('username'),
'password' => bcrypt(request('password')),
'token' => random(30),
]);
event(new UserRegistered($user));
return back()->with('success','Please check your email to active your account.');
}
On the UserRegistered i pass the user data like this:
class UserRegistered
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $user;
/**
* Create a new event instance.
*
* #return void
*/
public function __construct(User $user)
{
$this->user = $user;
}
/**
* Get the channels the event should broadcast on.
*
* #return \Illuminate\Broadcasting\Channel|array
*/
public function broadcastOn()
{
return new PrivateChannel('channel-name');
}
and here's my listener:
class SendActivationCode
{
/**
* Create the event listener.
*
* #return void
*/
public function __construct()
{
//
}
/**
* Handle the event.
*
* #param UserRegistered $event
* #return void
*/
public function handle(UserRegistered $event)
{
Mail::to($event)->send(new SendActivationMail($event));
}
}
and here the SendActivationMail class:
class SendActivationMail extends Mailable
{
use Queueable, SerializesModels;
protected $user;
/**
* Create a new message instance.
*
* #return void
*/
public function __construct(User $user)
{
$this->user = $user;
}
/**
* Build the message.
*
* #return $this
*/
public function build()
{
return $this->markdown('mails.user.activation')->with([
'name' => $this->user->name,
'token' => $this->user->token,
]);
}
}
but i got this errors:
"Type error: Argument 1 passed to App\Mail\SendActivationMail::__construct() must be an instance of App\User, instance of App\Events\UserRegistered given, called in E:\laragon\www\blog\app\Listeners\SendActivationCode.php on line 33 ◀"
My activation.blade.php:
#component('mail::message')
# Activation Code for {{ config('app.name') }}
Hi {{ $user->name }} You are recieved this because you are registered at our site. To active your account please click the link bellow.
#component('mail::button', ['url' => route('verify').$user->token])
Active Account
#endcomponent
Thanks,<br>
{{ config('app.name') }}
#endcomponent
so what can make me get this errors and how to fix it?
Looks like your SendActivatiionMail class doesn't extend Illuminate\Mail\Mailable. Try this in SendActivatiionMail.php:
namespace App\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
class SendActivatiionMail extends Mailable
{
use Queueable, SerializesModels;
...
and then in your event listener:
use App\Mail\SendActivationMail;
public function handle(UserRegistered $event)
{
Mail::to($event->user->email)->send(new SendActivationMail($event->user));
}
Your SendActivatiionCode must extends the mailable Class.
<?php
use Illuminate\Mail\Mailable;
class SendActivatiionCode extends Mailable {
...
}

Resources