Implement Show sender domain warning for settings
This would show the sender domain warning message for domains that are not verified and have a Retricted DMARC Policy MAILPOET-4302
This commit is contained in:
committed by
Veljko V
parent
370de8050a
commit
9e5f1d0ff0
@ -11,6 +11,7 @@ function SenderEmailAddressWarning({
|
|||||||
emailAddress,
|
emailAddress,
|
||||||
mssActive,
|
mssActive,
|
||||||
isEmailAuthorized,
|
isEmailAuthorized,
|
||||||
|
showSenderDomainWarning,
|
||||||
}) {
|
}) {
|
||||||
const [showAuthorizedEmailModal, setShowAuthorizedEmailModal] =
|
const [showAuthorizedEmailModal, setShowAuthorizedEmailModal] =
|
||||||
useState(false);
|
useState(false);
|
||||||
@ -21,6 +22,8 @@ function SenderEmailAddressWarning({
|
|||||||
setShowAuthorizedEmailModal(true);
|
setShowAuthorizedEmailModal(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const emailAddressDomain = emailAddress.split('@').pop().toLowerCase();
|
||||||
|
|
||||||
if (mssActive) {
|
if (mssActive) {
|
||||||
if (!isEmailAuthorized) {
|
if (!isEmailAuthorized) {
|
||||||
return (
|
return (
|
||||||
@ -56,9 +59,42 @@ function SenderEmailAddressWarning({
|
|||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
if (showSenderDomainWarning) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{showAuthorizedEmailModal && (
|
||||||
|
// TODO: Change me. This should open the sender domain modal
|
||||||
|
<AuthorizeSenderEmailModal
|
||||||
|
senderEmail={emailAddress}
|
||||||
|
onRequestClose={() => {
|
||||||
|
setShowAuthorizedEmailModal(false);
|
||||||
|
}}
|
||||||
|
setAuthorizedAddress={setAuthorizedEmailAddress}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<p className="sender_email_address_warning">
|
||||||
|
{ReactStringReplace(
|
||||||
|
MailPoet.I18n.t('authorizeSenderDomain'),
|
||||||
|
/\[link](.*?)\[\/link]/g,
|
||||||
|
(match) => (
|
||||||
|
<a
|
||||||
|
key={match}
|
||||||
|
className="mailpoet-link"
|
||||||
|
href="https://kb.mailpoet.com/article/328-set-up-dkim-for-your-sender-domain"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
onClick={loadModal}
|
||||||
|
>
|
||||||
|
{match}
|
||||||
|
</a>
|
||||||
|
),
|
||||||
|
)}
|
||||||
|
</p>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
const emailAddressDomain = emailAddress.split('@').pop().toLowerCase();
|
|
||||||
if (window.mailpoet_free_domains.indexOf(emailAddressDomain) > -1) {
|
if (window.mailpoet_free_domains.indexOf(emailAddressDomain) > -1) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@ -100,10 +136,12 @@ SenderEmailAddressWarning.propTypes = {
|
|||||||
emailAddress: PropTypes.string.isRequired,
|
emailAddress: PropTypes.string.isRequired,
|
||||||
mssActive: PropTypes.bool.isRequired,
|
mssActive: PropTypes.bool.isRequired,
|
||||||
isEmailAuthorized: PropTypes.bool,
|
isEmailAuthorized: PropTypes.bool,
|
||||||
|
showSenderDomainWarning: PropTypes.bool,
|
||||||
};
|
};
|
||||||
|
|
||||||
SenderEmailAddressWarning.defaultProps = {
|
SenderEmailAddressWarning.defaultProps = {
|
||||||
isEmailAuthorized: true, // don't show error message by default
|
isEmailAuthorized: true, // don't show error message by default
|
||||||
|
showSenderDomainWarning: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
export { SenderEmailAddressWarning };
|
export { SenderEmailAddressWarning };
|
||||||
|
@ -1,15 +1,30 @@
|
|||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
|
import { MailPoet } from 'mailpoet';
|
||||||
import { Label, Inputs } from 'settings/components';
|
import { Label, Inputs } from 'settings/components';
|
||||||
import { isEmail, t, onChange, setLowercaseValue } from 'common/functions';
|
import { isEmail, t, onChange, setLowercaseValue } from 'common/functions';
|
||||||
import { Input } from 'common/form/input/input';
|
import { Input } from 'common/form/input/input';
|
||||||
import { useSetting, useSelector, useAction } from 'settings/store/hooks';
|
import { useSetting, useSelector, useAction } from 'settings/store/hooks';
|
||||||
import { SenderEmailAddressWarning } from 'common/sender_email_address_warning.jsx';
|
import { SenderEmailAddressWarning } from 'common/sender_email_address_warning.jsx';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} email - Email address
|
||||||
|
* @param {ApiActionType} type - action type
|
||||||
|
* @returns {Promise}
|
||||||
|
*/
|
||||||
|
const makeApiRequest = (domain: string) =>
|
||||||
|
MailPoet.Ajax.post({
|
||||||
|
api_version: MailPoet.apiVersion,
|
||||||
|
endpoint: 'settings',
|
||||||
|
action: 'checkDomainDmarcPolicy',
|
||||||
|
data: { domain },
|
||||||
|
});
|
||||||
|
|
||||||
export function DefaultSender() {
|
export function DefaultSender() {
|
||||||
const isMssActive = useSelector('isMssActive')();
|
const isMssActive = useSelector('isMssActive')();
|
||||||
const [senderName, setSenderName] = useSetting('sender', 'name');
|
const [senderName, setSenderName] = useSetting('sender', 'name');
|
||||||
const [senderEmail, setSenderEmail] = useSetting('sender', 'address');
|
const [senderEmail, setSenderEmail] = useSetting('sender', 'address');
|
||||||
const [isAuthorized, setIsAuthorized] = useState(true);
|
const [isAuthorized, setIsAuthorized] = useState(true);
|
||||||
|
const [showSenderDomainWarning, setShowSenderDomainWarning] = useState(false);
|
||||||
const [replyToName, setReplyToName] = useSetting('reply_to', 'name');
|
const [replyToName, setReplyToName] = useSetting('reply_to', 'name');
|
||||||
const [replyToEmail, setReplyToEmail] = useSetting('reply_to', 'address');
|
const [replyToEmail, setReplyToEmail] = useSetting('reply_to', 'address');
|
||||||
const setErrorFlag = useAction('setErrorFlag');
|
const setErrorFlag = useAction('setErrorFlag');
|
||||||
@ -22,6 +37,36 @@ export function DefaultSender() {
|
|||||||
}
|
}
|
||||||
setIsAuthorized(window.mailpoet_authorized_emails.includes(email));
|
setIsAuthorized(window.mailpoet_authorized_emails.includes(email));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const checkSenderEmailDomain = (email: string) => {
|
||||||
|
const emailAddressDomain = email.split('@').pop().toLowerCase();
|
||||||
|
|
||||||
|
const isDomainVerified =
|
||||||
|
window.mailpoet_verified_sender_domains.includes(emailAddressDomain);
|
||||||
|
if (isDomainVerified) {
|
||||||
|
// do nothing if the email domain is verified
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check domain DMARC policy
|
||||||
|
makeApiRequest(emailAddressDomain)
|
||||||
|
.then((res) => {
|
||||||
|
const isDmarcPolicyRetricted = Boolean(
|
||||||
|
res?.data?.isDmarcPolicyRetricted,
|
||||||
|
);
|
||||||
|
setShowSenderDomainWarning(isDmarcPolicyRetricted);
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
// do nothing for now when the request fails
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const performActionOnBlur = (data: string) => {
|
||||||
|
isAuthorizedEmail(data);
|
||||||
|
|
||||||
|
checkSenderEmailDomain(data);
|
||||||
|
};
|
||||||
|
|
||||||
const updateSenderEmailController = (email: string) => {
|
const updateSenderEmailController = (email: string) => {
|
||||||
setIsAuthorized(true);
|
setIsAuthorized(true);
|
||||||
setSenderEmail(email);
|
setSenderEmail(email);
|
||||||
@ -66,7 +111,7 @@ export function DefaultSender() {
|
|||||||
data-automation-id="from-email-field"
|
data-automation-id="from-email-field"
|
||||||
value={senderEmail}
|
value={senderEmail}
|
||||||
onChange={onChange(setLowercaseValue(updateSenderEmailController))}
|
onChange={onChange(setLowercaseValue(updateSenderEmailController))}
|
||||||
onBlur={onChange(isAuthorizedEmail)}
|
onBlur={onChange(performActionOnBlur)}
|
||||||
/>
|
/>
|
||||||
<br />
|
<br />
|
||||||
{invalidSenderEmail && (
|
{invalidSenderEmail && (
|
||||||
@ -79,6 +124,7 @@ export function DefaultSender() {
|
|||||||
emailAddress={senderEmail}
|
emailAddress={senderEmail}
|
||||||
mssActive={isMssActive}
|
mssActive={isMssActive}
|
||||||
isEmailAuthorized={isAuthorized}
|
isEmailAuthorized={isAuthorized}
|
||||||
|
showSenderDomainWarning={showSenderDomainWarning}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<label className="mailpoet-settings-inputs-row" htmlFor="reply_to-name">
|
<label className="mailpoet-settings-inputs-row" htmlFor="reply_to-name">
|
||||||
|
@ -15,6 +15,7 @@ use MailPoet\Newsletter\NewslettersRepository;
|
|||||||
use MailPoet\Newsletter\Sending\ScheduledTasksRepository;
|
use MailPoet\Newsletter\Sending\ScheduledTasksRepository;
|
||||||
use MailPoet\Segments\SegmentsRepository;
|
use MailPoet\Segments\SegmentsRepository;
|
||||||
use MailPoet\Services\AuthorizedEmailsController;
|
use MailPoet\Services\AuthorizedEmailsController;
|
||||||
|
use MailPoet\Services\AuthorizedSenderDomainController;
|
||||||
use MailPoet\Services\Bridge;
|
use MailPoet\Services\Bridge;
|
||||||
use MailPoet\Settings\SettingsChangeHandler;
|
use MailPoet\Settings\SettingsChangeHandler;
|
||||||
use MailPoet\Settings\SettingsController;
|
use MailPoet\Settings\SettingsController;
|
||||||
@ -37,6 +38,9 @@ class Settings extends APIEndpoint {
|
|||||||
/** @var AuthorizedEmailsController */
|
/** @var AuthorizedEmailsController */
|
||||||
private $authorizedEmailsController;
|
private $authorizedEmailsController;
|
||||||
|
|
||||||
|
/** @var AuthorizedSenderDomainController */
|
||||||
|
private $senderDomainController;
|
||||||
|
|
||||||
/** @var TransactionalEmails */
|
/** @var TransactionalEmails */
|
||||||
private $wcTransactionalEmails;
|
private $wcTransactionalEmails;
|
||||||
|
|
||||||
@ -80,6 +84,7 @@ class Settings extends APIEndpoint {
|
|||||||
SettingsController $settings,
|
SettingsController $settings,
|
||||||
Bridge $bridge,
|
Bridge $bridge,
|
||||||
AuthorizedEmailsController $authorizedEmailsController,
|
AuthorizedEmailsController $authorizedEmailsController,
|
||||||
|
AuthorizedSenderDomainController $senderDomainController,
|
||||||
TransactionalEmails $wcTransactionalEmails,
|
TransactionalEmails $wcTransactionalEmails,
|
||||||
WPFunctions $wp,
|
WPFunctions $wp,
|
||||||
EntityManager $entityManager,
|
EntityManager $entityManager,
|
||||||
@ -96,6 +101,7 @@ class Settings extends APIEndpoint {
|
|||||||
$this->settings = $settings;
|
$this->settings = $settings;
|
||||||
$this->bridge = $bridge;
|
$this->bridge = $bridge;
|
||||||
$this->authorizedEmailsController = $authorizedEmailsController;
|
$this->authorizedEmailsController = $authorizedEmailsController;
|
||||||
|
$this->senderDomainController = $senderDomainController;
|
||||||
$this->wcTransactionalEmails = $wcTransactionalEmails;
|
$this->wcTransactionalEmails = $wcTransactionalEmails;
|
||||||
$this->servicesChecker = $servicesChecker;
|
$this->servicesChecker = $servicesChecker;
|
||||||
$this->wp = $wp;
|
$this->wp = $wp;
|
||||||
@ -246,6 +252,22 @@ class Settings extends APIEndpoint {
|
|||||||
return $this->successResponse($response);
|
return $this->successResponse($response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function checkDomainDmarcPolicy($data = []) {
|
||||||
|
$domain = $data['domain'] ?? null;
|
||||||
|
|
||||||
|
if (!$domain) {
|
||||||
|
return $this->badRequest([
|
||||||
|
APIError::BAD_REQUEST => WPFunctions::get()->__('No sender domain specified.', 'mailpoet'),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$domain = trim($domain);
|
||||||
|
|
||||||
|
$response = ['isDmarcPolicyRetricted' => $this->senderDomainController->isDomainDmarcRetricted($domain)];
|
||||||
|
|
||||||
|
return $this->successResponse($response);
|
||||||
|
}
|
||||||
|
|
||||||
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'];
|
||||||
|
@ -19,6 +19,7 @@ use MailPoet\Newsletter\NewslettersRepository;
|
|||||||
use MailPoet\Newsletter\Sending\ScheduledTasksRepository;
|
use MailPoet\Newsletter\Sending\ScheduledTasksRepository;
|
||||||
use MailPoet\Segments\SegmentsRepository;
|
use MailPoet\Segments\SegmentsRepository;
|
||||||
use MailPoet\Services\AuthorizedEmailsController;
|
use MailPoet\Services\AuthorizedEmailsController;
|
||||||
|
use MailPoet\Services\AuthorizedSenderDomainController;
|
||||||
use MailPoet\Services\Bridge;
|
use MailPoet\Services\Bridge;
|
||||||
use MailPoet\Settings\SettingsChangeHandler;
|
use MailPoet\Settings\SettingsChangeHandler;
|
||||||
use MailPoet\Settings\SettingsController;
|
use MailPoet\Settings\SettingsController;
|
||||||
@ -53,6 +54,7 @@ class SettingsTest extends \MailPoetTest {
|
|||||||
$this->settings,
|
$this->settings,
|
||||||
new Bridge,
|
new Bridge,
|
||||||
$this->make(AuthorizedEmailsController::class, ['onSettingsSave' => null ]),
|
$this->make(AuthorizedEmailsController::class, ['onSettingsSave' => null ]),
|
||||||
|
$this->diContainer->get(AuthorizedSenderDomainController::class),
|
||||||
$this->make(TransactionalEmails::class),
|
$this->make(TransactionalEmails::class),
|
||||||
WPFunctions::get(),
|
WPFunctions::get(),
|
||||||
$this->diContainer->get(EntityManager::class),
|
$this->diContainer->get(EntityManager::class),
|
||||||
@ -96,6 +98,7 @@ class SettingsTest extends \MailPoetTest {
|
|||||||
$this->settings,
|
$this->settings,
|
||||||
$this->make(Bridge::class, ['onSettingsSave' => Expected::once()]),
|
$this->make(Bridge::class, ['onSettingsSave' => Expected::once()]),
|
||||||
$this->make(AuthorizedEmailsController::class, ['onSettingsSave' => Expected::once()]),
|
$this->make(AuthorizedEmailsController::class, ['onSettingsSave' => Expected::once()]),
|
||||||
|
$this->diContainer->get(AuthorizedSenderDomainController::class),
|
||||||
$this->make(TransactionalEmails::class),
|
$this->make(TransactionalEmails::class),
|
||||||
WPFunctions::get(),
|
WPFunctions::get(),
|
||||||
$this->diContainer->get(EntityManager::class),
|
$this->diContainer->get(EntityManager::class),
|
||||||
@ -130,6 +133,7 @@ class SettingsTest extends \MailPoetTest {
|
|||||||
$this->settings,
|
$this->settings,
|
||||||
$bridgeMock,
|
$bridgeMock,
|
||||||
new AuthorizedEmailsController($this->settings, $bridgeMock, $this->diContainer->get(NewslettersRepository::class)),
|
new AuthorizedEmailsController($this->settings, $bridgeMock, $this->diContainer->get(NewslettersRepository::class)),
|
||||||
|
$this->diContainer->get(AuthorizedSenderDomainController::class),
|
||||||
$this->make(TransactionalEmails::class),
|
$this->make(TransactionalEmails::class),
|
||||||
WPFunctions::get(),
|
WPFunctions::get(),
|
||||||
$this->diContainer->get(EntityManager::class),
|
$this->diContainer->get(EntityManager::class),
|
||||||
@ -159,6 +163,7 @@ class SettingsTest extends \MailPoetTest {
|
|||||||
$this->settings,
|
$this->settings,
|
||||||
$bridgeMock,
|
$bridgeMock,
|
||||||
new AuthorizedEmailsController($this->settings, $bridgeMock, $this->diContainer->get(NewslettersRepository::class)),
|
new AuthorizedEmailsController($this->settings, $bridgeMock, $this->diContainer->get(NewslettersRepository::class)),
|
||||||
|
$this->diContainer->get(AuthorizedSenderDomainController::class),
|
||||||
$this->make(TransactionalEmails::class),
|
$this->make(TransactionalEmails::class),
|
||||||
WPFunctions::get(),
|
WPFunctions::get(),
|
||||||
$this->diContainer->get(EntityManager::class),
|
$this->diContainer->get(EntityManager::class),
|
||||||
@ -190,6 +195,7 @@ class SettingsTest extends \MailPoetTest {
|
|||||||
$this->settings,
|
$this->settings,
|
||||||
$bridgeMock,
|
$bridgeMock,
|
||||||
new AuthorizedEmailsController($this->settings, $bridgeMock, $this->diContainer->get(NewslettersRepository::class)),
|
new AuthorizedEmailsController($this->settings, $bridgeMock, $this->diContainer->get(NewslettersRepository::class)),
|
||||||
|
$this->diContainer->get(AuthorizedSenderDomainController::class),
|
||||||
$this->make(TransactionalEmails::class),
|
$this->make(TransactionalEmails::class),
|
||||||
WPFunctions::get(),
|
WPFunctions::get(),
|
||||||
$this->diContainer->get(EntityManager::class),
|
$this->diContainer->get(EntityManager::class),
|
||||||
|
@ -103,6 +103,7 @@
|
|||||||
'invalidEmail': __('Invalid email address'),
|
'invalidEmail': __('Invalid email address'),
|
||||||
'youNeedToAuthorizeTheEmail': __('You need to authorize the email address [email] to be able to send with it.'),
|
'youNeedToAuthorizeTheEmail': __('You need to authorize the email address [email] to be able to send with it.'),
|
||||||
'authorizeMyEmail': __('Authorize my email address'),
|
'authorizeMyEmail': __('Authorize my email address'),
|
||||||
|
'authorizeSenderDomain': __('Email violates Sender Domain’s DMARC policy. Please set up [link]sender authentication[/link].'),
|
||||||
|
|
||||||
'enableSignupConfTitle': __('Enable sign-up confirmation'),
|
'enableSignupConfTitle': __('Enable sign-up confirmation'),
|
||||||
'enableSignupConfDescription': __("If you enable this option, your subscribers will first receive a confirmation email after they subscribe. Once they confirm their subscription (via this email), they will be marked as 'confirmed' and will begin to receive your email newsletters."),
|
'enableSignupConfDescription': __("If you enable this option, your subscribers will first receive a confirmation email after they subscribe. Once they confirm their subscription (via this email), they will be marked as 'confirmed' and will begin to receive your email newsletters."),
|
||||||
|
Reference in New Issue
Block a user