1
0
mirror of https://github.com/freescout-helpdesk/freescout.git synced 2024-11-25 11:52:29 +01:00
freescout/app/Jobs/SendReplyToCustomer.php

240 lines
8.4 KiB
PHP
Raw Normal View History

2018-08-02 18:17:13 +02:00
<?php
namespace App\Jobs;
use App\Mail\ReplyToCustomer;
2018-08-08 09:52:53 +02:00
use App\SendLog;
2018-08-02 18:17:13 +02:00
use App\Thread;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
2018-08-02 18:18:32 +02:00
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
2018-08-02 18:17:13 +02:00
use Mail;
class SendReplyToCustomer implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
// Number of retries + 1
public $tries = 6;
2018-12-09 10:53:36 +01:00
2018-08-02 18:17:13 +02:00
public $conversation;
public $threads;
public $customer;
2018-08-20 19:41:51 +02:00
private $failures = [];
private $recipients = [];
private $last_thread = null;
private $message_id = '';
2018-08-21 11:22:27 +02:00
private $customer_email = '';
2018-08-20 19:41:51 +02:00
2018-08-02 18:17:13 +02:00
/**
* Create a new job instance.
*
* @return void
*/
2018-08-08 09:52:53 +02:00
public function __construct($conversation, $threads, $customer)
2018-08-02 18:17:13 +02:00
{
$this->conversation = $conversation;
$this->threads = $threads;
$this->customer = $customer;
}
/**
* Execute the job.
*
* @return void
*/
public function handle()
{
2019-06-24 07:39:30 +02:00
// When forwarding conversation is undone, new conversation is deleted.
if (!$this->conversation) {
return;
}
2018-08-02 18:17:13 +02:00
$mailbox = $this->conversation->mailbox;
2019-06-24 07:39:30 +02:00
// Add forwarded conversation replies.
if ($this->conversation->threads_count == 1 && count($this->threads) == 1) {
$forward_child_thread = $this->threads[0];
if ($forward_child_thread->isForwarded() && $forward_child_thread->getForwardParentConversation()) {
// Add replies from original conversation.
$forwarded_replies = $forward_child_thread->getForwardParentConversation()->getReplies();
$forwarded_replies = $forwarded_replies->sortByDesc(function ($item, $key) {
return $item->created_at;
});
$forward_parent_thread = Thread::find($forward_child_thread->getMeta('forward_parent_thread_id'));
if ($forward_parent_thread) {
// Remove threads created after forwarding.
foreach ($forwarded_replies as $i => $thread) {
if ($thread->created_at > $forward_parent_thread->created_at) {
$forwarded_replies->forget($i);
}
}
$this->threads = $this->threads->merge($forwarded_replies);
}
}
}
2018-08-02 18:17:13 +02:00
// Threads has to be sorted here, if sorted before, they come here in wrong order
$this->threads = $this->threads->sortByDesc(function ($item, $key) {
return $item->created_at;
});
$new = false;
$headers = [];
2018-08-20 19:41:51 +02:00
$this->last_thread = $this->threads->first();
2018-08-02 18:17:13 +02:00
$prev_thread = null;
2018-09-16 12:52:52 +02:00
// If thread is draft, it means it has been undone
if ($this->last_thread->isDraft()) {
return;
}
2018-08-08 09:52:53 +02:00
// Configure mail driver according to Mailbox settings
\App\Misc\Mail::setMailDriver($mailbox, $this->last_thread->created_by_user);
2018-08-08 09:52:53 +02:00
2018-08-02 18:17:13 +02:00
if (count($this->threads) == 1) {
$new = true;
}
$i = 0;
foreach ($this->threads as $thread) {
if ($i == 1) {
$prev_thread = $thread;
break;
}
$i++;
}
// Get penultimate email Message-Id if reply
if (!$new && !empty($prev_thread) && $prev_thread->message_id) {
$headers['In-Reply-To'] = '<'.$prev_thread->message_id.'>';
$headers['References'] = '<'.$prev_thread->message_id.'>';
}
$this->message_id = \App\Misc\Mail::MESSAGE_ID_PREFIX_REPLY_TO_CUSTOMER.'-'.$this->last_thread->id.'-'.md5($this->last_thread->id).'@'.$mailbox->getEmailDomain();
2018-08-20 19:41:51 +02:00
$headers['Message-ID'] = $this->message_id;
2018-08-02 18:17:13 +02:00
2018-08-27 10:08:20 +02:00
$this->customer_email = $this->conversation->customer_email;
2018-08-20 19:41:51 +02:00
$cc_array = $mailbox->removeMailboxEmailsFromList($this->last_thread->getCcArray());
$bcc_array = $mailbox->removeMailboxEmailsFromList($this->last_thread->getBccArray());
2018-08-27 10:08:20 +02:00
// Remove customer email from CC and BCC
$cc_array = \App\Misc\Mail::removeEmailFromArray($cc_array, $this->customer_email);
$bcc_array = \App\Misc\Mail::removeEmailFromArray($bcc_array, $this->customer_email);
2018-08-27 10:08:20 +02:00
// Remove from BCC emails which are present in CC
foreach ($cc_array as $cc_email) {
$bcc_array = \App\Misc\Mail::removeEmailFromArray($bcc_array, $cc_email);
2018-08-27 10:08:20 +02:00
}
2018-08-21 11:22:27 +02:00
$this->recipients = array_merge([$this->customer_email], $cc_array, $bcc_array);
2018-08-20 19:41:51 +02:00
// If sending fails, all recipiens fail.
// if ($this->attempts() > 1) {
// $cc_array = [];
// $bcc_array = [];
// }
2018-08-15 08:10:05 +02:00
try {
2018-08-21 11:22:27 +02:00
Mail::to([['name' => $this->customer->getFullName(), 'email' => $this->customer_email]])
2018-08-15 15:03:53 +02:00
->cc($cc_array)
->bcc($bcc_array)
->send(new ReplyToCustomer($this->conversation, $this->threads, $headers, $mailbox));
2018-08-15 08:10:05 +02:00
} catch (\Exception $e) {
2018-08-22 09:26:42 +02:00
// We come here in case SMTP server unavailable for example
2018-08-15 08:10:05 +02:00
activity()
2018-08-22 09:26:42 +02:00
->causedBy($this->customer)
->withProperties([
2018-08-21 11:22:27 +02:00
'error' => $e->getMessage().'; File: '.$e->getFile().' ('.$e->getLine().')',
2018-08-22 09:26:42 +02:00
])
->useLog(\App\ActivityLog::NAME_EMAILS_SENDING)
->log(\App\ActivityLog::DESCRIPTION_EMAILS_SENDING_ERROR_TO_CUSTOMER);
2018-08-20 19:41:51 +02:00
2018-08-22 09:26:42 +02:00
// Failures will be saved to send log when retry attempts will finish
// Mail::failures() is empty in case of connection error.
2018-08-20 19:41:51 +02:00
$this->failures = $this->recipients;
2018-08-22 09:26:42 +02:00
// Save to send log
$this->saveToSendLog($e->getMessage());
2018-12-09 10:53:36 +01:00
// Retry job with delay.
// https://stackoverflow.com/questions/35258175/how-can-i-create-delays-between-failed-queued-job-attempts-in-laravel
if ($this->attempts() < $this->tries) {
2018-12-09 10:53:36 +01:00
$this->release(3600);
2018-12-13 10:11:15 +01:00
2018-12-09 10:53:36 +01:00
throw $e;
} else {
$this->last_thread->send_status = SendLog::STATUS_SEND_ERROR;
$this->last_thread->updateSendStatusData(['msg' => $e->getMessage()]);
$this->last_thread->save();
// This executes $this->failed().
2018-12-09 10:53:36 +01:00
$this->fail($e);
2018-12-21 10:10:07 +01:00
return;
2018-12-09 10:53:36 +01:00
}
2018-08-15 08:10:05 +02:00
}
2018-08-02 18:17:13 +02:00
2018-08-09 10:14:48 +02:00
// In message_id we are storing Message-ID of the incoming email which created the thread
// Outcoming message_id can be generated for each thread by thread->id
2018-08-20 19:41:51 +02:00
// $this->last_thread->message_id = $message_id;
// $this->last_thread->save();
2018-08-02 18:17:13 +02:00
2018-08-08 09:52:53 +02:00
// Laravel tells us exactly what email addresses failed
2018-08-20 19:41:51 +02:00
$this->failures = Mail::failures();
2018-08-02 18:18:32 +02:00
2018-08-08 09:52:53 +02:00
// Save to send log
2018-08-20 19:41:51 +02:00
$this->saveToSendLog();
2018-08-02 18:17:13 +02:00
}
/**
* The job failed to process.
2018-08-22 09:26:42 +02:00
* This method is called after attempts had finished.
* At this stage method has access only to variables passed in constructor.
2018-08-02 18:17:13 +02:00
*
2018-08-02 18:18:32 +02:00
* @param Exception $exception
*
2018-08-02 18:17:13 +02:00
* @return void
*/
2018-08-24 14:24:11 +02:00
public function failed(\Exception $e)
{
activity()
->causedBy($this->customer)
->withProperties([
'error' => $e->getMessage().'; File: '.$e->getFile().' ('.$e->getLine().')',
2018-08-27 10:08:20 +02:00
'to' => $this->customer_email,
2018-08-24 14:24:11 +02:00
])
->useLog(\App\ActivityLog::NAME_EMAILS_SENDING)
->log(\App\ActivityLog::DESCRIPTION_EMAILS_SENDING_ERROR_TO_CUSTOMER);
$this->saveToSendLog();
}
2018-08-20 19:41:51 +02:00
/**
2018-08-22 09:26:42 +02:00
* Save emails to send log.
2018-08-20 19:41:51 +02:00
*/
2018-08-22 09:26:42 +02:00
public function saveToSendLog($error_message = '')
2018-08-20 19:41:51 +02:00
{
foreach ($this->recipients as $recipient) {
if (in_array($recipient, $this->failures)) {
$status = SendLog::STATUS_SEND_ERROR;
2018-08-22 09:26:42 +02:00
$status_message = $error_message;
2018-08-20 19:41:51 +02:00
} else {
$status = SendLog::STATUS_ACCEPTED;
2018-08-22 09:26:42 +02:00
$status_message = '';
2018-08-20 19:41:51 +02:00
}
2018-08-21 11:22:27 +02:00
if ($this->customer_email == $recipient) {
2018-08-20 19:41:51 +02:00
$customer_id = $this->customer->id;
} else {
$customer_id = null;
}
2018-08-24 14:24:11 +02:00
SendLog::log($this->last_thread->id, $this->message_id, $recipient, SendLog::MAIL_TYPE_EMAIL_TO_CUSTOMER, $status, $customer_id, null, $status_message);
2018-08-20 19:41:51 +02:00
}
2018-08-02 18:17:13 +02:00
}
}