OwlCyberSecurity - MANAGER
Edit File: MailPoetMapper.php
<?php // phpcs:ignore SlevomatCodingStandard.TypeHints.DeclareStrictTypes.DeclareStrictTypesMissing namespace MailPoet\Mailer\Methods\ErrorMappers; if (!defined('ABSPATH')) exit; use InvalidArgumentException; use MailPoet\Config\ServicesChecker; use MailPoet\Mailer\Mailer; use MailPoet\Mailer\MailerError; use MailPoet\Mailer\SubscriberError; use MailPoet\Services\Bridge\API; use MailPoet\Util\Helpers; use MailPoet\Util\License\Features\Subscribers as SubscribersFeature; use MailPoet\Util\Notices\PendingApprovalNotice; use MailPoet\Util\Notices\UnauthorizedEmailNotice; use MailPoet\WP\Functions as WPFunctions; use MailPoetVendor\Carbon\Carbon; class MailPoetMapper { use BlacklistErrorMapperTrait; use ConnectionErrorMapperTrait; const METHOD = Mailer::METHOD_MAILPOET; const TEMPORARY_UNAVAILABLE_RETRY_INTERVAL = 300; // seconds /** @var ServicesChecker */ private $servicesChecker; /** @var SubscribersFeature */ private $subscribersFeature; /** @var WPFunctions */ private $wp; /** @var PendingApprovalNotice */ private $pendingApprovalNotice; public function __construct( ServicesChecker $servicesChecker, SubscribersFeature $subscribers, WPFunctions $wp, PendingApprovalNotice $pendingApprovalNotice ) { $this->servicesChecker = $servicesChecker; $this->subscribersFeature = $subscribers; $this->wp = $wp; $this->pendingApprovalNotice = $pendingApprovalNotice; } public function getInvalidApiKeyError() { return new MailerError( MailerError::OPERATION_SEND, MailerError::LEVEL_HARD, __('MailPoet API key is invalid!', 'mailpoet') ); } public function getErrorForResult(array $result, $subscribers, $sender = null, $newsletter = null) { $level = MailerError::LEVEL_HARD; $operation = MailerError::OPERATION_SEND; $retryInterval = null; $subscribersErrors = []; $resultCode = !empty($result['code']) ? $result['code'] : null; switch ($resultCode) { case API::RESPONSE_CODE_NOT_ARRAY: $message = __('JSON input is not an array', 'mailpoet'); break; case API::RESPONSE_CODE_PAYLOAD_ERROR: $resultParsed = json_decode($result['message'], true); $message = __('Error while sending.', 'mailpoet'); if (is_array($resultParsed)) { try { $subscribersErrors = $this->getSubscribersErrors($resultParsed, $subscribers); $level = MailerError::LEVEL_SOFT; } catch (InvalidArgumentException $e) { $message .= ' ' . $e->getMessage(); } break; } $appendedMessage = ' ' . $result['message']; if (isset($result['error']) && in_array($result['error'], [API::ERROR_MESSAGE_DMRAC, API::ERROR_MESSAGE_BULK_EMAIL_FORBIDDEN])) { $appendedMessage = $this->getDmarcMessage($result, $sender); if ($result['error'] === API::ERROR_MESSAGE_BULK_EMAIL_FORBIDDEN) { $operation = MailerError::OPERATION_DOMAIN_AUTHORIZATION; $level = MailerError::LEVEL_SOFT; } } $message .= $appendedMessage; break; case API::RESPONSE_CODE_INTERNAL_SERVER_ERROR: case API::RESPONSE_CODE_BAD_GATEWAY: case API::RESPONSE_CODE_TEMPORARY_UNAVAILABLE: case API::RESPONSE_CODE_GATEWAY_TIMEOUT: $message = __('Email service is temporarily not available, please try again in a few minutes.', 'mailpoet'); $retryInterval = self::TEMPORARY_UNAVAILABLE_RETRY_INTERVAL; break; case API::RESPONSE_CODE_CAN_NOT_SEND: [$operation, $message] = $this->getCanNotSendError($result, $sender); break; case API::RESPONSE_CODE_KEY_INVALID: case API::RESPONSE_CODE_PAYLOAD_TOO_BIG: default: $message = $result['message']; } return new MailerError($operation, $level, $message, $retryInterval, $subscribersErrors); } private function getSubscribersErrors($resultParsed, $subscribers) { $errors = []; foreach ($resultParsed as $resultError) { if (!is_array($resultError) || !isset($resultError['index']) || !isset($subscribers[$resultError['index']])) { throw new InvalidArgumentException(__('Invalid MSS response format.', 'mailpoet')); } $subscriberErrors = []; if (isset($resultError['errors']) && is_array($resultError['errors'])) { array_walk_recursive($resultError['errors'], function($item) use (&$subscriberErrors) { $subscriberErrors[] = $item; }); } $message = join(', ', $subscriberErrors); $errors[] = new SubscriberError($subscribers[$resultError['index']], $message); } return $errors; } private function getUnauthorizedEmailMessage($sender) { $email = $sender ? $sender['from_email'] : __('Unknown address', 'mailpoet'); $validationError = ['invalid_sender_address' => $email]; $notice = new UnauthorizedEmailNotice($this->wp, null); $message = $notice->getMessage($validationError); return $message; } private function getSubscribersLimitReachedMessage(): string { $message = __('You have reached the subscriber limit of your plan. Please [link1]upgrade your plan[/link1], or [link2]contact our support team[/link2] if you have any questions.', 'mailpoet'); $message = Helpers::replaceLinkTags( $message, 'https://account.mailpoet.com/account/', [ 'target' => '_blank', 'rel' => 'noopener noreferrer', ], 'link1' ); $message = Helpers::replaceLinkTags( $message, 'https://www.mailpoet.com/support/', [ 'target' => '_blank', 'rel' => 'noopener noreferrer', ], 'link2' ); return "{$message}<br/>"; } private function getAccountBannedMessage(): string { $message = __('The MailPoet Sending Service has been temporarily suspended for your site due to a high number of [link1]undeliverable emails or emails marked as unwanted by recipients[/link1]. Please [link2]contact our support team[/link2] to resolve the issue.', 'mailpoet'); $message = Helpers::replaceLinkTags( $message, 'https://kb.mailpoet.com/article/231-sending-does-not-work#suspended', [ 'target' => '_blank', 'rel' => 'noopener noreferrer', ], 'link1' ); $message = Helpers::replaceLinkTags( $message, 'https://www.mailpoet.com/support-for-banned-users/', [ 'target' => '_blank', 'rel' => 'noopener noreferrer', ], 'link2' ); return "{$message}<br/>"; } private function getDmarcMessage($result, $sender): string { $messageToAppend = __('[link1]Click here to start the authentication[/link1].', 'mailpoet'); $senderEmail = $sender['from_email'] ?? ''; $appendMessage = Helpers::replaceLinkTags( $messageToAppend, '#', [ 'class' => 'mailpoet-js-button-authorize-email-and-sender-domain', 'data-email' => $senderEmail, 'data-type' => 'domain', 'rel' => 'noopener noreferrer', ], 'link1' ); $final = ' ' . $result['message'] . ' ' . $appendMessage; return $final; } private function getEmailVolumeLimitReachedMessage(): string { $partialApiKey = $this->servicesChecker->generatePartialApiKey(); $emailVolumeLimit = $this->subscribersFeature->getEmailVolumeLimit(); $date = Carbon::now()->startOfMonth()->addMonth(); if ($emailVolumeLimit) { $message = sprintf( // translators: %1$s is email volume limit and %2$s the date when you can resume sending. __('You have sent more emails this month than your MailPoet plan includes (%1$s), and sending has been temporarily paused. To continue sending with MailPoet Sending Service please [link]upgrade your plan[/link], or wait until sending is automatically resumed on %2$s.', 'mailpoet'), $emailVolumeLimit, $this->wp->dateI18n($this->wp->getOption('date_format'), $date->getTimestamp()) ); } else { $message = sprintf( // translators: %1$s the date when you can resume sending. __('You have sent more emails this month than your MailPoet plan includes, and sending has been temporarily paused. To continue sending with MailPoet Sending Service please [link]upgrade your plan[/link], or wait until sending is automatically resumed on %1$s.', 'mailpoet'), $this->wp->dateI18n($this->wp->getOption('date_format'), $date->getTimestamp()) ); } $message = Helpers::replaceLinkTags( $message, "https://account.mailpoet.com/orders/upgrade/{$partialApiKey}", [ 'target' => '_blank', 'rel' => 'noopener noreferrer', ] ); return "{$message}<br/>"; } /** * Returns error $message and $operation for API::RESPONSE_CODE_CAN_NOT_SEND */ private function getCanNotSendError(array $result, $sender): array { if ($result['error'] === API::ERROR_MESSAGE_PENDING_APPROVAL) { $operation = MailerError::OPERATION_PENDING_APPROVAL; $message = $this->pendingApprovalNotice->getPendingApprovalMessage() . '<br/>'; return [$operation, $message]; } // Backward compatibility for older blocked keys. // Exceeded subscribers limit used to use the same error message as insufficient privileges. // We can change the message to "Insufficient privileges" like wording a couple of months after releasing SHOP-1228 if ($result['error'] === API::ERROR_MESSAGE_INSUFFICIENT_PRIVILEGES) { $operation = MailerError::OPERATION_INSUFFICIENT_PRIVILEGES; $message = $this->getSubscribersLimitReachedMessage(); return [$operation, $message]; } if ($result['error'] === API::ERROR_MESSAGE_SUBSCRIBERS_LIMIT_REACHED) { $operation = MailerError::OPERATION_SUBSCRIBER_LIMIT_REACHED; $message = $this->getSubscribersLimitReachedMessage(); return [$operation, $message]; } if ($result['error'] === API::ERROR_MESSAGE_EMAIL_VOLUME_LIMIT_REACHED) { $operation = MailerError::OPERATION_EMAIL_LIMIT_REACHED; $message = $this->getEmailVolumeLimitReachedMessage(); return [$operation, $message]; } if ($result['error'] === API::ERROR_MESSAGE_INVALID_FROM) { $operation = MailerError::OPERATION_AUTHORIZATION; $message = $this->getUnauthorizedEmailMessage($sender); return [$operation, $message]; } $message = $this->getAccountBannedMessage(); $operation = MailerError::OPERATION_SEND; return [$operation, $message]; } }