We can't create mailer directly in DI container using the factory because it may fail in case the plugin is not configured properly and prevent plugin from start. The Mailer was previously injected because it contains lazy initialization. The lazy initialization in the singleton Mailer service was dangerous, because when used with some custom parameters it could cause that all services that inject the Mailer from DI would use the custom config instead the default. [MAILPOET-4115]
149 lines
4.5 KiB
PHP
149 lines
4.5 KiB
PHP
<?php
|
|
|
|
namespace MailPoet\Subscribers;
|
|
|
|
use Html2Text\Html2Text;
|
|
use MailPoet\Entities\SegmentEntity;
|
|
use MailPoet\Entities\SubscriberEntity;
|
|
use MailPoet\Mailer\MailerFactory;
|
|
use MailPoet\Mailer\MetaInfo;
|
|
use MailPoet\Services\AuthorizedEmailsController;
|
|
use MailPoet\Services\Bridge;
|
|
use MailPoet\Settings\SettingsController;
|
|
use MailPoet\Subscription\SubscriptionUrlFactory;
|
|
use MailPoet\Util\Helpers;
|
|
use MailPoet\WP\Functions as WPFunctions;
|
|
|
|
class ConfirmationEmailMailer {
|
|
|
|
const MAX_CONFIRMATION_EMAILS = 3;
|
|
|
|
/** @var MailerFactory */
|
|
private $mailerFactory;
|
|
|
|
/** @var WPFunctions */
|
|
private $wp;
|
|
|
|
/** @var SettingsController */
|
|
private $settings;
|
|
|
|
/** @var MetaInfo */
|
|
private $mailerMetaInfo;
|
|
|
|
/** @var SubscribersRepository */
|
|
private $subscribersRepository;
|
|
|
|
/** @var SubscriptionUrlFactory */
|
|
private $subscriptionUrlFactory;
|
|
|
|
/** @var array Cache for confirmation emails sent within a request */
|
|
private $sentEmails = [];
|
|
|
|
public function __construct(
|
|
MailerFactory $mailerFactory,
|
|
WPFunctions $wp,
|
|
SettingsController $settings,
|
|
SubscribersRepository $subscribersRepository,
|
|
SubscriptionUrlFactory $subscriptionUrlFactory
|
|
) {
|
|
$this->mailerFactory = $mailerFactory;
|
|
$this->wp = $wp;
|
|
$this->settings = $settings;
|
|
$this->mailerMetaInfo = new MetaInfo;
|
|
$this->subscriptionUrlFactory = $subscriptionUrlFactory;
|
|
$this->subscribersRepository = $subscribersRepository;
|
|
}
|
|
|
|
/**
|
|
* Use this method if you want to make sure the confirmation email
|
|
* is not sent multiple times within a single request
|
|
* e.g. if sending confirmation emails from hooks
|
|
* @throws \Exception if unable to send the email.
|
|
*/
|
|
public function sendConfirmationEmailOnce(SubscriberEntity $subscriber): bool {
|
|
if (isset($this->sentEmails[$subscriber->getId()])) {
|
|
return true;
|
|
}
|
|
return $this->sendConfirmationEmail($subscriber);
|
|
}
|
|
|
|
/**
|
|
* @throws \Exception if unable to send the email.
|
|
*/
|
|
public function sendConfirmationEmail(SubscriberEntity $subscriber) {
|
|
$signupConfirmation = $this->settings->get('signup_confirmation');
|
|
if ((bool)$signupConfirmation['enabled'] === false) {
|
|
return false;
|
|
}
|
|
if (!$this->wp->isUserLoggedIn() && $subscriber->getConfirmationsCount() >= self::MAX_CONFIRMATION_EMAILS) {
|
|
return false;
|
|
}
|
|
|
|
$authorizationEmailsValidation = $this->settings->get(AuthorizedEmailsController::AUTHORIZED_EMAIL_ADDRESSES_ERROR_SETTING);
|
|
$unauthorizedSenderEmail = isset($authorizationEmailsValidation['invalid_sender_address']);
|
|
if (Bridge::isMPSendingServiceEnabled() && $unauthorizedSenderEmail) {
|
|
return false;
|
|
}
|
|
|
|
$segments = $subscriber->getSegments()->toArray();
|
|
$segmentNames = array_map(function(SegmentEntity $segment) {
|
|
return $segment->getName();
|
|
}, $segments);
|
|
|
|
$body = nl2br($signupConfirmation['body']);
|
|
|
|
// replace list of segments shortcode
|
|
$body = str_replace(
|
|
'[lists_to_confirm]',
|
|
'<strong>' . join(', ', $segmentNames) . '</strong>',
|
|
$body
|
|
);
|
|
|
|
// replace activation link
|
|
$body = Helpers::replaceLinkTags(
|
|
$body,
|
|
$this->subscriptionUrlFactory->getConfirmationUrl($subscriber),
|
|
['target' => '_blank'],
|
|
'activation_link'
|
|
);
|
|
|
|
//create a text version. @ is important here, Html2Text throws warnings
|
|
$text = @Html2Text::convert(
|
|
(mb_detect_encoding($body, 'UTF-8', true)) ? $body : utf8_encode($body),
|
|
true
|
|
);
|
|
|
|
// build email data
|
|
$email = [
|
|
'subject' => $signupConfirmation['subject'],
|
|
'body' => [
|
|
'html' => $body,
|
|
'text' => $text,
|
|
],
|
|
];
|
|
|
|
// send email
|
|
$extraParams = [
|
|
'meta' => $this->mailerMetaInfo->getConfirmationMetaInfo($subscriber),
|
|
];
|
|
try {
|
|
$result = $this->mailerFactory->getDefaultMailer()->send($email, $subscriber, $extraParams);
|
|
} catch (\Exception $e) {
|
|
throw new \Exception(__('Something went wrong with your subscription. Please contact the website owner.', 'mailpoet'));
|
|
}
|
|
|
|
if ($result['response'] === false) {
|
|
throw new \Exception(__('Something went wrong with your subscription. Please contact the website owner.', 'mailpoet'));
|
|
};
|
|
|
|
if (!$this->wp->isUserLoggedIn()) {
|
|
$subscriber->setConfirmationsCount($subscriber->getConfirmationsCount() + 1);
|
|
$this->subscribersRepository->persist($subscriber);
|
|
$this->subscribersRepository->flush();
|
|
}
|
|
$this->sentEmails[$subscriber->getId()] = true;
|
|
|
|
return true;
|
|
}
|
|
}
|