<?php
namespace MailPoet\Subscribers;
if (!defined('ABSPATH')) exit;
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;
}
}