Spaces:
No application file
No application file
namespace Mautic\EmailBundle\MonitoredEmail\Processor; | |
use Doctrine\ORM\EntityNotFoundException; | |
use Mautic\CoreBundle\Helper\EmailAddressHelper; | |
use Mautic\EmailBundle\EmailEvents; | |
use Mautic\EmailBundle\Entity\EmailReply; | |
use Mautic\EmailBundle\Entity\Stat; | |
use Mautic\EmailBundle\Event\EmailReplyEvent; | |
use Mautic\EmailBundle\Model\EmailStatModel; | |
use Mautic\EmailBundle\MonitoredEmail\Exception\ReplyNotFound; | |
use Mautic\EmailBundle\MonitoredEmail\Message; | |
use Mautic\EmailBundle\MonitoredEmail\Processor\Reply\Parser; | |
use Mautic\EmailBundle\MonitoredEmail\Search\ContactFinder; | |
use Mautic\LeadBundle\Model\LeadModel; | |
use Mautic\LeadBundle\Tracker\ContactTracker; | |
use Psr\Log\LoggerInterface; | |
use Symfony\Component\EventDispatcher\EventDispatcherInterface; | |
class Reply implements ProcessorInterface | |
{ | |
public function __construct( | |
private EmailStatModel $emailStatModel, | |
private ContactFinder $contactFinder, | |
private LeadModel $leadModel, | |
private EventDispatcherInterface $dispatcher, | |
private LoggerInterface $logger, | |
private ContactTracker $contactTracker, | |
private EmailAddressHelper $addressHelper | |
) { | |
} | |
public function process(Message $message): void | |
{ | |
$this->logger->debug('MONITORED EMAIL: Processing message ID '.$message->id.' for a reply'); | |
try { | |
$parser = new Parser($message); | |
$repliedEmail = $parser->parse(); | |
} catch (ReplyNotFound) { | |
// No hash found so bail as we won't consider this a reply | |
$this->logger->debug('MONITORED EMAIL: No hash ID found in the email body'); | |
return; | |
} | |
$hashId = $repliedEmail->getStatHash(); | |
$result = $this->contactFinder->findByHash($hashId); | |
if (!$stat = $result->getStat()) { | |
// No stat found so bail as we won't consider this a reply | |
$this->logger->debug('MONITORED EMAIL: Stat not found'); | |
return; | |
} | |
// A stat has been found so let's compare to the From address for the contact to prevent false positives | |
$possibleFromEmails = $this->addressHelper->getVariations($stat->getLead()->getEmail()); | |
$fromEmail = $this->addressHelper->cleanEmail($repliedEmail->getFromAddress()); | |
if (!in_array($fromEmail, $possibleFromEmails)) { | |
// We can't reliably assume this email was from the originating contact | |
$this->logger->debug('MONITORED EMAIL: '.implode(', ', $possibleFromEmails).' != '.$fromEmail.' so cannot confirm match'); | |
return; | |
} | |
$this->createReply($stat, $message->id); | |
$this->dispatchEvent($stat); | |
if (null !== $stat->getLead()) { | |
$this->leadModel->getRepository()->detachEntity($stat->getLead()); | |
} | |
$this->emailStatModel->getRepository()->detachEntity($stat); | |
} | |
/** | |
* @param string $trackingHash | |
* @param string $messageId | |
*/ | |
public function createReplyByHash($trackingHash, $messageId): void | |
{ | |
/** @var Stat|null $stat */ | |
$stat = $this->emailStatModel->getRepository()->findOneBy(['trackingHash' => $trackingHash]); | |
if (null === $stat) { | |
throw new EntityNotFoundException("Email Stat with tracking hash {$trackingHash} was not found"); | |
} | |
$stat->setIsRead(true); | |
if (null === $stat->getDateRead()) { | |
$stat->setDateRead(new \DateTime()); | |
} | |
$this->createReply($stat, $messageId); | |
$contact = $stat->getLead(); | |
if ($contact) { | |
$this->dispatchEvent($stat); | |
} | |
} | |
/** | |
* @param string $messageId | |
*/ | |
protected function createReply(Stat $stat, $messageId) | |
{ | |
$replies = $stat->getReplies()->filter( | |
fn (EmailReply $reply): bool => $reply->getMessageId() === $messageId | |
); | |
if (!$replies->count()) { | |
$emailReply = new EmailReply($stat, $messageId); | |
$stat->addReply($emailReply); | |
$this->emailStatModel->saveEntity($stat); | |
} | |
} | |
private function dispatchEvent(Stat $stat): void | |
{ | |
if ($this->dispatcher->hasListeners(EmailEvents::EMAIL_ON_REPLY)) { | |
$this->contactTracker->setTrackedContact($stat->getLead()); | |
$event = new EmailReplyEvent($stat); | |
$this->dispatcher->dispatch($event, EmailEvents::EMAIL_ON_REPLY); | |
unset($event); | |
} | |
} | |
} | |