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,
|
||||
mssActive,
|
||||
isEmailAuthorized,
|
||||
showSenderDomainWarning,
|
||||
}) {
|
||||
const [showAuthorizedEmailModal, setShowAuthorizedEmailModal] =
|
||||
useState(false);
|
||||
@ -21,6 +22,8 @@ function SenderEmailAddressWarning({
|
||||
setShowAuthorizedEmailModal(true);
|
||||
};
|
||||
|
||||
const emailAddressDomain = emailAddress.split('@').pop().toLowerCase();
|
||||
|
||||
if (mssActive) {
|
||||
if (!isEmailAuthorized) {
|
||||
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;
|
||||
}
|
||||
const emailAddressDomain = emailAddress.split('@').pop().toLowerCase();
|
||||
if (window.mailpoet_free_domains.indexOf(emailAddressDomain) > -1) {
|
||||
return (
|
||||
<>
|
||||
@ -100,10 +136,12 @@ SenderEmailAddressWarning.propTypes = {
|
||||
emailAddress: PropTypes.string.isRequired,
|
||||
mssActive: PropTypes.bool.isRequired,
|
||||
isEmailAuthorized: PropTypes.bool,
|
||||
showSenderDomainWarning: PropTypes.bool,
|
||||
};
|
||||
|
||||
SenderEmailAddressWarning.defaultProps = {
|
||||
isEmailAuthorized: true, // don't show error message by default
|
||||
showSenderDomainWarning: false,
|
||||
};
|
||||
|
||||
export { SenderEmailAddressWarning };
|
||||
|
@ -1,15 +1,30 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { MailPoet } from 'mailpoet';
|
||||
import { Label, Inputs } from 'settings/components';
|
||||
import { isEmail, t, onChange, setLowercaseValue } from 'common/functions';
|
||||
import { Input } from 'common/form/input/input';
|
||||
import { useSetting, useSelector, useAction } from 'settings/store/hooks';
|
||||
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() {
|
||||
const isMssActive = useSelector('isMssActive')();
|
||||
const [senderName, setSenderName] = useSetting('sender', 'name');
|
||||
const [senderEmail, setSenderEmail] = useSetting('sender', 'address');
|
||||
const [isAuthorized, setIsAuthorized] = useState(true);
|
||||
const [showSenderDomainWarning, setShowSenderDomainWarning] = useState(false);
|
||||
const [replyToName, setReplyToName] = useSetting('reply_to', 'name');
|
||||
const [replyToEmail, setReplyToEmail] = useSetting('reply_to', 'address');
|
||||
const setErrorFlag = useAction('setErrorFlag');
|
||||
@ -22,6 +37,36 @@ export function DefaultSender() {
|
||||
}
|
||||
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) => {
|
||||
setIsAuthorized(true);
|
||||
setSenderEmail(email);
|
||||
@ -66,7 +111,7 @@ export function DefaultSender() {
|
||||
data-automation-id="from-email-field"
|
||||
value={senderEmail}
|
||||
onChange={onChange(setLowercaseValue(updateSenderEmailController))}
|
||||
onBlur={onChange(isAuthorizedEmail)}
|
||||
onBlur={onChange(performActionOnBlur)}
|
||||
/>
|
||||
<br />
|
||||
{invalidSenderEmail && (
|
||||
@ -79,6 +124,7 @@ export function DefaultSender() {
|
||||
emailAddress={senderEmail}
|
||||
mssActive={isMssActive}
|
||||
isEmailAuthorized={isAuthorized}
|
||||
showSenderDomainWarning={showSenderDomainWarning}
|
||||
/>
|
||||
</div>
|
||||
<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\Segments\SegmentsRepository;
|
||||
use MailPoet\Services\AuthorizedEmailsController;
|
||||
use MailPoet\Services\AuthorizedSenderDomainController;
|
||||
use MailPoet\Services\Bridge;
|
||||
use MailPoet\Settings\SettingsChangeHandler;
|
||||
use MailPoet\Settings\SettingsController;
|
||||
@ -37,6 +38,9 @@ class Settings extends APIEndpoint {
|
||||
/** @var AuthorizedEmailsController */
|
||||
private $authorizedEmailsController;
|
||||
|
||||
/** @var AuthorizedSenderDomainController */
|
||||
private $senderDomainController;
|
||||
|
||||
/** @var TransactionalEmails */
|
||||
private $wcTransactionalEmails;
|
||||
|
||||
@ -80,6 +84,7 @@ class Settings extends APIEndpoint {
|
||||
SettingsController $settings,
|
||||
Bridge $bridge,
|
||||
AuthorizedEmailsController $authorizedEmailsController,
|
||||
AuthorizedSenderDomainController $senderDomainController,
|
||||
TransactionalEmails $wcTransactionalEmails,
|
||||
WPFunctions $wp,
|
||||
EntityManager $entityManager,
|
||||
@ -96,6 +101,7 @@ class Settings extends APIEndpoint {
|
||||
$this->settings = $settings;
|
||||
$this->bridge = $bridge;
|
||||
$this->authorizedEmailsController = $authorizedEmailsController;
|
||||
$this->senderDomainController = $senderDomainController;
|
||||
$this->wcTransactionalEmails = $wcTransactionalEmails;
|
||||
$this->servicesChecker = $servicesChecker;
|
||||
$this->wp = $wp;
|
||||
@ -246,6 +252,22 @@ class Settings extends APIEndpoint {
|
||||
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) {
|
||||
// Recalculate inactive subscribers
|
||||
$oldInactivationInterval = $oldSettings['deactivate_subscriber_after_inactive_days'];
|
||||
|
@ -19,6 +19,7 @@ use MailPoet\Newsletter\NewslettersRepository;
|
||||
use MailPoet\Newsletter\Sending\ScheduledTasksRepository;
|
||||
use MailPoet\Segments\SegmentsRepository;
|
||||
use MailPoet\Services\AuthorizedEmailsController;
|
||||
use MailPoet\Services\AuthorizedSenderDomainController;
|
||||
use MailPoet\Services\Bridge;
|
||||
use MailPoet\Settings\SettingsChangeHandler;
|
||||
use MailPoet\Settings\SettingsController;
|
||||
@ -53,6 +54,7 @@ class SettingsTest extends \MailPoetTest {
|
||||
$this->settings,
|
||||
new Bridge,
|
||||
$this->make(AuthorizedEmailsController::class, ['onSettingsSave' => null ]),
|
||||
$this->diContainer->get(AuthorizedSenderDomainController::class),
|
||||
$this->make(TransactionalEmails::class),
|
||||
WPFunctions::get(),
|
||||
$this->diContainer->get(EntityManager::class),
|
||||
@ -96,6 +98,7 @@ class SettingsTest extends \MailPoetTest {
|
||||
$this->settings,
|
||||
$this->make(Bridge::class, ['onSettingsSave' => Expected::once()]),
|
||||
$this->make(AuthorizedEmailsController::class, ['onSettingsSave' => Expected::once()]),
|
||||
$this->diContainer->get(AuthorizedSenderDomainController::class),
|
||||
$this->make(TransactionalEmails::class),
|
||||
WPFunctions::get(),
|
||||
$this->diContainer->get(EntityManager::class),
|
||||
@ -130,6 +133,7 @@ class SettingsTest extends \MailPoetTest {
|
||||
$this->settings,
|
||||
$bridgeMock,
|
||||
new AuthorizedEmailsController($this->settings, $bridgeMock, $this->diContainer->get(NewslettersRepository::class)),
|
||||
$this->diContainer->get(AuthorizedSenderDomainController::class),
|
||||
$this->make(TransactionalEmails::class),
|
||||
WPFunctions::get(),
|
||||
$this->diContainer->get(EntityManager::class),
|
||||
@ -159,6 +163,7 @@ class SettingsTest extends \MailPoetTest {
|
||||
$this->settings,
|
||||
$bridgeMock,
|
||||
new AuthorizedEmailsController($this->settings, $bridgeMock, $this->diContainer->get(NewslettersRepository::class)),
|
||||
$this->diContainer->get(AuthorizedSenderDomainController::class),
|
||||
$this->make(TransactionalEmails::class),
|
||||
WPFunctions::get(),
|
||||
$this->diContainer->get(EntityManager::class),
|
||||
@ -190,6 +195,7 @@ class SettingsTest extends \MailPoetTest {
|
||||
$this->settings,
|
||||
$bridgeMock,
|
||||
new AuthorizedEmailsController($this->settings, $bridgeMock, $this->diContainer->get(NewslettersRepository::class)),
|
||||
$this->diContainer->get(AuthorizedSenderDomainController::class),
|
||||
$this->make(TransactionalEmails::class),
|
||||
WPFunctions::get(),
|
||||
$this->diContainer->get(EntityManager::class),
|
||||
|
@ -103,6 +103,7 @@
|
||||
'invalidEmail': __('Invalid email address'),
|
||||
'youNeedToAuthorizeTheEmail': __('You need to authorize the email address [email] to be able to send with it.'),
|
||||
'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'),
|
||||
'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