PluginProbe ʕ •ᴥ•ʔ
MailPoet – Newsletters, Email Marketing, and Automation / 5.34.2
MailPoet – Newsletters, Email Marketing, and Automation v5.34.2
5.34.3 5.34.2 5.34.1 5.34.0 5.33.1 5.33.0 5.32.0 5.31.0 5.30.0 5.29.0 5.28.1 5.28.0 5.27.0 5.26.0 5.26.1 5.25.0 5.24.0 4.43.0 4.43.1 4.44.0 4.44.1 4.45.0 4.46.0 4.47.0 4.48.0 4.48.1 4.48.2 4.49.0 4.49.1 4.5.0 4.5.1 4.5.2 4.50.0 4.50.1 4.51.0 4.51.1 4.51.2 4.52.0 4.53.0 4.54.0 4.55.0 4.56.0 4.57.0 4.58.0 4.58.1 4.58.2 4.6.0 4.6.1 4.6.2 4.7.0 4.7.1 4.8.0 4.8.1 4.9.0 5.0.0 5.0.1 5.0.2 5.1.0 5.1.1 5.10.0 5.10.1 5.11.0 5.12.0 5.12.1 5.12.10 5.12.11 5.12.12 5.12.13 5.12.2 5.12.3 5.12.4 5.12.5 5.12.6 5.12.7 5.12.8 5.12.9 5.13.0 5.13.1 5.13.2 5.14.0 5.14.1 5.14.2 5.14.3 5.15.0 5.15.1 5.16.0 5.16.1 5.16.2 5.16.3 5.16.4 5.17.0 5.17.1 5.17.2 5.17.3 5.17.4 5.17.5 5.17.6 5.18.0 5.19.0 5.2.0 5.2.1 5.2.2 5.2.3 5.20.0 5.21.0 5.21.1 5.21.2 5.21.3 5.22.0 5.22.1 5.22.2 5.22.3 5.22.4 5.23.0 5.23.1 5.23.2 5.3.0 5.3.1 5.3.2 5.3.3 5.3.4 5.3.5 5.3.6 5.3.7 5.4.0 5.4.1 5.4.2 5.5.0 5.5.1 5.5.2 5.6.0 5.6.1 5.6.2 5.6.3 5.6.4 5.7.0 5.7.1 5.8.0 5.8.1 5.9.0 3.0.0-beta.15 3.7.1 3.0.0-beta.16 3.7.2 3.0.0-beta.17 3.7.3 3.0.0-beta.18 3.7.4 3.0.0-beta.19 3.7.5 3.0.0-beta.2 3.7.6 3.0.0-beta.20 3.7.8 3.0.0-beta.21 3.70.0 3.0.0-beta.22 3.71.0 3.0.0-beta.23 3.71.1 3.0.0-beta.23.1 3.71.2 3.0.0-beta.23.2 3.71.3 3.0.0-beta.24 3.72.0 3.0.0-beta.25 3.73.0 3.0.0-beta.26 3.73.1 3.0.0-beta.27 3.73.2 3.0.0-beta.28 3.74.0 3.0.0-beta.29 3.74.1 3.0.0-beta.3 3.74.2 3.0.0-beta.30 3.74.3 3.0.0-beta.31 3.75.0 3.0.0-beta.32 3.75.1 3.0.0-beta.33 3.76.0 3.0.0-beta.33.1 3.77.0 3.0.0-beta.34.0.0 3.77.1 3.0.0-beta.36.0.0 3.78.0 3.0.0-beta.36.0.1 3.79.0 3.0.0-beta.36.2.0 3.8 3.0.0-beta.36.3.0 3.8.1 3.0.0-beta.36.3.1 3.8.2 3.0.0-beta.37.0.0 3.8.3 3.0.0-beta.4 3.8.4 3.0.0-beta.5 3.8.5 3.0.0-beta.6 3.8.6 3.0.0-beta.7 3.80.0 3.0.0-beta.7.1 3.81.0 3.0.0-beta.8 3.82.0 3.0.0-beta.9 3.83.0 3.0.0-rc.1.0.0 3.84.0 3.0.0-rc.1.0.1 3.84.1 3.0.0-rc.1.0.2 3.85.0 3.0.0-rc.1.0.3 3.85.1 3.0.0-rc.1.0.4 3.86.0 3.0.0-rc.2.0.0 3.87.0 3.0.0-rc.2.0.1 3.87.1 3.0.0-rc.2.0.2 3.87.2 3.0.0-rc.2.0.3 3.88.0 3.0.1 3.88.1 3.0.2 3.88.2 3.0.3 3.89.0 3.0.4 3.89.1 3.0.5 3.89.2 3.0.6 3.89.3 3.0.7 3.89.4 3.0.8 3.9.0 3.0.9 3.9.1 3.1.0 3.90.0 3.10 3.90.1 3.10.1 3.90.2 3.100.0 3.91.0 3.100.1 3.91.1 3.100.2 3.92.0 3.101.0 3.92.1 3.101.1 3.93.0 3.102.0 3.93.1 3.102.1 3.94.0 3.103.0 3.95.0 3.103.1 3.95.1 3.11.0 3.96.0 3.11.1 3.96.1 3.11.2 3.97.0 3.11.3 3.98.0 3.11.4 3.98.1 3.11.5 3.99.0 3.12.0 3.99.1 3.12.1 4.0.0 3.13.0 4.0.1 3.14.0 4.1.0 3.14.1 4.1.1 3.15.0 4.10.0 3.16.0 4.11.0 3.16.1 4.11.1 3.16.2 4.12.0 3.16.3 4.12.1 3.17.0 4.12.2 3.17.1 4.13.0 3.17.2 4.14.0 3.18.0 4.15.0 3.18.1 4.16.0 3.18.2 4.17.0 3.19.0 4.17.1 3.19.1 4.18.0 3.19.2 4.18.1 3.19.3 4.19.0 3.2.0 4.2.0 3.2.1 4.20.0 3.2.2 4.20.1 3.2.3 4.20.2 3.2.4 4.21.0 3.2.5 4.22.0 3.20.0 4.22.1 3.21.0 4.22.2 3.21.1 4.23.0 3.22.0 4.24.0 3.23.0 4.25.0 3.23.1 4.26.0 3.23.2 4.26.1 3.24.0 4.27.0 3.25.0 4.28.0 3.25.1 4.29.0 3.26.0 4.3.0 3.26.1 4.3.1 3.27.0 4.30.0 3.28.0 4.31.0 3.29.0 4.31.1 3.3.0 4.32.0 3.3.1 4.33.0 3.3.2 4.34.0 3.3.3 4.35.0 3.3.4 4.35.1 3.3.5 4.36.0 3.3.6 4.37.0 3.30.0 4.38.0 3.31.0 4.39.0 3.31.1 4.4.0 3.32.0 4.40.0 3.32.1 4.41.0 3.32.2 4.41.1 3.33.0 4.41.2 3.34.0 4.41.3 3.34.1 4.42.0 3.34.2 4.42.1 3.34.3 3.34.4 3.35.0 3.35.1 3.35.3 3.35.4 3.36.0 3.37.0 3.37.1 3.37.2 3.37.3 3.38.0 3.38.1 3.39.0 3.39.1 3.39.2 3.4.0 3.4.1 3.4.2 3.4.3 3.4.4 3.40.0 3.40.1 3.41.0 3.41.1 3.41.2 3.42.0 3.42.1 3.42.2 3.42.3 3.43.0 3.43.1 3.44.0 3.45.0 3.45.1 3.46.0 3.46.1 3.46.10 3.46.11 3.46.12 3.46.13 3.46.14 3.46.2 3.46.3 3.46.4 3.46.5 3.46.6 3.46.7 3.46.8 3.46.9 3.47.0 3.47.1 3.47.10 3.47.11 3.47.2 3.47.3 3.47.5 3.47.6 3.47.7 3.47.9 3.48.0 3.48.1 3.49.0 3.49.1 3.5.0 3.5.1 3.50.0 3.51.0 3.51.1 3.51.2 3.52.0 3.53.0 3.54.0 3.54.1 3.54.2 3.54.3 3.55.0 3.55.1 3.56.0 3.56.1 3.56.2 3.57.0 3.57.1 3.58.0 3.59.0 3.59.1 3.59.2 3.6.0 3.6.1 3.6.2 3.6.3 3.6.4 3.6.5 3.6.6 3.6.7 3.60.0 3.60.1 3.60.10 3.60.11 3.60.12 3.60.2 3.60.3 3.60.4 3.60.6 3.60.7 3.60.8 3.60.9 3.61.0 3.62.0 3.62.1 3.63.0 3.64.0 3.64.1 3.64.2 3.64.3 3.65.0 trunk 3.65.1 3.0.0 3.66.0 3.0.0-beta.1 3.67.0 3.0.0-beta.10 3.67.1 3.0.0-beta.11 3.68.0 3.0.0-beta.12 3.69.0 3.0.0-beta.13 3.69.1 3.0.0-beta.14 3.7.0
mailpoet / lib / Mailer / Methods / ErrorMappers / MailPoetMapper.php
mailpoet / lib / Mailer / Methods / ErrorMappers Last commit date
AmazonSESMapper.php 3 years ago BlacklistErrorMapperTrait.php 3 years ago ConnectionErrorMapperTrait.php 3 years ago MailPoetMapper.php 1 year ago PHPMailMapper.php 4 years ago PHPMailerMapper.php 3 years ago SMTPMapper.php 4 years ago SendGridMapper.php 3 years ago index.php 3 years ago
MailPoetMapper.php
281 lines
1 <?php // phpcs:ignore SlevomatCodingStandard.TypeHints.DeclareStrictTypes.DeclareStrictTypesMissing
2
3 namespace MailPoet\Mailer\Methods\ErrorMappers;
4
5 if (!defined('ABSPATH')) exit;
6
7
8 use InvalidArgumentException;
9 use MailPoet\Config\ServicesChecker;
10 use MailPoet\Mailer\Mailer;
11 use MailPoet\Mailer\MailerError;
12 use MailPoet\Mailer\SubscriberError;
13 use MailPoet\Services\Bridge\API;
14 use MailPoet\Util\Helpers;
15 use MailPoet\Util\License\Features\Subscribers as SubscribersFeature;
16 use MailPoet\Util\Notices\PendingApprovalNotice;
17 use MailPoet\Util\Notices\UnauthorizedEmailNotice;
18 use MailPoet\WP\Functions as WPFunctions;
19 use MailPoetVendor\Carbon\Carbon;
20
21 class MailPoetMapper {
22 use BlacklistErrorMapperTrait;
23 use ConnectionErrorMapperTrait;
24
25 const METHOD = Mailer::METHOD_MAILPOET;
26
27 const TEMPORARY_UNAVAILABLE_RETRY_INTERVAL = 300; // seconds
28
29 /** @var ServicesChecker */
30 private $servicesChecker;
31
32 /** @var SubscribersFeature */
33 private $subscribersFeature;
34
35 /** @var WPFunctions */
36 private $wp;
37
38 /** @var PendingApprovalNotice */
39 private $pendingApprovalNotice;
40
41 public function __construct(
42 ServicesChecker $servicesChecker,
43 SubscribersFeature $subscribers,
44 WPFunctions $wp,
45 PendingApprovalNotice $pendingApprovalNotice
46 ) {
47 $this->servicesChecker = $servicesChecker;
48 $this->subscribersFeature = $subscribers;
49 $this->wp = $wp;
50 $this->pendingApprovalNotice = $pendingApprovalNotice;
51 }
52
53 public function getInvalidApiKeyError() {
54 return new MailerError(
55 MailerError::OPERATION_SEND,
56 MailerError::LEVEL_HARD,
57 __('MailPoet API key is invalid!', 'mailpoet')
58 );
59 }
60
61 public function getErrorForResult(array $result, $subscribers, $sender = null, $newsletter = null) {
62 $level = MailerError::LEVEL_HARD;
63 $operation = MailerError::OPERATION_SEND;
64 $retryInterval = null;
65 $subscribersErrors = [];
66 $resultCode = !empty($result['code']) ? $result['code'] : null;
67
68 switch ($resultCode) {
69 case API::RESPONSE_CODE_NOT_ARRAY:
70 $message = __('JSON input is not an array', 'mailpoet');
71 break;
72 case API::RESPONSE_CODE_PAYLOAD_ERROR:
73 $resultParsed = json_decode($result['message'], true);
74 $message = __('Error while sending.', 'mailpoet');
75
76 if (is_array($resultParsed)) {
77 try {
78 $subscribersErrors = $this->getSubscribersErrors($resultParsed, $subscribers);
79 $level = MailerError::LEVEL_SOFT;
80 } catch (InvalidArgumentException $e) {
81 $message .= ' ' . $e->getMessage();
82 }
83 break;
84 }
85
86 $appendedMessage = ' ' . $result['message'];
87 if (isset($result['error']) && in_array($result['error'], [API::ERROR_MESSAGE_DMRAC, API::ERROR_MESSAGE_BULK_EMAIL_FORBIDDEN])) {
88 $appendedMessage = $this->getDmarcMessage($result, $sender);
89
90 if ($result['error'] === API::ERROR_MESSAGE_BULK_EMAIL_FORBIDDEN) {
91 $operation = MailerError::OPERATION_DOMAIN_AUTHORIZATION;
92 $level = MailerError::LEVEL_SOFT;
93 }
94 }
95 $message .= $appendedMessage;
96 break;
97 case API::RESPONSE_CODE_INTERNAL_SERVER_ERROR:
98 case API::RESPONSE_CODE_BAD_GATEWAY:
99 case API::RESPONSE_CODE_TEMPORARY_UNAVAILABLE:
100 case API::RESPONSE_CODE_GATEWAY_TIMEOUT:
101 $message = __('Email service is temporarily not available, please try again in a few minutes.', 'mailpoet');
102 $retryInterval = self::TEMPORARY_UNAVAILABLE_RETRY_INTERVAL;
103 break;
104 case API::RESPONSE_CODE_CAN_NOT_SEND:
105 [$operation, $message] = $this->getCanNotSendError($result, $sender);
106 break;
107 case API::RESPONSE_CODE_KEY_INVALID:
108 case API::RESPONSE_CODE_PAYLOAD_TOO_BIG:
109 default:
110 $message = $result['message'];
111 }
112 return new MailerError($operation, $level, $message, $retryInterval, $subscribersErrors);
113 }
114
115 private function getSubscribersErrors($resultParsed, $subscribers) {
116 $errors = [];
117 foreach ($resultParsed as $resultError) {
118 if (!is_array($resultError) || !isset($resultError['index']) || !isset($subscribers[$resultError['index']])) {
119 throw new InvalidArgumentException(__('Invalid MSS response format.', 'mailpoet'));
120 }
121 $subscriberErrors = [];
122 if (isset($resultError['errors']) && is_array($resultError['errors'])) {
123 array_walk_recursive($resultError['errors'], function($item) use (&$subscriberErrors) {
124 $subscriberErrors[] = $item;
125 });
126 }
127 $message = join(', ', $subscriberErrors);
128 $errors[] = new SubscriberError($subscribers[$resultError['index']], $message);
129 }
130 return $errors;
131 }
132
133 private function getUnauthorizedEmailMessage($sender) {
134 $email = $sender ? $sender['from_email'] : __('Unknown address', 'mailpoet');
135 $validationError = ['invalid_sender_address' => $email];
136 $notice = new UnauthorizedEmailNotice($this->wp, null);
137 $message = $notice->getMessage($validationError);
138 return $message;
139 }
140
141 private function getSubscribersLimitReachedMessage(): string {
142 $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');
143 $message = Helpers::replaceLinkTags(
144 $message,
145 'https://account.mailpoet.com/account/',
146 [
147 'target' => '_blank',
148 'rel' => 'noopener noreferrer',
149 ],
150 'link1'
151 );
152 $message = Helpers::replaceLinkTags(
153 $message,
154 'https://www.mailpoet.com/support/',
155 [
156 'target' => '_blank',
157 'rel' => 'noopener noreferrer',
158 ],
159 'link2'
160 );
161
162 return "{$message}<br/>";
163 }
164
165 private function getAccountBannedMessage(): string {
166 $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');
167 $message = Helpers::replaceLinkTags(
168 $message,
169 'https://kb.mailpoet.com/article/231-sending-does-not-work#suspended',
170 [
171 'target' => '_blank',
172 'rel' => 'noopener noreferrer',
173 ],
174 'link1'
175 );
176 $message = Helpers::replaceLinkTags(
177 $message,
178 'https://www.mailpoet.com/support-for-banned-users/',
179 [
180 'target' => '_blank',
181 'rel' => 'noopener noreferrer',
182 ],
183 'link2'
184 );
185
186 return "{$message}<br/>";
187 }
188
189 private function getDmarcMessage($result, $sender): string {
190 $messageToAppend = __('[link1]Click here to start the authentication[/link1].', 'mailpoet');
191 $senderEmail = $sender['from_email'] ?? '';
192
193 $appendMessage = Helpers::replaceLinkTags(
194 $messageToAppend,
195 '#',
196 [
197 'class' => 'mailpoet-js-button-authorize-email-and-sender-domain',
198 'data-email' => $senderEmail,
199 'data-type' => 'domain',
200 'rel' => 'noopener noreferrer',
201 ],
202 'link1'
203 );
204 $final = ' ' . $result['message'] . ' ' . $appendMessage;
205 return $final;
206 }
207
208 private function getEmailVolumeLimitReachedMessage(): string {
209 $partialApiKey = $this->servicesChecker->generatePartialApiKey();
210 $emailVolumeLimit = $this->subscribersFeature->getEmailVolumeLimit();
211 $date = Carbon::now()->startOfMonth()->addMonth();
212 if ($emailVolumeLimit) {
213 $message = sprintf(
214 // translators: %1$s is email volume limit and %2$s the date when you can resume sending.
215 __('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'),
216 $emailVolumeLimit,
217 $this->wp->dateI18n($this->wp->getOption('date_format'), $date->getTimestamp())
218 );
219 } else {
220 $message = sprintf(
221 // translators: %1$s the date when you can resume sending.
222 __('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'),
223 $this->wp->dateI18n($this->wp->getOption('date_format'), $date->getTimestamp())
224 );
225 }
226
227 $message = Helpers::replaceLinkTags(
228 $message,
229 "https://account.mailpoet.com/orders/upgrade/{$partialApiKey}",
230 [
231 'target' => '_blank',
232 'rel' => 'noopener noreferrer',
233 ]
234 );
235
236 return "{$message}<br/>";
237 }
238
239 /**
240 * Returns error $message and $operation for API::RESPONSE_CODE_CAN_NOT_SEND
241 */
242 private function getCanNotSendError(array $result, $sender): array {
243 if ($result['error'] === API::ERROR_MESSAGE_PENDING_APPROVAL) {
244 $operation = MailerError::OPERATION_PENDING_APPROVAL;
245 $message = $this->pendingApprovalNotice->getPendingApprovalMessage() . '<br/>';
246 return [$operation, $message];
247 }
248
249 // Backward compatibility for older blocked keys.
250 // Exceeded subscribers limit used to use the same error message as insufficient privileges.
251 // We can change the message to "Insufficient privileges" like wording a couple of months after releasing SHOP-1228
252 if ($result['error'] === API::ERROR_MESSAGE_INSUFFICIENT_PRIVILEGES) {
253 $operation = MailerError::OPERATION_INSUFFICIENT_PRIVILEGES;
254 $message = $this->getSubscribersLimitReachedMessage();
255 return [$operation, $message];
256 }
257
258 if ($result['error'] === API::ERROR_MESSAGE_SUBSCRIBERS_LIMIT_REACHED) {
259 $operation = MailerError::OPERATION_SUBSCRIBER_LIMIT_REACHED;
260 $message = $this->getSubscribersLimitReachedMessage();
261 return [$operation, $message];
262 }
263
264 if ($result['error'] === API::ERROR_MESSAGE_EMAIL_VOLUME_LIMIT_REACHED) {
265 $operation = MailerError::OPERATION_EMAIL_LIMIT_REACHED;
266 $message = $this->getEmailVolumeLimitReachedMessage();
267 return [$operation, $message];
268 }
269
270 if ($result['error'] === API::ERROR_MESSAGE_INVALID_FROM) {
271 $operation = MailerError::OPERATION_AUTHORIZATION;
272 $message = $this->getUnauthorizedEmailMessage($sender);
273 return [$operation, $message];
274 }
275
276 $message = $this->getAccountBannedMessage();
277 $operation = MailerError::OPERATION_SEND;
278 return [$operation, $message];
279 }
280 }
281