PluginProbe
AcyMailing – An Ultimate Newsletter Plugin and Marketing Automation Solution for WordPress / 11.1.0
AcyMailing – An Ultimate Newsletter Plugin and Marketing Automation Solution for WordPress v11.1.0
11.1.1 11.1.0 11.0.5 11.0.4 11.0.3 11.0.2 11.0.1 11.0.0 10.11.1 10.11.0 10.10.2 10.10.1 10.10.0 10.9.1 trunk 10.0.0 10.0.1 10.1.0 10.1.1 10.1.2 10.1.3 10.1.4 10.2.0 10.2.1 10.2.2 All 62 releases
← All changes | back/dynamics/acymailer/plugin.php +1299 -0 11.1.1 → 11.1.0 View file →
@@ -1,0 +1,1299 @@
1 +<?php
2 +
3 +use AcyMailing\Classes\MailClass;
4 +use AcyMailing\Classes\QueueClass;
5 +use AcyMailing\Core\AcymPlugin;
6 +
7 +class plgAcymAcymailer extends AcymPlugin
8 +{
9 + const SENDING_METHOD_ID = 'acymailer';
10 + const SENDING_METHOD_NAME = 'AcyMailing sending service';
11 + const SENDING_METHOD_API_URL = 'https://api.acymailer.com/';
12 + const CREDITS_RELOAD_DELAY = 900;
13 + const TRANSLATIONS = [
14 + 0 => 'ACYM_ERROR_SEE_LOGS',
15 + 1 => 'ACYM_PLEASE_INSTALL_LATEST_VERSION',
16 + 2 => 'ACYM_EMAIL_SEND_FAIL_SEE_LOGS',
17 + 3 => 'ACYM_DOMAIN_NOT_ATTACHED_TO_THE_SITE',
18 + 4 => 'ACYM_NOT_ALLOWED_TO_DELETE_THIS_DOMAIN',
19 + 5 => 'ACYM_DOMAIN_DOES_NOT_EXIST',
20 + 6 => 'ACYM_DOMAIN_STATUS_SUCCESSFULLY_OBTAINED',
21 + 7 => 'ACYM_AN_ERROR_RELATED_TO_THE_REMAINING_CREDITS_OCCURRED',
22 + 8 => 'ACYM_LICENSE_EXPIRED',
23 + 9 => 'ACYM_IDENTITY_CREATED',
24 + 10 => 'ACYM_DOMAIN_ALREADY_EXISTS_FOR_THIS_WEBSITE',
25 + 11 => 'ACYM_DOMAIN_ALREADY_EXISTS_AND_DOES_NOT_BELONG_TO_YOU',
26 + 12 => 'ACYM_NO_DOMAINS_TO_CHECK',
27 + 13 => 'ACYM_DOMAINS_VERIFIED',
28 + 14 => 'ACYM_ERROR_WHILE_CHECKING_DOMAINS',
29 + 15 => 'ACYM_BLOCKED_LICENSE',
30 + 16 => 'ACYM_MISSING_EMAIL',
31 + 17 => 'ACYM_MISSING_ARGUMENTS',
32 + 18 => 'ACYM_NO_CREDITS_LEFT',
33 + 19 => 'ACYM_MISSING_API_KEY',
34 + 20 => 'ACYM_DOMAIN_NOT_FOUND',
35 + 21 => 'ACYM_LICENSE_NOT_FOUND',
36 + 22 => 'ACYM_EMAIL_SENT',
37 + 23 => 'ACYM_INVALID_API_KEY',
38 + 24 => 'ACYM_LICENSE_BLOCKED',
39 + 25 => 'ACYM_SEE_LOGS_FILE',
40 + 26 => 'ACYM_SERVICE_TEMPORARY_UNAVAILABLE',
41 + 27 => 'ACYM_DOMAIN_ONLY_ON_ONE_LICENSE',
42 + 28 => 'ACYM_EMAIL_UNDER_VERIFICATION',
43 + 29 => 'ACYM_DOMAIN_BLOCKED',
44 + 30 => 'ACYM_DOMAIN_UNDER_REVIEW',
45 + ];
46 +
47 + private array $errorCodes = [0, 1, 2, 3, 4, 5, 7, 8, 10, 11, 12, 14, 15, 16, 17, 18, 19, 20, 21, 23, 24, 25, 26, 27, 28, 29, 30];
48 + private array $cnameErrors = [];
49 +
50 + public function __construct()
51 + {
52 + parent::__construct();
53 + $this->pluginDescription->name = self::SENDING_METHOD_NAME;
54 + }
55 +
56 + protected function callApiSendingMethod(
57 + string $url,
58 + array $data = [],
59 + array $headers = [],
60 + string $type = 'GET',
61 + array $authentication = [],
62 + bool $dataDecoded = false,
63 + array $files = []
64 + ): array {
65 + if (strpos($url, self::SENDING_METHOD_API_URL) === false) {
66 + $url = self::SENDING_METHOD_API_URL.'api/'.$url;
67 + }
68 +
69 + $defaultHeaders = [
70 + 'Accept' => 'application/json',
71 + 'Content-Type' => 'application/json',
72 + 'API-KEY' => $this->config->get(self::SENDING_METHOD_ID.'_apikey', ''),
73 + 'Version' => $this->config->get('version'),
74 + ];
75 +
76 + $usedHeaders = array_map('strtolower', array_keys($headers));
77 + foreach ($defaultHeaders as $key => $value) {
78 + if (!in_array(strtolower($key), $usedHeaders, true)) {
79 + $headers[$key] = $value;
80 + }
81 + }
82 +
83 + $result = parent::callApiSendingMethod($url, $data, $headers, $type, $authentication, $dataDecoded, $files);
84 + if (!empty($result['error_curl'])) {
85 + $result['message'] = $result['error_curl'];
86 + $this->errors[] = $result['error_curl'];
87 + $this->errorCallback();
88 + } else {
89 + $result['message'] = $this->translate($result);
90 + }
91 +
92 + return $result;
93 + }
94 +
95 + public function onAcymGetSendingMethods(&$data, $isMailer = false)
96 + {
97 + $data['sendingMethods'][self::SENDING_METHOD_ID] = [
98 + 'name' => $this->pluginDescription->name,
99 + 'image' => ACYM_IMAGES.'mailers/'.self::SENDING_METHOD_ID.'.png',
100 + 'recommended' => true,
101 + 'image_class' => '',
102 + ];
103 + }
104 +
105 + public function onAcymAttachedLicenseOption()
106 + {
107 + $licenseKey = $this->config->get('license_key');
108 + $acyMailerKey = $this->config->get('acymailer_apikey');
109 + $mailerMethod = $this->config->get('mailer_method');
110 +
111 + if (empty($licenseKey) || empty($acyMailerKey) || $mailerMethod === self::SENDING_METHOD_ID) {
112 + return;
113 + }
114 + ?>
115 + <div class="grid-x grid-margin-x margin-top-1" id="activate_ass_method_notice">
116 + <label class="cell medium-7 acym_vcenter">
117 + <i class="acymicon-info-circle" id="acymailer_info_icon"></i>
118 + <?php echo esc_html(acym_translation('ACYM_ACTIVATE_ACYMAILER')); ?>
119 + </label>
120 + <button type="button"
121 + id="acym__configuration__activate__acymailer"
122 + class="cell shrink button margin-bottom-0">
123 + <?php echo esc_html(acym_translation('ACYM_SEE_THE_SENDING_METHOD')); ?>
124 + </button>
125 + </div>
126 + <?php
127 + }
128 +
129 + public function onAcymGetSendingMethodsHtmlSetting(&$data)
130 + {
131 + $licenseKey = $this->config->get('license_key');
132 + $acyMailerKey = $this->config->get('acymailer_apikey');
133 + $domains = $this->config->get(self::SENDING_METHOD_ID.'_domains', []);
134 + $domainsWaiting = [];
135 + if (!empty($domains)) {
136 + $domains = json_decode($domains, true);
137 + $domainsWaiting = array_filter($domains, function ($domain) {
138 + return $domain['status'] !== 'SUCCESS';
139 + });
140 + }
141 +
142 + $unverifiedDomains = $this->getDomainsUnVerified();
143 + ?>
144 + <div class="send_settings cell grid-x acym_vcenter" id="<?php echo esc_attr(self::SENDING_METHOD_ID); ?>_settings">
145 + <div class="cell grid-x acym__sending__methods__one__settings <?php echo empty($data['step']) ? 'xlarge-10 xxlarge-8' : ''; ?>">
146 + <?php if (!acym_level(ACYM_ESSENTIAL) && empty($data['step'])) { ?>
147 + <div class="acym_vcenter acym__config__acymailer__warning margin-top-1 cell grid-x large-8 xlarge-6 xxlarge-5">
148 + <label for="acym__configuration__license-key" class="cell">
149 + <?php echo esc_html(acym_translation('ACYM_YOUR_LICENSE_KEY')); ?>
150 + </label>
151 + <input type="text" name="config[license_key]" id="acym__configuration__license-key" class="cell auto" value="<?php echo esc_attr($licenseKey); ?>">
152 + <button type="button"
153 + id="acym__configuration__button__license"
154 + class="cell shrink medium-3 button margin-top-1 medium-margin-top-0 medium-margin-left-1"
155 + data-acym-linked="<?php echo empty($licenseKey) ? 0 : 1; ?>">
156 + <?php echo esc_html(acym_translation(empty($licenseKey) ? 'ACYM_ATTACH_MY_LICENSE' : 'ACYM_UNLINK_MY_LICENSE')); ?>
157 + </button>
158 + </div>
159 + <?php }
160 + if (empty($licenseKey)) { ?>
161 + <div class="cell acym_vcenter acym__config__acymailer__warning margin-top-1">
162 + <i class="acymicon-exclamation-triangle acym__color__orange"></i>
163 + <span class="margin-right-1">
164 + <?php
165 + $pricingPage = ACYM_ACYMAILING_WEBSITE.'pricing?utm_source=acymailing_plugin&utm_medium=sendingmethod&utm_campaign=purchase';
166 + echo esc_html(acym_translation(acym_level(ACYM_ESSENTIAL) ? 'ACYM_NO_LICENSE' : 'ACYM_NO_LICENSE_STARTER'));
167 + ?>
168 + <a target="_blank" href="<?php echo esc_url($pricingPage); ?>"><?php echo esc_html(acym_translation('ACYM_GET_A_LICENSE')); ?></a>
169 + </span>
170 + </div>
171 + <?php } elseif (empty($acyMailerKey)) { ?>
172 + <div class="cell acym_vcenter acym__config__acymailer__warning margin-top-1">
173 + <i class="acymicon-exclamation-triangle acym__color__orange"></i>
174 + <span>
175 + <?php
176 + $subscriptionsPage = ACYM_ACYMAILING_WEBSITE.'account/license?utm_source=acymailing_plugin&utm_medium=sendingmethod&utm_campaign=purchase';
177 + echo esc_html(acym_translation('ACYM_API_KEY_NOT_ALLOWING_METHOD'));
178 + ?>
179 + <a target="_blank" href="<?php echo esc_url($subscriptionsPage); ?>"><?php echo esc_html(
180 + acym_translation('ACYM_SWITCH_MY_LICENSE')
181 + ); ?></a>
182 + </span>
183 + </div>
184 +
185 + <div class="acym__configuration__acymailer__check-license cell grid-x">
186 + <div class="cell"><?php echo esc_html(acym_translation('ACYM_CHECK_SENDING_SERVICE_LICENSE')); ?></div>
187 + <button
188 + data-task="attachLicenseAcymailer"
189 + id="acym__configuration__acymailer__verify-license"
190 + class="cell medium-shrink button margin-left-0 margin-top-1 acy_button_submit">
191 + <?php echo esc_html(acym_translation('ACYM_CHECK_LICENSE')); ?>
192 + </button>
193 + </div>
194 + <?php } else { ?>
195 + <div class="cell grid-x">
196 + <?php if (!empty($domainsWaiting)) { ?>
197 + <div class="cell <?php echo empty($data['step']) ? 'large-8' : ''; ?> grid-x acym_vcenter acym__config__acymailer__warning">
198 + <i class="cell small-2 margin-right-0 acymicon-access-time acym__color__orange"></i>
199 + <div class="cell small-10 grid-x">
200 + <span class="cell"><?php echo esc_html(acym_translation('ACYM_DOMAINS_WAITING_VALIDATION_ADD_CNAME')); ?></span>
201 + <a href="<?php echo esc_url(
202 + ACYM_DOCUMENTATION
203 + ); ?>external-sending-method/acymailing-sending-service#how-to-add-the-dns-entries-on-my-server"
204 + target="_blank"
205 + class="cell">
206 + <?php echo esc_html(acym_translation('ACYM_CHECK_THIS_TUTORIAL')); ?>
207 + </a>
208 + </div>
209 + </div>
210 + <div class="cell <?php echo empty($data['step']) ? 'large-4' : ''; ?> margin-top-1 margin-bottom-1">
211 + <button id="acym__config__acymailer__update-domain-status"
212 + type="button"
213 + class="button button-secondary float-right"
214 + sending-method-id="<?php echo esc_attr(self::SENDING_METHOD_ID); ?>">
215 + <i class="acymicon-autorenew"></i><?php echo esc_html(acym_translation('ACYM_UPDATE_DOMAIN_STATUS')); ?>
216 + </button>
217 + </div>
218 + <?php } ?>
219 + </div>
220 + <div class="grid-x acym__listing cell">
221 + <div class="grid-x cell acym__listing__header">
222 + <div class="grid-x medium-auto small-11 cell acym__listing__header__title__container">
223 + <div class="cell small-8 medium-auto acym__listing__header__title">
224 + <?php echo esc_html(acym_translation('ACYM_DOMAIN_NAME')); ?>
225 + </div>
226 + <div class="cell hide-for-small-only medium-2 acym__listing__header__title text-center">
227 + <?php echo esc_html(acym_translation('ACYM_STATUS')); ?>
228 + </div>
229 + <div class="cell hide-for-small-only medium-2 acym__listing__header__title text-center">
230 + <?php echo esc_html(acym_translation('ACYM_BOUNCE_RATE'));
231 + acym_info(['textShownInTooltip' => 'ACYM_BOUNCE_RATE_DESC']); ?>
232 + </div>
233 + <div class="cell hide-for-small-only medium-2 acym__listing__header__title text-center">
234 + <?php echo esc_html(acym_translation('ACYM_COMPLAINT_RATE'));
235 + acym_info(['textShownInTooltip' => 'ACYM_COMPLAINT_RATE_DESC']); ?>
236 + </div>
237 + <div class="cell small-4 medium-2 acym__listing__header__title text-center">
238 + <?php echo esc_html(acym_translation('ACYM_ACTIONS')); ?>
239 + </div>
240 + </div>
241 + </div>
242 + <?php if (empty($domains)) { ?>
243 + <div class="grid-x cell margin-top-1 align-center">
244 + <?php echo esc_html(acym_translation('ACYM_NO_DOMAINS_YET')); ?>
245 + </div>
246 + <?php } else {
247 + foreach ($domains as &$domain) {
248 + $isValid = true;
249 + foreach ($domain['CnameRecords'] as $i => $cnameRecord) {
250 + $domain['CnameRecords'][$i]['isValid'] = $this->checkCnameEntry($cnameRecord['name'], $cnameRecord['value']);
251 + $isValid = $isValid && $domain['CnameRecords'][$i]['isValid'];
252 + $domain['CnameRecords'][$i]['tooltipMessages'] = $this->cnameErrors;
253 + $this->cnameErrors = [];
254 + }
255 +
256 + if (!$isValid && $domain['status'] === 'SUCCESS') {
257 + $domain['status'] = 'PENDING';
258 + $this->config->saveConfig([self::SENDING_METHOD_ID.'_domains' => json_encode($domains)]);
259 + }
260 +
261 + $bounceRateColorClass = $this->getRateColor(
262 + empty($domain['bounce_rate']) ? 0 : $domain['bounce_rate'],
263 + empty($domain['allowed_bounce_rate']) ? 0 : $domain['allowed_bounce_rate'],
264 + empty($domain['warning_bounce_rate']) ? 0 : $domain['warning_bounce_rate']
265 + );
266 + $complaintRateColorClass = $this->getRateColor(
267 + empty($domain['complaint_rate']) ? 0 : $domain['complaint_rate'],
268 + empty($domain['allowed_complaint_rate']) ? 0 : $domain['allowed_complaint_rate'],
269 + empty($domain['warning_complaint_rate']) ? 0 : $domain['warning_complaint_rate']
270 + );
271 + ?>
272 + <div acym-data-domain="<?php echo esc_attr($domain['domain']); ?>" class="grid-x cell align-middle acym__listing__row">
273 + <div class="cell small-6 medium-auto grid-x acym__listing__title__container">
274 + <?php echo esc_html($domain['domain']); ?>
275 + </div>
276 + <div class="cell small-1 medium-2 grid-x acym__listing__title__container align-center">
277 + <?php
278 + switch ($domain['status']) {
279 + case 'SUCCESS':
280 + $iconClass = 'acymicon-check-circle acym__color__green';
281 + $tooltipText = acym_translation('ACYM_VALIDATED');
282 + break;
283 + case 'FAILED':
284 + $iconClass = 'acymicon-close acym__color__red notValidated';
285 + $tooltipText = acym_translation('ACYM_APPROVAL_FAILED');
286 + break;
287 + default:
288 + $iconClass = 'acymicon-access-time acym__color__orange notValidated';
289 + $tooltipText = acym_translation('ACYM_A_CNAME_MISSING');
290 + }
291 +
292 + acym_tooltip(
293 + [
294 + 'hoveredText' => '<i class="acym__config__acymailer__status__icon '.$iconClass.'"></i>',
295 + 'textShownInTooltip' => $tooltipText,
296 + ]
297 + );
298 + ?>
299 + </div>
300 + <div class="cell hide-for-small-only medium-2 grid-x acym__listing__title__container align-center <?php echo esc_attr(
301 + $bounceRateColorClass
302 + ); ?>">
303 + <?php echo empty($domain['bounce_rate']) ? '-' : esc_html(round($domain['bounce_rate'], 2)).'%';
304 + $this->displayRateIcon(
305 + empty($domain['bounce_rate']) ? 0 : $domain['bounce_rate'],
306 + empty($domain['allowed_bounce_rate']) ? 0 : $domain['allowed_bounce_rate'],
307 + empty($domain['warning_bounce_rate']) ? 0 : $domain['warning_bounce_rate']
308 + );
309 + ?>
310 + </div>
311 + <div class="cell hide-for-small-only medium-2 grid-x acym__listing__title__container align-center <?php echo esc_attr(
312 + $complaintRateColorClass
313 + ); ?>">
314 + <?php echo empty($domain['complaint_rate']) ? '-' : esc_html(round($domain['complaint_rate'], 2)).'%';
315 + $this->displayRateIcon(
316 + empty($domain['complaint_rate']) ? 0 : $domain['complaint_rate'],
317 + empty($domain['allowed_complaint_rate']) ? 0 : $domain['allowed_complaint_rate'],
318 + empty($domain['warning_complaint_rate']) ? 0 : $domain['warning_complaint_rate']
319 + );
320 + ?>
321 + </div>
322 + <div class="cell small-4 medium-2 grid-x margin-left-1 medium-margin-left-0 acym__listing__title__container align-center">
323 + <?php ob_start(); ?>
324 + <div class="cell grid-x acym__config__acymailer__cname__modal">
325 + <h6 class="cell text-center margin-top-2 margin-bottom-1"><?php echo esc_html(acym_translation('ACYM_DNS_ENTRIES')); ?></h6>
326 + <div class="grid-x cell align-center margin-top-1 margin-bottom-2 acym_vcenter">
327 + <p class="cell shrink"><?php echo esc_html(acym_translation('ACYM_DO_NOT_KNOW_HOW_DO_IT')); ?> </p>
328 + <a href="<?php echo esc_url(
329 + ACYM_DOCUMENTATION
330 + ); ?>external-sending-method/acymailing-sending-service#how-to-add-the-dns-entries-on-my-server"
331 + class="cell shrink acym__config__acymailer__cname__modal__link"
332 + target="_blank">
333 + <?php echo esc_html(acym_translation('ACYM_STEP_BY_STEP_GUIDE')); ?>
334 + </a>
335 + </div>
336 + <div class="grid-x acym__listing cell">
337 + <div class="grid-x acym__listing cell">
338 + <div class="cell grid-x grid-margin-x margin-left-0 padding-bottom-1 acym__listing__header">
339 + <div class="cell small-10 hide-for-medium acym__listing__header__title">
340 + <?php echo esc_html(acym_translation('ACYM_NAME').' / '.acym_translation('ACYM_VALUE')); ?>
341 + </div>
342 + <div class="cell small-5 show-for-medium acym__listing__header__title">
343 + <?php echo esc_html(acym_translation('ACYM_NAME')); ?>
344 + </div>
345 + <div class="cell small-5 show-for-medium acym__listing__header__title">
346 + <?php echo esc_html(acym_translation('ACYM_VALUE')); ?>
347 + </div>
348 + <div class="cell small-2 acym__listing__header__title text-center">
349 + <?php echo esc_html(acym_translation('ACYM_STATUS')); ?>
350 + </div>
351 + </div>
352 + <?php foreach ($domain['CnameRecords'] as $cnameRecord) { ?>
353 + <div class="cell grid-x grid-margin-x margin-left-0 align-middle acym__listing__row">
354 + <div class="cell small-11 medium-5 cname-name">
355 + <?php echo esc_html($cnameRecord['name']); ?>
356 + </div>
357 + <div class="cell small-1 hide-for-medium cname-value">
358 + <?php $this->displayCnameStatus($cnameRecord); ?>
359 + </div>
360 + <div class="cell small-11 medium-5 cname-value">
361 + <?php echo esc_html($cnameRecord['value']); ?>
362 + </div>
363 + <div class="cell medium-2 show-for-medium text-center">
364 + <?php $this->displayCnameStatus($cnameRecord); ?>
365 + </div>
366 + </div>
367 + <?php } ?>
368 + </div>
369 + </div>
370 + </div>
371 + <?php
372 + $modalContent = ob_get_clean();
373 + ob_start();
374 + acym_tooltip(
375 + [
376 + 'hoveredText' => '<i class="acymicon-cogs acym__config__acymailer__domain--settings cursor-pointer acym__color__blue" acym-data-domain="'.esc_attr(
377 + $domain['domain']
378 + ).'"></i>',
379 + 'textShownInTooltip' => acym_translation('ACYM_SHOW_DNS_SETTINGS'),
380 + ]
381 + );
382 + $buttonModal = ob_get_clean();
383 + acym_modal(
384 + $buttonModal,
385 + $modalContent,
386 + null,
387 + [],
388 + [],
389 + true,
390 + true,
391 + 'acym__config__acymailer__cname__modal__container'
392 + );
393 +
394 + acym_tooltip(
395 + [
396 + 'hoveredText' => '<i class="acymicon-delete acym__config__acymailer__domain--delete cursor-pointer" acym-data-domain="'.esc_attr(
397 + $domain['domain']
398 + ).'"></i>',
399 + 'textShownInTooltip' => acym_translation('ACYM_DELETE'),
400 + ]
401 + );
402 + ?>
403 + </div>
404 + </div>
405 + <?php
406 + }
407 + }
408 + ?>
409 + </div>
410 + <div class="cell grid-x acym_vcenter acym__sending__methods__one__settings padding-top-1">
411 + <div class="cell grid-x">
412 + <div class="cell small-7 medium-4 large-3 margin-next-1">
413 + <input id="<?php echo esc_attr(self::SENDING_METHOD_ID); ?>_domain"
414 + class="cell medium-6 large-4 xlarge-3"
415 + type="text"
416 + autocomplete="off"
417 + value="">
418 + <span id="<?php echo esc_attr(self::SENDING_METHOD_ID); ?>_domain_error" class="medium-6 large-4 xlarge-3"></span>
419 + <?php
420 + if (!empty($unverifiedDomains)) { ?>
421 + <span id="acym__acymailer__unverifiedDomains">
422 + <?php foreach ($unverifiedDomains as $oneDomain) { ?>
423 + <span class="acym__acymailer__oneSuggestion"><?php echo esc_html($oneDomain); ?></span>
424 + <?php } ?>
425 + </span>
426 + <?php } ?>
427 + </div>
428 + <div id="acym__configuration__sending__method_addDomain_submit" class="cell grid-x small-4 medium-6 large-8 acym_vcenter">
429 + <button type="button"
430 + id="acym__configuration__sending__method-addDomain"
431 + class="cell shrink button button-secondary">
432 + <?php echo esc_html(acym_translation('ACYM_ADD_A_DOMAIN')); ?>
433 + </button>
434 + <i class="margin-left-1 acym_vcenter acymicon-circle-o-notch acymicon-spin is-hidden"
435 + id="acym__configuration__sending__method_add_domain-wait"></i>
436 + <div class="cell shrink grid-x acym_vcenter" id="acym__configuration__acymailer__add__error">
437 + <i class="acymicon-close acym__color__red cell shrink"></i>
438 + <span class="cell shrink" id="acym__configuration__acymailer__add__error__message"></span>
439 + </div>
440 + </div>
441 + </div>
442 + </div>
443 + <?php if (!$this->isLogFileEmpty()) { ?>
444 + <div class="cell grid-x acym__sending__methods__log">
445 + <?php
446 + acym_modal(
447 + acym_translation('ACYM_REPORT_SEE'),
448 + '',
449 + null,
450 + [],
451 + [
452 + 'class' => 'button',
453 + 'data-ajax' => 'true',
454 + 'data-iframe' => '&ctrl=configuration&task=seeLogs&filename='.$this->logFilename,
455 + ]
456 + );
457 + ?>
458 + </div>
459 + <?php } ?>
460 + <?php } ?>
461 + </div>
462 + </div>
463 + <?php
464 + }
465 +
466 + public function onAcymTestCredentialSendingMethod($sendingMethod, $credentials)
467 + {
468 + if ($sendingMethod !== self::SENDING_METHOD_ID) return;
469 +
470 + if (empty($credentials[self::SENDING_METHOD_ID.'_apikey'])) {
471 + acym_sendAjaxResponse(acym_translation('ACYM_MISSING_API_KEY'), [], false);
472 + }
473 +
474 + $response = $this->callApiSendingMethod(
475 + 'get_credits',
476 + [],
477 + [
478 + 'API-KEY' => $credentials[self::SENDING_METHOD_ID.'_apikey'],
479 + ]
480 + );
481 +
482 + if (empty($response)) {
483 + $errorMsg = acym_translation('ACYM_NO_ANSWER');
484 + acym_sendAjaxResponse(acym_translationSprintf('ACYM_ERROR_OCCURRED_WHILE_CALLING_API', $errorMsg), [], false);
485 + } elseif (!empty($response['error_curl'])) {
486 + acym_sendAjaxResponse(acym_translationSprintf('ACYM_ERROR_OCCURRED_WHILE_CALLING_API', $response['error_curl']), [], false);
487 + } elseif (!empty($response['message']) && $response['message'] == 'Invalid private key') {
488 + acym_sendAjaxResponse(acym_translation('ACYM_AUTHENTICATION_FAILS_WITH_API_KEY'), [], false);
489 + } elseif (!empty($response['message']) && !$this->checkSuccessCode($this->responseCode)) {
490 + if ($this->responseCode === 401) {
491 + acym_sendAjaxResponse(
492 + acym_translationSprintf(
493 + 'ACYM_SENDING_METHOD_ERROR_WHILE_ACTION',
494 + self::SENDING_METHOD_NAME,
495 + acym_translation('ACYM_GETTING_REMAINING_CREDITS'),
496 + $response['message']
497 + ),
498 + [],
499 + false
500 + );
501 + }
502 + acym_sendAjaxResponse($response['message'], [], false);
503 + } else {
504 + acym_sendAjaxResponse(acym_translation('ACYM_API_KEY_CORRECT'));
505 + }
506 + }
507 +
508 + public function onAcymSendEmail(&$response, $mailerHelper, $to, $from, $replyTo, $bcc = [], $attachments = [], $sendingMethodListParams = [])
509 + {
510 + if ($mailerHelper->externalMailer !== self::SENDING_METHOD_ID) {
511 + return;
512 + }
513 +
514 + $apikey = $this->config->get(self::SENDING_METHOD_ID.'_apikey');
515 + if (empty($apikey)) {
516 + $mailerHelper->failedCounting = false;
517 + $response['error'] = true;
518 + $response['message'] = acym_translation('ACYM_MISSING_API_KEY');
519 +
520 + return;
521 + }
522 +
523 + if ($this->isUnsubscribeLinkMissing($mailerHelper)) {
524 + $mailerHelper->failedCounting = false;
525 + $response['error'] = true;
526 + $response['message'] = acym_translation('ACYM_MISSING_UNSUBSCRIBE_LINK');
527 +
528 + return;
529 + }
530 +
531 + // In Amazon SES, you must verify each identity used as a "From", "Source", "Sender", or "Return-Path" address.
532 + $domainsUsed = [
533 + acym_getDomain($from['email']),
534 + acym_getDomain($replyTo['email']),
535 + ];
536 + $bounceAddress = $this->getBounceAddress($mailerHelper);
537 + if (!empty($bounceAddress)) {
538 + $domainsUsed[] = acym_getDomain($bounceAddress);
539 + }
540 +
541 + $domainsUsed = array_unique($domainsUsed);
542 +
543 + // Maybe don't try to send if one of these domains is not validated?
544 + $verifiedDomains = $this->getVerifiedDomains();
545 +
546 + $unverifiedDomains = array_diff($domainsUsed, $verifiedDomains);
547 + if (!empty($unverifiedDomains)) {
548 + $mailerHelper->failedCounting = false;
549 + $response['error'] = true;
550 + $response['message'] = acym_translationSprintf('ACYM_UNVERIFIED_DOMAINS_PREVENTING_EMAILS_FROM_BEING_SENT_X', implode(', ', $unverifiedDomains));
551 +
552 + return;
553 + }
554 +
555 + $recipients = [];
556 + if (!empty($mailerHelper->cc) || !empty($mailerHelper->bcc)) {
557 + $recipients[] = $to['email'];
558 + $recipients = array_merge($recipients, array_column($mailerHelper->cc, 0), array_column($mailerHelper->bcc, 0));
559 + $mailerHelper->cc = [];
560 + $mailerHelper->bcc = [];
561 + }
562 +
563 + $responseMailer = $this->callApiSendingMethod(
564 + 'send',
565 + [
566 + 'email' => $mailerHelper->getSentMIMEMessage(),
567 + 'domainsUsed' => $domainsUsed,
568 + 'isTransactional' => $mailerHelper->isTransactional,
569 + 'isOneTimeMail' => $mailerHelper->isOneTimeMail,
570 + 'recipients' => $recipients,
571 + ],
572 + [],
573 + 'POST'
574 + );
575 +
576 + if (!empty($responseMailer['logs'])) {
577 + acym_logError($responseMailer['logs'], self::SENDING_METHOD_ID);
578 + }
579 +
580 + if (!empty($responseMailer['error_curl'])) {
581 + $mailerHelper->failedCounting = false;
582 + $response['error'] = true;
583 + $response['message'] = acym_translationSprintf('ACYM_ERROR_OCCURRED_WHILE_CALLING_API', $responseMailer['error_curl']);
584 + } elseif (!$this->checkSuccessCode($this->responseCode)) {
585 + $response['error'] = true;
586 + $response['message'] = $this->translate($responseMailer);
587 +
588 + if ($response['message'] === acym_translation('ACYM_NO_CREDITS_LEFT')) {
589 + $response['message'] = acym_translation('ACYM_NOT_ENOUGH_CREDITS').' : ';
590 + $response['message'] .= '<a target="_blank" class="acym__color__blue" href="'.ACYM_ACYMAILING_WEBSITE.'">';
591 + $response['message'] .= acym_translation('ACYM_GET_MORE_CREDITS');
592 + $response['message'] .= '</a>';
593 + }
594 +
595 + // Don't unsubscribe/remove recipients if the error isn't related to them
596 + if (!empty($responseMailer['code']) && in_array($responseMailer['code'], [18, 26, 28])) {
597 + $mailerHelper->failedCounting = false;
598 + }
599 +
600 + if ($responseMailer['code'] == 26) {
601 + $queueClass = new QueueClass();
602 + $queueClass->delayAll(24);
603 + }
604 + } else {
605 + $response['error'] = false;
606 + }
607 + }
608 +
609 + public function replaceUserInformation(object &$email, ?object &$user, bool $send = true): void
610 + {
611 + if (empty($email->externalMailer) || $email->externalMailer !== self::SENDING_METHOD_ID) return;
612 +
613 + $bounceAddress = $this->getBounceAddress($email);
614 +
615 + if (!empty($bounceAddress) && method_exists($email, 'addCustomHeader')) {
616 + $email->addCustomHeader('Return-Path', $bounceAddress);
617 + }
618 + }
619 +
620 + public function ajaxCheckDomain()
621 + {
622 + $sendingMethod = acym_getVar('string', 'sendingMethod', '');
623 + if ($sendingMethod != self::SENDING_METHOD_ID) {
624 + acym_sendAjaxResponse();
625 + }
626 +
627 + $domains = json_decode($this->config->get(self::SENDING_METHOD_ID.'_domains', '[]'), true);
628 + if (empty($domains)) {
629 + acym_sendAjaxResponse();
630 + }
631 +
632 + $remainingDomains = $this->checkDomainsDNS($domains);
633 + if (empty($remainingDomains)) {
634 + acym_sendAjaxResponse('', ['domains' => $domains]);
635 + }
636 +
637 + $preparedDomains = array_map(
638 + function ($domain) {
639 + return $domain['domain'];
640 + },
641 + $remainingDomains
642 + );
643 +
644 + $responseApi = $this->callApiSendingMethod(
645 + 'getDomainStatus',
646 + ['domains' => $preparedDomains],
647 + [],
648 + 'POST'
649 + );
650 +
651 + if (empty($responseApi)) {
652 + acym_sendAjaxResponse('', ['domains' => $domains]);
653 + }
654 +
655 + if (!$this->checkSuccessCode($this->responseCode)) {
656 + acym_sendAjaxResponse(acym_translation('ACYM_ERROR_ON_CALL_ACYBA_WEBSITE').': '.$responseApi['message'], ['domains' => $domains], false);
657 + }
658 +
659 + $errorDomains = [];
660 + foreach ($domains as $key => $oneDomain) {
661 + $domainName = $oneDomain['domain'];
662 + if (!array_key_exists($domainName, $responseApi['data']) || !is_array($responseApi['data'][$domainName])) {
663 + $errorDomains[] = acym_translation('ACYM_ERROR_ON_CALL_ACYBA_WEBSITE').': '.$responseApi['data'][$domainName].': '.$domainName;
664 + continue;
665 + }
666 +
667 + if (!isset($responseApi['data'][$domainName]['code'])) {
668 + $domains[$key] = array_merge($domains[$key], $responseApi['data'][$domainName]);
669 + continue;
670 + }
671 +
672 + if (!empty(self::TRANSLATIONS[$responseApi['data'][$domainName]['code']])) {
673 + $message = self::TRANSLATIONS[$responseApi['data'][$domainName]['code']];
674 + } else {
675 + if (empty($responseApi['data'][$domainName]['message'])) {
676 + $message = 'ACYM_DOMAIN_DEFAULT_ERROR';
677 + } else {
678 + $message = $this->displayMessage($responseApi['data'][$domainName]['message']);
679 + }
680 + }
681 + acym_enqueueMessage(
682 + acym_translation('ACYM_ERROR_ON_CALL_ACYBA_WEBSITE').': '.acym_translationSprintf(
683 + $message,
684 + $domainName
685 + ),
686 + 'error'
687 + );
688 + }
689 +
690 + $this->config->saveConfig([self::SENDING_METHOD_ID.'_domains' => json_encode($domains)]);
691 +
692 + if (!empty($errorDomains)) {
693 + acym_sendAjaxResponse(implode(', ', $errorDomains), [], false);
694 + }
695 +
696 + acym_sendAjaxResponse('', ['domains' => $domains]);
697 + }
698 +
699 + public function onAcymDeleteDomain()
700 + {
701 + $oneDomain = acym_getVar('string', 'oneDomain', '');
702 +
703 + if (empty($oneDomain)) {
704 + return;
705 + }
706 +
707 + $apikey = $this->config->get(self::SENDING_METHOD_ID.'_apikey');
708 + if (empty($apikey)) {
709 + acym_sendAjaxResponse(acym_translation('ACYM_MISSING_API_KEY'), [], false);
710 + }
711 +
712 + $responseApi = $this->callApiSendingMethod(
713 + 'deleteDomainIdentity',
714 + ['domain' => $oneDomain, 'siteUrl' => acym_baseURI()],
715 + [],
716 + 'POST'
717 + );
718 +
719 + if (!empty($responseApi['error_curl'])) {
720 + $message = acym_translationSprintf('ACYM_ERROR_OCCURRED_WHILE_CALLING_API', $responseApi['error_curl']);
721 + acym_sendAjaxResponse($message, [], false);
722 + } elseif (!empty($responseApi['message']) && $responseApi['message'] === 'Invalid private key') {
723 + acym_sendAjaxResponse(acym_translation('ACYM_AUTHENTICATION_FAILS_WITH_API_KEY'), [], false);
724 + } elseif (!$this->checkSuccessCode($this->responseCode) && (empty($responseApi['code']) || !in_array($responseApi['code'], [5, 4, 3]))) {
725 + /*
726 + We may ask the API for the deletion of a domain while:
727 + - it already doesn't exist (error code 5)
728 + - it doesn't belong to the current API key (error code 4)
729 + - it isn't linked to this website (error code 3)
730 +
731 + In all 3 cases, we don't want to keep this domain in the AcyMailing configuration, so we remove it and consider the deletion as a success
732 + */
733 +
734 + $message = acym_translation('ACYM_ERROR_ON_CALL_ACYBA_WEBSITE').': '.$this->translate($responseApi);
735 + if (!empty($responseApi['logs'])) {
736 + acym_logError($responseApi['logs'], self::SENDING_METHOD_ID);
737 + }
738 +
739 + acym_sendAjaxResponse($message, [], false);
740 + } else {
741 + $field = self::SENDING_METHOD_ID.'_domains';
742 + $domains = json_decode($this->config->get($field, '[]'), true);
743 + $domains = array_filter($domains, function ($domain) use ($oneDomain) {
744 + return $domain['domain'] !== $oneDomain;
745 + });
746 +
747 + $this->config->saveConfig([$field => json_encode($domains)]);
748 +
749 + acym_sendAjaxResponse();
750 + }
751 + }
752 +
753 + public function ajaxAddDomain(): void
754 + {
755 + $oneDomain = acym_getVar('string', 'oneDomain', '');
756 +
757 + $this->config->saveConfig(['mailer_method' => self::SENDING_METHOD_ID]);
758 +
759 + if (empty($oneDomain)) {
760 + acym_sendAjaxResponse(acym_translation('ACYM_MISSING_DOMAIN'), [], false);
761 + }
762 +
763 + $oneDomain = acym_strtolower($oneDomain);
764 +
765 + $apikey = $this->config->get(self::SENDING_METHOD_ID.'_apikey');
766 + if (empty($apikey)) {
767 + acym_sendAjaxResponse(acym_translation('ACYM_MISSING_API_KEY'), [], false);
768 + }
769 +
770 + $domainValidation = preg_match('/^(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z0-9][a-z0-9-]{0,61}[a-z0-9]$/u', $oneDomain);
771 + if (!$domainValidation) {
772 + $message = acym_translationSprintf('ACYM_THE_DOMAIN_X_IS_NOT_VALID', $oneDomain);
773 + acym_sendAjaxResponse($message, ['type' => 'DOMAIN_VALIDATION'], false);
774 + }
775 +
776 + $field = self::SENDING_METHOD_ID.'_domains';
777 + $domains = $this->config->get($field, []);
778 +
779 + if (!empty($domains)) {
780 + $domains = @json_decode($domains, true);
781 + }
782 +
783 + if (!empty($domains[$oneDomain])) {
784 + acym_sendAjaxResponse(acym_translation('ACYM_DOMAIN_ALREADY_SENT'), [], false);
785 + }
786 +
787 + $responseApi = $this->callApiSendingMethod(
788 + 'createDomainIdentity',
789 + ['domain' => $oneDomain, 'siteUrl' => acym_baseURI()],
790 + [],
791 + 'POST'
792 + );
793 +
794 + if (!empty($responseApi['error_curl'])) {
795 + $message = acym_translationSprintf('ACYM_ERROR_OCCURRED_WHILE_CALLING_API', $responseApi['error_curl']);
796 + acym_sendAjaxResponse($message, [], false);
797 + } elseif (!empty($responseApi['message']) && $responseApi['message'] === 'Invalid API-KEY') {
798 + acym_sendAjaxResponse(acym_translation('ACYM_AUTHENTICATION_FAILS_WITH_API_KEY'), [], false);
799 + } elseif (!$this->checkSuccessCode($this->responseCode)) {
800 + if (empty($responseApi['code']) || empty(self::TRANSLATIONS[$responseApi['code']])) {
801 + $errorCodeTranslationKey = empty($responseApi['message']) ? 'ACYM_DOMAIN_DEFAULT_ERROR' : $this->displayMessage($responseApi['message']);
802 + } else {
803 + $errorCodeTranslationKey = self::TRANSLATIONS[$responseApi['code']];
804 + }
805 + $message = acym_translationSprintf($errorCodeTranslationKey, $oneDomain);
806 + acym_sendAjaxResponse($message, [], false);
807 + } elseif ($this->responseCode === 201) {
808 + $domains[$oneDomain] = [
809 + 'domain' => $oneDomain,
810 + 'CnameRecords' => $responseApi['cnameRecords'],
811 + 'status' => 'PENDING',
812 + ];
813 + $this->config->saveConfig([$field => json_encode($domains)]);
814 + acym_sendAjaxResponse($this->translate($responseApi), ['cnameRecords' => $responseApi['cnameRecords']]);
815 + } else {
816 + $cnameRecords = $responseApi['data'][$oneDomain]['cnameRecords'];
817 + $status = $responseApi['data'][$oneDomain]['status'];
818 + $domains[$oneDomain] = [
819 + 'domain' => $oneDomain,
820 + 'CnameRecords' => $cnameRecords,
821 + 'status' => $status,
822 + ];
823 + $this->config->saveConfig([$field => json_encode($domains)]);
824 +
825 + acym_sendAjaxResponse(
826 + $this->translate($responseApi),
827 + ['cnameRecords' => $cnameRecords, 'alreadyVerified' => $status === 'SUCCESS']
828 + );
829 + }
830 + }
831 +
832 + public function onAcymDisplayPage()
833 + {
834 + if (intval($this->config->get('walk_through', 0)) === 1) {
835 + return;
836 + }
837 +
838 + $unverifiedDomains = $this->getDomainsUnVerified();
839 +
840 + if (!empty($unverifiedDomains)) {
841 + $message = acym_translationSprintf('ACYM_UNVERIFIED_DOMAINS_PREVENTING_EMAILS_FROM_BEING_SENT_X', implode(', ', $unverifiedDomains));
842 + $notification = [
843 + 'name' => 'unverified_domains',
844 + 'removable' => 0,
845 + ];
846 +
847 + if (acym_getVar('string', 'page') === 'acymailing_dashboard' || acym_getVar('string', 'ctrl') === 'dashboard') {
848 + acym_enqueueMessage($message, 'warning', false, [$notification], false);
849 + } else {
850 + acym_enqueueMessage($message, 'warning', true, [$notification]);
851 + }
852 + } else {
853 + acym_removeDashboardNotification('unverified_domains');
854 + }
855 + }
856 +
857 + public function onAcymGetCreditRemainingSendingMethod(&$html, $reloading = false)
858 + {
859 + $sendingMethod = $this->config->get('mailer_method', '');
860 + if (empty($sendingMethod) || $sendingMethod != self::SENDING_METHOD_ID) return;
861 +
862 + $apiKey = $this->config->get(self::SENDING_METHOD_ID.'_apikey', '');
863 + if (empty($apiKey)) return;
864 +
865 + $response = $this->getRemainingCredits($reloading);
866 +
867 + if (!isset($response['remaining_credits'])) {
868 + if (empty($this->translate($response))) {
869 + $html = acym_translation('ACYM_ERROR_CONTACT_ACYMAILING');
870 + } else {
871 + $html = acym_translationSprintf(
872 + 'ACYM_SENDING_METHOD_ERROR_WHILE_ACTION',
873 + self::SENDING_METHOD_NAME,
874 + acym_translation('ACYM_GETTING_REMAINING_CREDITS'),
875 + $this->translate($response)
876 + );
877 + }
878 +
879 + return;
880 + }
881 +
882 + $unityTranslation = 'ACYM_CREDITS_REMAINING';
883 + $creditsShowed = $response['remaining_credits'];
884 +
885 + if (!empty($response['is_multisite'])) {
886 + $fromEmail = $this->config->get('from_email', '');
887 + // If the license is multisite we check and increment credits on the domain of the from email
888 + $domain = explode('@', $fromEmail)[1];
889 +
890 + if (empty($domain) || empty($response['domains'][$domain])) {
891 + $html = acym_translation('ACYM_DOMAIN_FROM_EMAIL_NOT_VALID_ASS');
892 + } else {
893 + $domainData = $response['domains'][$domain];
894 + if ($domainData['is_limited']) {
895 + $creditsShowed = $domainData['remaining_credits'];
896 + } else {
897 + $creditsShowed = $domainData['credits_used'];
898 + $unityTranslation = 'ACYM_CREDITS_USED';
899 + }
900 + }
901 + }
902 +
903 + // Add security empty text message
904 + if (empty($creditsShowed)) {
905 + $creditsShowed = '0';
906 + }
907 +
908 + ob_start();
909 + acym_tooltip(
910 + [
911 + 'hoveredText' => $creditsShowed,
912 + 'textShownInTooltip' => acym_translation('ACYM_GET_MORE_CREDITS'),
913 + 'classContainer' => 'credits_remaining',
914 + 'link' => ACYM_ACYMAILING_WEBSITE,
915 + ]
916 + );
917 + $tooltip = ob_get_clean();
918 + $html = acym_translationSprintf(
919 + 'ACYM_SENDING_METHOD_X_UNITY',
920 + self::SENDING_METHOD_NAME,
921 + $tooltip,
922 + '<span class="acym_not_bold">'.esc_html(acym_translation($unityTranslation)).'</span>'
923 + );
924 + }
925 +
926 + /**
927 + * Called before loading the emails of a batch to get the credits left
928 + *
929 + * @param int $creditsLeft
930 + *
931 + * @return void
932 + */
933 + public function onAcymCreditsLeft(&$creditsLeft)
934 + {
935 + $sendingMethod = $this->config->get('mailer_method', '');
936 + if (empty($sendingMethod) || $sendingMethod != self::SENDING_METHOD_ID) return;
937 +
938 + $apiKey = $this->config->get(self::SENDING_METHOD_ID.'_apikey', '');
939 + if (empty($apiKey)) {
940 + $creditsLeft = 0;
941 +
942 + return;
943 + }
944 +
945 + $credits = $this->getRemainingCredits(true);
946 + if (empty($credits['remaining_credits'])) {
947 + $creditsLeft = 0;
948 + } else {
949 + $creditsLeft = (int)$credits['remaining_credits'];
950 + }
951 + }
952 +
953 + public function onAcymAttachLicense($licenseKey)
954 + {
955 + if (empty($licenseKey)) {
956 + return;
957 + }
958 +
959 + $response = $this->callApiSendingMethod(self::SENDING_METHOD_API_URL.'public/licenses/'.$licenseKey);
960 +
961 + if (!empty($response['id'])) {
962 + $this->config->saveConfig([self::SENDING_METHOD_ID.'_apikey' => $response['id']]);
963 + }
964 + }
965 +
966 + public function onAcymDetachLicense()
967 + {
968 + $this->config->saveConfig([self::SENDING_METHOD_ID.'_apikey' => '']);
969 + }
970 +
971 + public function onAcymCampaignSummary(&$data)
972 + {
973 + if ($this->config->get('mailer_method') !== self::SENDING_METHOD_ID) {
974 + return;
975 + }
976 +
977 + $mail = $data['mailClass']->getOneById($data['mailId']);
978 + if (empty($mail->body) || !$this->isContainingUnsubscribeLink($mail->body)) {
979 + $data['notAllowedSendingError'] = acym_translation('ACYM_UNSUB_LINK');
980 + }
981 +
982 + $unverifiedDomains = $this->getDomainsUnVerified();
983 + if (!empty($unverifiedDomains)) {
984 + $data['notAllowedSendingError'] = acym_translationSprintf(
985 + 'ACYM_UNVERIFIED_DOMAINS_PREVENTING_EMAILS_FROM_BEING_SENT_X',
986 + implode(', ', $unverifiedDomains)
987 + );
988 + }
989 + }
990 +
991 + private function getDomainsUnVerified(): array
992 + {
993 + if ($this->config->get('mailer_method') !== self::SENDING_METHOD_ID) {
994 + return [];
995 + }
996 +
997 + // In Amazon SES, you must verify each identity used as a "From", "Source", "Sender", or "Return-Path" address.
998 + $allDomains = [];
999 +
1000 + $allDomains[] = acym_getDomain($this->config->get('from_email'));
1001 + if ($this->config->get('from_as_replyto') === '0') {
1002 + $allDomains[] = acym_getDomain($this->config->get('replyto_email'));
1003 + }
1004 +
1005 + if ($this->config->get('multilingual') === '1') {
1006 + $senderInfoTranslation = $this->config->get('sender_info_translation');
1007 + if (!empty($senderInfoTranslation)) {
1008 + $senderInfoTranslation = json_decode($senderInfoTranslation, true);
1009 + foreach ($senderInfoTranslation as $oneSenderInfo) {
1010 + $allDomains[] = acym_getDomain($oneSenderInfo['from_email']);
1011 + $allDomains[] = acym_getDomain($oneSenderInfo['replyto_email']);
1012 + }
1013 + }
1014 + }
1015 +
1016 + $allDomains[] = acym_getDomain($this->config->get('bounce_email'));
1017 + $allDomains = array_filter(array_unique($allDomains));
1018 +
1019 + $verifiedDomains = $this->getVerifiedDomains();
1020 +
1021 + return array_diff($allDomains, $verifiedDomains);
1022 + }
1023 +
1024 + private function getRateColor(float $rate, float $allowedRate, float $warningRate): string
1025 + {
1026 + if (empty($rate) || empty($allowedRate) || empty($warningRate)) {
1027 + return '';
1028 + }
1029 +
1030 + if ($rate > $allowedRate) {
1031 + return 'acym__color__red';
1032 + } elseif ($rate >= $warningRate) {
1033 + return 'acym__color__orange';
1034 + }
1035 +
1036 + return '';
1037 + }
1038 +
1039 + private function displayRateIcon(float $rate, float $allowedRate, float $warningRate): void
1040 + {
1041 + if (empty($rate) || empty($allowedRate) || empty($warningRate)) {
1042 + return;
1043 + }
1044 +
1045 + if ($rate > $allowedRate) {
1046 + acym_tooltip(
1047 + [
1048 + 'hoveredText' => '<i class="acym__config__acymailer__rate-status__icon acymicon-close acym__color__red"></i>',
1049 + 'textShownInTooltip' => acym_translation('ACYM_RATE_BLOCKED'),
1050 + ]
1051 + );
1052 + } elseif ($rate >= $warningRate) {
1053 + acym_tooltip(
1054 + [
1055 + 'hoveredText' => '<i class="acym__config__acymailer__rate-status__icon acymicon-exclamation-triangle acym__color__orange"></i>',
1056 + 'textShownInTooltip' => acym_translation('ACYM_RATE_WARNING'),
1057 + ]
1058 + );
1059 + }
1060 + }
1061 +
1062 + private function updateDomainRates($domainsRates)
1063 + {
1064 + $domains = $this->config->get(self::SENDING_METHOD_ID.'_domains', []);
1065 +
1066 + if (empty($domains)) {
1067 + return;
1068 + }
1069 +
1070 + $domains = @json_decode($domains, true);
1071 +
1072 + foreach ($domainsRates as $oneDomain => $oneRate) {
1073 + if (empty($domains[$oneDomain])) continue;
1074 + foreach ($oneRate as $rateKey => $rateValue) {
1075 + $domains[$oneDomain][$rateKey] = $rateValue;
1076 + }
1077 + }
1078 +
1079 + $this->config->saveConfig([self::SENDING_METHOD_ID.'_domains' => json_encode($domains)]);
1080 + }
1081 +
1082 + private function getVerifiedDomains(): array
1083 + {
1084 + $verifiedDomains = [];
1085 + $domainStatuses = json_decode($this->config->get(self::SENDING_METHOD_ID.'_domains', '[]'), true);
1086 + if (!empty($domainStatuses)) {
1087 + foreach ($domainStatuses as $domain => $info) {
1088 + if ($info['status'] === 'SUCCESS') {
1089 + $verifiedDomains[] = $domain;
1090 + }
1091 + }
1092 + }
1093 +
1094 + return $verifiedDomains;
1095 + }
1096 +
1097 + private function displayMessage($message): string
1098 + {
1099 + $correspondances = [
1100 + 'AlreadyExistsException' => 'ACYM_DOMAIN_X_ALREADY_EXIST',
1101 + 'TooManyRequestsException' => 'ACYM_DOMAIN_TO_MANY_REQUEST',
1102 + 'NotFoundException' => 'ACYM_DOMAIN_NOT_FOUND',
1103 + 'NotExistException' => 'ACYM_CANT_DELETE_DOMAIN',
1104 + ];
1105 +
1106 + if (empty($message) || empty($correspondances[$message])) {
1107 + return 'ACYM_DOMAIN_DEFAULT_ERROR';
1108 + }
1109 +
1110 + return $correspondances[$message];
1111 + }
1112 +
1113 + private function getRemainingCredits($forceReload = false)
1114 + {
1115 + $time = time();
1116 + $lastCheck = $this->config->get(self::SENDING_METHOD_ID.'_last_credits_check', 0);
1117 + $lastDetails = $this->config->get(self::SENDING_METHOD_ID.'_credits_details', []);
1118 +
1119 + if (!$forceReload && !empty($lastDetails) && $lastCheck > $time - self::CREDITS_RELOAD_DELAY) {
1120 + return json_decode($lastDetails, true);
1121 + }
1122 +
1123 + $response = $this->callApiSendingMethod('get_credits');
1124 +
1125 + $this->config->saveConfig([
1126 + self::SENDING_METHOD_ID.'_credits_details' => json_encode($response),
1127 + self::SENDING_METHOD_ID.'_last_credits_check' => $time,
1128 + ]);
1129 +
1130 + if (!empty($response['domains'])) {
1131 + $this->updateDomainRates($response['domains']);
1132 + }
1133 +
1134 + return $response;
1135 + }
1136 +
1137 + private function checkSuccessCode($responseCode): bool
1138 + {
1139 + // we can add more success response codes if needed but for now, that's all the success response codes the API can send
1140 + return in_array($responseCode, [200, 201]);
1141 + }
1142 +
1143 + private function translate($response)
1144 + {
1145 + if (!isset($response['code']) && empty($response['message'])) {
1146 + return '';
1147 + }
1148 +
1149 + $correspondence = '';
1150 + $messageData = [];
1151 +
1152 +
1153 + if (isset($response['code']) && !empty(self::TRANSLATIONS[$response['code']])) {
1154 + $correspondence = self::TRANSLATIONS[$response['code']];
1155 + }
1156 +
1157 + if (!empty($response['messageData'])) {
1158 + $messageData = $response['messageData'];
1159 + }
1160 +
1161 + if (empty($correspondence)) {
1162 + if (empty($messageData)) {
1163 + return $response['message'];
1164 + }
1165 +
1166 + return acym_translationVsprintf($response['message'], $messageData, false);
1167 + }
1168 +
1169 + if (empty($messageData)) {
1170 + $finalMessage = acym_translation($correspondence);
1171 + } else {
1172 + $finalMessage = acym_translationVsprintf($correspondence, $messageData);
1173 + }
1174 +
1175 + if (in_array($response['code'], $this->errorCodes)) {
1176 + $this->errors[] = $finalMessage;
1177 + $this->errorCallback();
1178 + }
1179 +
1180 + return $finalMessage;
1181 + }
1182 +
1183 + /**
1184 + * Emails not needing an unsubscribe link:
1185 + * - Sending a test from config, from campaign tab or from editor
1186 + * - Forwarding a bounce message
1187 + * - Sending a spam-test
1188 + * - Overriding website emails
1189 + * - Sending notification messages
1190 + * - Unsubscribe emails
1191 + * - Sending the walkthrough email
1192 + * - Forwarding an email to a specific address from mailbox actions
1193 + */
1194 + private function isUnsubscribeLinkMissing($mailerHelper): bool
1195 + {
1196 + if ($mailerHelper->isTest || $mailerHelper->isForward || $mailerHelper->isSpamTest || empty($mailerHelper->mail)) {
1197 + return false;
1198 + }
1199 +
1200 + if (in_array($mailerHelper->mail->type, MailClass::TYPES_TRANSACTIONAL) || $mailerHelper->mail->type === MailClass::TYPE_AUTOMATION) {
1201 + return false;
1202 + }
1203 +
1204 + return !$this->isContainingUnsubscribeLink($mailerHelper->mail->body);
1205 + }
1206 +
1207 + private function isContainingUnsubscribeLink(string $text): bool
1208 + {
1209 + return strpos($text, '{unsubscribe}') !== false
1210 + || strpos($text, '{unsubscribeall}') !== false
1211 + || strpos($text, 'task=unsubscribe') !== false
1212 + || strpos($text, 'frontusers/unsubscribe') !== false
1213 + || strpos($text, '{direct_unsubscribe') !== false;
1214 + }
1215 +
1216 + private function checkDomainsDNS($domains): array
1217 + {
1218 + $remainingDomains = [];
1219 + foreach ($domains as $oneDomain) {
1220 + // No DNS entries yet, we have to check the domain to get DNS entries
1221 + if (empty($oneDomain['CnameRecords'])) {
1222 + $remainingDomains[] = $oneDomain;
1223 + continue;
1224 + }
1225 +
1226 + // Check if all DNS entries are valid before calling the API
1227 + foreach ($oneDomain['CnameRecords'] as $oneRecord) {
1228 + if (!$this->checkCnameEntry($oneRecord['name'], $oneRecord['value'])) {
1229 + $domainPosition = strpos($oneRecord['name'], '_domainkey') + 11;
1230 + $domainName = substr($oneRecord['name'], $domainPosition);
1231 + acym_sendAjaxResponse(acym_translation('ACYM_A_CNAME_MISSING'), ['domain' => $domainName], false);
1232 + }
1233 + }
1234 +
1235 + $remainingDomains[] = $oneDomain;
1236 + }
1237 +
1238 + return $remainingDomains;
1239 + }
1240 +
1241 + private function checkCnameEntry(string $entryName, string $entryValue): bool
1242 + {
1243 + $domainPosition = strpos($entryName, '_domainkey') + 11;
1244 + $domainName = substr($entryName, $domainPosition);
1245 +
1246 + $dnsEntries = @dns_get_record($entryName, DNS_CNAME);
1247 +
1248 + if (empty($dnsEntries)) {
1249 + $entryName = substr($entryName, 0, $domainPosition);
1250 + $doubleDomainEntry = $entryName.'.'.$domainName;
1251 +
1252 + $dnsEntries = @dns_get_record($doubleDomainEntry, DNS_CNAME);
1253 + if (!empty($dnsEntries)) {
1254 + $this->cnameErrors[] = acym_translationSprintf('ACYM_ACYMAILER_MALFORMED_CNAME', $doubleDomainEntry);
1255 + $this->cnameErrors[] = acym_translationSprintf('ACYM_ACYMAILER_CNAME_TRY_WITHOUT_DOMAIN', $entryName, $entryValue);
1256 + } else {
1257 + $this->cnameErrors[] = acym_translation('ACYM_WALK_ACYMAILER_STATUS_WAIT');
1258 + }
1259 +
1260 + return false;
1261 + }
1262 +
1263 + if (!is_array($dnsEntries)) {
1264 + $dnsEntries = [$dnsEntries];
1265 + }
1266 +
1267 + foreach ($dnsEntries as $oneEntry) {
1268 + if ($oneEntry['type'] !== 'CNAME' || $oneEntry['host'] !== $entryName) {
1269 + continue;
1270 + }
1271 +
1272 + if (rtrim($oneEntry['target'], '.') === rtrim($entryValue, '.')) {
1273 + return true;
1274 + }
1275 +
1276 + $this->cnameErrors[] = acym_translationSprintf('ACYM_DOMAIN_CHECK_INCORRECT_VALUE', $entryName, $domainName);
1277 +
1278 + return false;
1279 + }
1280 +
1281 + $this->cnameErrors[] = acym_translation('ACYM_DNS_NOT_CNAME');
1282 +
1283 + return false;
1284 + }
1285 +
1286 + private function displayCnameStatus(array $cnameRecord): void
1287 + {
1288 + if ($cnameRecord['isValid']) {
1289 + echo '<i class="acym__config__acymailer__status__icon acymicon-check-circle acym__color__green"></i>';
1290 + } else {
1291 + acym_tooltip(
1292 + [
1293 + 'hoveredText' => '<i class="acym__config__acymailer__status__icon acymicon-close acym__color__red"></i>',
1294 + 'textShownInTooltip' => implode('<br/>', $cnameRecord['tooltipMessages']),
1295 + ]
1296 + );
1297 + }
1298 + }
1299 +}