I have a multi-tenant setup which allows each tenant to save their own SMTP information in a settings table. The job being saved right now is being sent to the system database instead of the tenant. This is causing an issue as a Service Provider is setup to configure the mail configuration on boot() to each of the provided values in the database. With the worker running the email job does send but uses the stored system SMTP values instead of the tenants - which I assume is just because it's looking in the same database as the current job's connection.
Service Provider
class TenantEmail extends ServiceProvider
{
/**
* Bootstrap services.
*
* #return void
*/
public function boot()
{
//
Config::set('mail.host', setting('admin.email_host'));
Config::set('mail.port', setting('admin.email_port'));
Config::set('mail.encryption', setting('admin.email_encrypt'));
Config::set('mail.username', setting('admin.email_username'));
Config::set('mail.password', setting('admin.email_password'));
}
}
SendEmail Job
Looking over the documentation on Hyn is looks like I can force set the tenant website Id during the dispatch but that didn't make a difference.
class SendEmail implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public $user;
public $sub;
public $content;
public $unsubscribeUrl;
public $replyAddress;
public $website_id;
/**
* Create a new job instance.
*
* #return void
*/
public function __construct($row, $subject, $message, $unsubscribeUrl, $replyTo,int $website_id)
{
//
$this->user = $row;
$this->sub = $subject;
$this->content = $message;
$this->unsubscribeUrl = $unsubscribeUrl;
$this->replyAddress = $replyTo;
$this->website_id = $website_id;
}
/**
* Execute the job.
*
* #return void
*/
public function handle()
{
//
$email = new ConnectEmail($this->user, $this->sub, $this->content, $this->unsubscribeUrl, $this->replyAddress);
Mail::to($this->user->email_address, $this->user->name)->send($email);
}
}
Not the cleanest approach perhaps but I was able to solve this by passing the SMTP information in my email controller when I dispatch the job.
$smtp = [
'host' => setting('admin.email_host'),
'port' => setting('admin.email_port'),
'encryption' => setting('admin.email_encrypt'),
'username' => setting('admin.email_username'),
'password' => setting('admin.email_password')
];
$emailJob = (new SendEmail($row, $subject, $message, $unsubscribeUrl, $replyTo, $websiteId, $smtp));
dispatch($emailJob)->delay($scheduleSend);
Then in my SendEmail job I just include the $smtp in the ConnectEmail and pass that over to the mailable, which in the init construct I just add in:
if(!empty($smtp)){
Config::set('mail.host', $smtp['host']);
Config::set('mail.port', $smtp['port']);
Config::set('mail.encryption', $smtp['encryption']);
Config::set('mail.username', $smtp['username']);
Config::set('mail.password', $smtp['password']);
}
This then queues up and sends the job using the dynamic SMTP information without a problem.
Related
I have successfully implemented pusher on my laravel app but I want to make, when the user succeeds in making an order the default status_message for the order is pending, the case is when the admin changes the status_message to processed, the user who has ordered gets a notification that the order he has made is processed.
this is my code but this code sends notifications to all users.
Controller
if ($data->status_message == 'processed') {
event(new OrderEvent('Hi, Your order is processed!'));
//...
}
My Event OrderEvent.php
public function broadcastOn()
{
return new Channel('notif-channel');
}
/**
* Broadcast order event.
*
* #return void
*/
public function broadcastAs()
{
return 'order-event';
}
in App blade
var channel = pusher.subscribe('notif-channel');
channel.bind('order-event', function(data) {
const obj = JSON.parse(JSON.stringify(data));
const message = obj.message;
blah blah blah
}
Both user and admin should be on the same channel. For example if user is subscribed for channel 'order-channel-SetUserID'.
Admin should send the message to that channel and you should look for it on the front end and make the changes on the DOM.
In your controller when you submit the changes of the status of the order run the event with the channel name
event(new OrderEvent($user_id, 'Hi, Your order is processed!'));
Now your event should look similar to this:
class OrderEvent implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $user_id;
public $message;
/**
* Create a new event instance.
*
* #return void
*/
public function __construct($user_id, $message)
{
$this->user_id = $user_id;
$this->message = $message;
}
/**
* Get the channels the event should broadcast on.
*
* #return \Illuminate\Broadcasting\Channel|array
*/
public function broadcastOn()
{
return new Channel('order-channel.' . $this->user_id);
}
public function broadcastAs()
{
return 'order-event';
}
}
Of course you can change your class Name etc... I'm just giving an idea.
it's important to send the changes on the same channel with this user or else you will make changes to other users that are visiting your website.
EDITED
Here is what else you need to configure.
In app/Providers/EventServiceProvider.php
You need to put the event in protected $listen
protected $listen = [
Registered::class => [
SendEmailVerificationNotification::class,
],
OrderEvent::class => [
OrderEventListener::class,
],
];
In app/Listeners You should create OrderEventListener.php and set it up as follow:
<?php
namespace App\Listeners;
use App\Events\OrderEvent;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Pusher;
class OrderEventListener
{
/**
* Create the event listener.
*
* #return void
*/
public function __construct()
{
//
}
/**
* Handle the event.
*
* #param \App\Events\OrderEvent $event
* #return void
*/
public function handle(OrderEvent $event)
{
$pusher = new Pusher(env('PUSHER_APP_KEY'),
env('PUSHER_APP_SECRET'), env('PUSHER_APP_ID'), [
'cluster' => env('PUSHER_APP_CLUSTER'),
'useTLS' => true
]);
$pusher->trigger($event->broadcastOn(),
$event->broadcastAs(), $event->data);
}
}
check your Debug Console in pusher dashboard? If you can see the event firing there all you need to do is show the message with javascript. If no event is running then something in your code is missing.
Hi everyone i'm just trying to queue my email with attachment in laravel project, but it does not seems to work. when i try to send an attachment without queue my mail it is working absolutely fine, but when i put my email in queue it just stop working. email is sent but attachment doesn't.
here is my code for email in controller
Mail::to($request->email)->send(new ContactUsEmail($contact_us));
and below code is from my mail job
class ContactUsEmail extends Mailable implements ShouldQueue
{
use Queueable, SerializesModels;
/**
* Create a new message instance.
*
* #return void
*/
protected $data;
public function __construct($data)
{
$this->data = $data;
}
/**
* Build the message.
*
* #return $this
*/
public function build()
{
$extension = explode('.',$this->data->attachment)[1];
return $this->subject($this->data->topic)->attach(public_path('/storage/attachments/contact-us/' . $this->data->attachment),
[
'as' => $this->data->attachment,
'mime' => 'application/'. $extension
])->markdown('mail.contact-us' ,[
'subject' => $this->data->subject,
'name' => $this->data->name,
'email' => $this->data->email,
'description' => $this->data->description,
]);
}
}
please let me know if i'm doing something wrong or missing something.
i appreciate your response
I can send emails to a lot of recipients but the problem is I am using a business email which I'm subscribe to my web host, the problem is when I send 1 email to a lot of recipients my web host automatically suspends my email's outgoing which technically I'm having problems with right now, so I tried using mailing list but it won't send emails to my recipients using the Mail(), but it works when sending a mail to mailist-join#domain.com.
Controller:
public function imail($request){
$dataEmail = [
'date' => $request->date,
'time_start' => $request->start,
'time_end' => $request->end,
'duration' => abs(strtotime($request->end) - strtotime($request->start))/(60*60),
'areas' => Purifier::clean($request->areas),
'reason' => Purifier::clean($request->activities)
];
$emails = UserEmail::where('email','!=','')->select('email')->get()->pluck('email');
$subject = 'ADVISORY (' . date("F j, Y",strtotime($request->date)) .')';
foreach ($emails as $email) {
Mail::to($email)
->send(new SendToAll($dataEmail,$subject));
}
}
SendToAll Mail
<?php
namespace App\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
class SendToAll extends Mailable implements ShouldQueue
{
use Queueable, SerializesModels;
// public $afterCommit = true;
public $data,$subject;
/**
* Create a new message instance.
*
* #return void
*/
public function __construct($data,$subject)
{
$this->data = $data;
$this->subject = $subject;
}
/**
* Build the message.
*
* #return $this
*/
public function build()
{
return $this->subject($this->subject)
->from('myemail#domain.com','Me')
->view('pages.imail')
->with('data',$this->data);
;
}
}
I also tried supervisor but to no avail. I'm using Windows Server 2012.
You have to use like below code
Mail::to($email)->cc(['mail1','mail2','mail3'])->send(new SendToAll($dataEmail,$subject));
I have Super-Admin and Admin roles. In Admin view I've added button to request verification email. The problem I'm having is that when Admin clicks the button to receive verification email, the email is from Admin, not Super-Admin.
How to make this to be sent to Admin from Super-Admin, instead of from Admin?
Route:
Route::post('/dashboard/SendEmailVerification', 'AdminDashboardController#SendEmailVerification')->name('dashboard.SendEmailVerification');
In AdminDashboardController:
use App\Notifications\EmailVerification;
use App\User;
.............
public function SendEmailVerification(Request $request){
$user = User::where('email_verification_code', $request->code)
->withoutGlobalScope('active')
->first();
$user->notify(new EmailVerification($user));
return Reply::success('Email sent!');
}
And the notification email:
namespace App\Notifications;
use App\Traits\SmtpSettings;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use App\User;
class EmailVerification extends Notification implements ShouldQueue
{
use Queueable, SmtpSettings;
protected $user;
/**
* Create a new notification instance.
*
* #return void
*/
public function __construct(User $user)
{
$this->user = $user;
$this->setMailConfigs();
}
/**
* Get the notification's delivery channels.
*t('mail::layout')
* #param mixed $notifiable
* #return array
*/
public function via($notifiable)
{
$via = ['mail'];
return $via;
}
/**
* Get the mail representation of the notification.
*
* #param mixed $notifiable
* #return \Illuminate\Notifications\Messages\MailMessage
*/
public function toMail($notifiable)
{
return (new MailMessage)
->subject('Confirm your email')
->greeting(__('Hello!'))
->line(__('email.emailVerify.text'))
->action('Confirm', getDomainSpecificUrl(route('front.get-email-verification', $this->user->email_verification_code), $this->user->company));
#->line(__('email.thankyouNote'));
}
/**
* Get the array representation of the notification.
*
* #param mixed $notifiable
* #return array
*/
public function toArray($notifiable)
{
return $notifiable->toArray();
}
}
You're getting wrong sender address because you never defined who's the sender in your Notification configuration. There are two ways to do this:
First: The first one is a really simple, but non-dynamic solution. In your .env configuration config, add these lines:
MAIL_FROM_NAME="My Name"
MAIL_FROM_ADDRESS=support#example.com
When you configure this, add this in yout config/mail.php configuration:
'from' => [
'address' => env('MAIL_FROM_ADDRESS', 'default value if not found in .env'),
'name' => env('MAIL_FROM_NAME', 'default value if not found in .env'),
],
Note: Don't forget to clear your cache, and restart queue when you do this:
Second: This is a more dynamic solution, since you can load the sender email address from your database. In your SendEmailVerification method, you can query up the super-admin user, and pass to the EmailVerification class:
public function SendEmailVerification(Request $request){
$user = User::where('email_verification_code', $request->code)
->withoutGlobalScope('active')
->first();
$superAdminUser = User::where('role', 'super-admin')->first();
$user->notify(new EmailVerification($user, $superAdminUser));
return Reply::success('Email sent!');
}
Then, change your EmailVerification class:
public $user;
public $superUser;
public function __construct(User $user, User $superUser)
{
$this->user = $user;
$this->superUser = $superUser;
$this->setMailConfigs();
}
And in your toMail() method, add another from() method:
public function toMail($notifiable)
{
return (new MailMessage)
->subject('Confirm your email')
->from($superAdminUser->email, $superAdminUser->first_name)
->greeting(__('Hello!'))
->line(__('email.emailVerify.text'))
->action('Confirm', getDomainSpecificUrl(route('front.get-email-verification', $this->user->email_verification_code), $this->user->company));
#->line(__('email.thankyouNote'));
}
Note: Also clear your cache and restart your queue.
Hope that this can resolve your issue. Let me know if you have any problems with these solutions.
You can read more about notifications on official documentation.
I am new in Laravel and I am trying to send Slack Notification each time an order is placed. For testing, I used my Incoming Webhook. Now when I am changing the webhook to clients slack webhook. Its still sending the notification to old webhook.
Can you help me sort this out?
This is my Listener
public function handle(OrderConfirmed $event)
{
$admin=User::find(73);
$user=User::find($event->order->user_id);
$order=Order::find($event->order->id);
Notification::send(User::find(73),(new \App\Notifications\PaymentProcessedNot($user,$order)));
}
This is my PaymentProcessedNot class
class PaymentProcessedNot extends Notification implements ShouldQueue
{
use Queueable;
public $user;
public $order;
/**
* Create a new notification instance.
*
* #return void
*/
public function __construct(\App\User $user,\App\Order $order)
{
$this->user=$user;
$this->order=$order;
}
/**
* Get the notification's delivery channels.
*
* #param mixed $notifiable
* #return array
*/
public function via($notifiable)
{
return ['slack'];
}
public function toSlack($notifiable){
return (new SlackMessage)
->success()
->content('A new Payment was just processed.')
->attachment(function ($attachment){
$attachment->title('Order : '. $this->order->order_id)
->fields([
'Amount' => ' ₹'. number_format($this->order->amount,2),
'From' => $this->user->name,
'Payment Mode' => strtoupper($this->order->payment_mode)
]);
});
}
}
This is my User.php
public function routeNotificationForSlack()
{
return 'new_slack_incoming_webhook';
}
If your using .env you should clear the cache!
Just checking this is actually the url right?
return 'new_slack_incoming_webhook';