Add an endpoint to set new authorized FROM email address
[MAILPOET-2804]
This commit is contained in:
@ -75,6 +75,25 @@ class Settings extends APIEndpoint {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function setAuthorizedFromAddress($data = []) {
|
||||||
|
$address = $data['address'] ?? null;
|
||||||
|
if (!$address) {
|
||||||
|
return $this->badRequest([
|
||||||
|
APIError::BAD_REQUEST => WPFunctions::get()->__('No email address specified.', 'mailpoet'),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
$address = trim($address);
|
||||||
|
|
||||||
|
try {
|
||||||
|
$this->authorizedEmailsController->setFromEmailAddress($address);
|
||||||
|
} catch (\InvalidArgumentException $e) {
|
||||||
|
return $this->badRequest([
|
||||||
|
APIError::UNAUTHORIZED => WPFunctions::get()->__('Can’t use this email yet! Please authorize it first.', 'mailpoet'),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
return $this->successResponse();
|
||||||
|
}
|
||||||
|
|
||||||
private function onSettingsChange($oldSettings, $newSettings) {
|
private function onSettingsChange($oldSettings, $newSettings) {
|
||||||
// Recalculate inactive subscribers
|
// Recalculate inactive subscribers
|
||||||
$oldInactivationInterval = $oldSettings['deactivate_subscriber_after_inactive_days'];
|
$oldInactivationInterval = $oldSettings['deactivate_subscriber_after_inactive_days'];
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace MailPoet\Mailer;
|
namespace MailPoet\Mailer;
|
||||||
|
|
||||||
|
use MailPoet\DI\ContainerWrapper;
|
||||||
use MailPoet\Mailer\Methods\AmazonSES;
|
use MailPoet\Mailer\Methods\AmazonSES;
|
||||||
use MailPoet\Mailer\Methods\ErrorMappers\AmazonSESMapper;
|
use MailPoet\Mailer\Methods\ErrorMappers\AmazonSESMapper;
|
||||||
use MailPoet\Mailer\Methods\ErrorMappers\MailPoetMapper;
|
use MailPoet\Mailer\Methods\ErrorMappers\MailPoetMapper;
|
||||||
@ -13,7 +14,6 @@ use MailPoet\Mailer\Methods\PHPMail;
|
|||||||
use MailPoet\Mailer\Methods\SendGrid;
|
use MailPoet\Mailer\Methods\SendGrid;
|
||||||
use MailPoet\Mailer\Methods\SMTP;
|
use MailPoet\Mailer\Methods\SMTP;
|
||||||
use MailPoet\Services\AuthorizedEmailsController;
|
use MailPoet\Services\AuthorizedEmailsController;
|
||||||
use MailPoet\Services\Bridge;
|
|
||||||
use MailPoet\Settings\SettingsController;
|
use MailPoet\Settings\SettingsController;
|
||||||
|
|
||||||
class Mailer {
|
class Mailer {
|
||||||
@ -74,7 +74,7 @@ class Mailer {
|
|||||||
$this->sender,
|
$this->sender,
|
||||||
$this->replyTo,
|
$this->replyTo,
|
||||||
new MailPoetMapper(),
|
new MailPoetMapper(),
|
||||||
new AuthorizedEmailsController($this->settings, new Bridge)
|
ContainerWrapper::getInstance()->get(AuthorizedEmailsController::class)
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case self::METHOD_SENDGRID:
|
case self::METHOD_SENDGRID:
|
||||||
|
@ -2,9 +2,11 @@
|
|||||||
|
|
||||||
namespace MailPoet\Services;
|
namespace MailPoet\Services;
|
||||||
|
|
||||||
|
use MailPoet\Mailer\Mailer;
|
||||||
use MailPoet\Mailer\MailerError;
|
use MailPoet\Mailer\MailerError;
|
||||||
use MailPoet\Mailer\MailerLog;
|
use MailPoet\Mailer\MailerLog;
|
||||||
use MailPoet\Models\Newsletter;
|
use MailPoet\Models\Newsletter;
|
||||||
|
use MailPoet\Newsletter\NewslettersRepository;
|
||||||
use MailPoet\Settings\SettingsController;
|
use MailPoet\Settings\SettingsController;
|
||||||
|
|
||||||
class AuthorizedEmailsController {
|
class AuthorizedEmailsController {
|
||||||
@ -16,15 +18,43 @@ class AuthorizedEmailsController {
|
|||||||
/** @var SettingsController */
|
/** @var SettingsController */
|
||||||
private $settings;
|
private $settings;
|
||||||
|
|
||||||
|
/** @var NewslettersRepository */
|
||||||
|
private $newslettersRepository;
|
||||||
|
|
||||||
private $automaticEmailTypes = [
|
private $automaticEmailTypes = [
|
||||||
Newsletter::TYPE_WELCOME,
|
Newsletter::TYPE_WELCOME,
|
||||||
Newsletter::TYPE_NOTIFICATION,
|
Newsletter::TYPE_NOTIFICATION,
|
||||||
Newsletter::TYPE_AUTOMATIC,
|
Newsletter::TYPE_AUTOMATIC,
|
||||||
];
|
];
|
||||||
|
|
||||||
public function __construct(SettingsController $settingsController, Bridge $bridge) {
|
public function __construct(
|
||||||
|
SettingsController $settingsController,
|
||||||
|
Bridge $bridge,
|
||||||
|
NewslettersRepository $newslettersRepository
|
||||||
|
) {
|
||||||
$this->settings = $settingsController;
|
$this->settings = $settingsController;
|
||||||
$this->bridge = $bridge;
|
$this->bridge = $bridge;
|
||||||
|
$this->newslettersRepository = $newslettersRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setFromEmailAddress(string $address) {
|
||||||
|
$authorizedEmails = array_map('strtolower', $this->bridge->getAuthorizedEmailAddresses() ?: []);
|
||||||
|
$isAuthorized = $this->validateAuthorizedEmail($authorizedEmails, $address);
|
||||||
|
if (!$isAuthorized) {
|
||||||
|
throw new \InvalidArgumentException("Email address '$address' is not authorized");
|
||||||
|
}
|
||||||
|
|
||||||
|
// update FROM address in settings & all scheduled and active emails
|
||||||
|
$this->settings->set('sender.address', $address);
|
||||||
|
$result = $this->validateAddressesInScheduledAndAutomaticEmails($authorizedEmails);
|
||||||
|
foreach ($result['invalid_senders_in_newsletters'] ?? [] as $item) {
|
||||||
|
$newsletter = $this->newslettersRepository->findOneById((int)$item['newsletter_id']);
|
||||||
|
if ($newsletter) {
|
||||||
|
$newsletter->setSenderAddress($address);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$this->newslettersRepository->flush();
|
||||||
|
$this->settings->set(self::AUTHORIZED_EMAIL_ADDRESSES_ERROR_SETTING, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function checkAuthorizedEmailAddresses() {
|
public function checkAuthorizedEmailAddresses() {
|
||||||
|
@ -3,10 +3,13 @@
|
|||||||
namespace MailPoet\Test\Services;
|
namespace MailPoet\Test\Services;
|
||||||
|
|
||||||
use Codeception\Stub\Expected;
|
use Codeception\Stub\Expected;
|
||||||
|
use InvalidArgumentException;
|
||||||
|
use MailPoet\Entities\NewsletterEntity;
|
||||||
use MailPoet\Mailer\Mailer;
|
use MailPoet\Mailer\Mailer;
|
||||||
use MailPoet\Mailer\MailerError;
|
use MailPoet\Mailer\MailerError;
|
||||||
use MailPoet\Mailer\MailerLog;
|
use MailPoet\Mailer\MailerLog;
|
||||||
use MailPoet\Models\Newsletter;
|
use MailPoet\Models\Newsletter;
|
||||||
|
use MailPoet\Newsletter\NewslettersRepository;
|
||||||
use MailPoet\Services\AuthorizedEmailsController;
|
use MailPoet\Services\AuthorizedEmailsController;
|
||||||
use MailPoet\Services\Bridge;
|
use MailPoet\Services\Bridge;
|
||||||
use MailPoet\Settings\SettingsController;
|
use MailPoet\Settings\SettingsController;
|
||||||
@ -155,6 +158,77 @@ class AuthorizedEmailsControllerTest extends \MailPoetTest {
|
|||||||
expect($error['invalid_senders_in_newsletters'][0]['subject'])->equals('Subject');
|
expect($error['invalid_senders_in_newsletters'][0]['subject'])->equals('Subject');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testItSetsFromAddressInSettings() {
|
||||||
|
$this->settings->set('sender.address', '');
|
||||||
|
$controller = $this->getController(['authorized@email.com']);
|
||||||
|
$controller->setFromEmailAddress('authorized@email.com');
|
||||||
|
expect($this->settings->get('sender.address'))->same('authorized@email.com');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testItSetsFromAddressInScheduledEmails() {
|
||||||
|
$newsletter = new NewsletterEntity();
|
||||||
|
$newsletter->setSubject('Subject');
|
||||||
|
$newsletter->setType(NewsletterEntity::TYPE_STANDARD);
|
||||||
|
$newsletter->setStatus(NewsletterEntity::STATUS_SCHEDULED);
|
||||||
|
$newsletter->setSenderAddress('invalid@email.com');
|
||||||
|
$this->entityManager->persist($newsletter);
|
||||||
|
$this->entityManager->flush();
|
||||||
|
|
||||||
|
$this->settings->set('sender.address', '');
|
||||||
|
$controller = $this->getController(['authorized@email.com']);
|
||||||
|
$controller->setFromEmailAddress('authorized@email.com');
|
||||||
|
expect($newsletter->getSenderAddress())->same('authorized@email.com');
|
||||||
|
|
||||||
|
// refresh from DB and check again
|
||||||
|
$this->entityManager->refresh($newsletter);
|
||||||
|
expect($newsletter->getSenderAddress())->same('authorized@email.com');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testItSetsFromAddressInAutomaticEmails() {
|
||||||
|
$newsletter = new NewsletterEntity();
|
||||||
|
$newsletter->setSubject('Subject');
|
||||||
|
$newsletter->setType(NewsletterEntity::TYPE_AUTOMATIC);
|
||||||
|
$newsletter->setStatus(NewsletterEntity::STATUS_ACTIVE);
|
||||||
|
$newsletter->setSenderAddress('invalid@email.com');
|
||||||
|
$this->entityManager->persist($newsletter);
|
||||||
|
$this->entityManager->flush();
|
||||||
|
|
||||||
|
$this->settings->set('sender.address', '');
|
||||||
|
$controller = $this->getController(['authorized@email.com']);
|
||||||
|
$controller->setFromEmailAddress('authorized@email.com');
|
||||||
|
expect($newsletter->getSenderAddress())->same('authorized@email.com');
|
||||||
|
|
||||||
|
// refresh from DB and check again
|
||||||
|
$this->entityManager->refresh($newsletter);
|
||||||
|
expect($newsletter->getSenderAddress())->same('authorized@email.com');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testItDoesntSetFromAddressForSentEmails() {
|
||||||
|
$newsletter = new NewsletterEntity();
|
||||||
|
$newsletter->setSubject('Subject');
|
||||||
|
$newsletter->setType(NewsletterEntity::TYPE_STANDARD);
|
||||||
|
$newsletter->setStatus(NewsletterEntity::STATUS_SENT);
|
||||||
|
$newsletter->setSenderAddress('invalid@email.com');
|
||||||
|
$this->entityManager->persist($newsletter);
|
||||||
|
$this->entityManager->flush();
|
||||||
|
|
||||||
|
$this->settings->set('sender.address', '');
|
||||||
|
$controller = $this->getController(['authorized@email.com']);
|
||||||
|
$controller->setFromEmailAddress('authorized@email.com');
|
||||||
|
expect($newsletter->getSenderAddress())->same('invalid@email.com');
|
||||||
|
|
||||||
|
// refresh from DB and check again
|
||||||
|
$this->entityManager->refresh($newsletter);
|
||||||
|
expect($newsletter->getSenderAddress())->same('invalid@email.com');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testSetsFromAddressThrowsForUnauthorizedEmail() {
|
||||||
|
$this->expectException(InvalidArgumentException::class);
|
||||||
|
$this->expectExceptionMessage("Email address 'invalid@email.com' is not authorized");
|
||||||
|
$controller = $this->getController(['authorized@email.com']);
|
||||||
|
$controller->setFromEmailAddress('invalid@email.com');
|
||||||
|
}
|
||||||
|
|
||||||
private function setMailPoetSendingMethod() {
|
private function setMailPoetSendingMethod() {
|
||||||
$this->settings->set(
|
$this->settings->set(
|
||||||
Mailer::MAILER_CONFIG_SETTING_NAME,
|
Mailer::MAILER_CONFIG_SETTING_NAME,
|
||||||
@ -172,7 +246,8 @@ class AuthorizedEmailsControllerTest extends \MailPoetTest {
|
|||||||
$getEmailsExpectaton = Expected::once($authorizedEmails);
|
$getEmailsExpectaton = Expected::once($authorizedEmails);
|
||||||
}
|
}
|
||||||
$bridgeMock = $this->make(Bridge::class, ['getAuthorizedEmailAddresses' => $getEmailsExpectaton]);
|
$bridgeMock = $this->make(Bridge::class, ['getAuthorizedEmailAddresses' => $getEmailsExpectaton]);
|
||||||
return new AuthorizedEmailsController($this->settings, $bridgeMock);
|
$newslettersRepository = $this->diContainer->get(NewslettersRepository::class);
|
||||||
|
return new AuthorizedEmailsController($this->settings, $bridgeMock, $newslettersRepository);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function _after() {
|
public function _after() {
|
||||||
|
Reference in New Issue
Block a user