PluginProbe
AcyMailing – An Ultimate Newsletter Plugin and Marketing Automation Solution for WordPress / 11.1.1
AcyMailing – An Ultimate Newsletter Plugin and Marketing Automation Solution for WordPress v11.1.1
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/Helpers/MailerHelper.php +0 -1721 10.2.2 → 11.1.1 View file →
@@ -1,1721 +1,0 @@
1 -<?php
2 -
3 -namespace AcyMailing\Helpers;
4 -
5 -use AcyMailing\Classes\CampaignClass;
6 -use AcyMailing\Classes\ConfigurationClass;
7 -use AcyMailing\Classes\FollowupClass;
8 -use AcyMailing\Classes\MailArchiveClass;
9 -use AcyMailing\Classes\MailClass;
10 -use AcyMailing\Classes\OverrideClass;
11 -use AcyMailing\Classes\UrlClass;
12 -use AcyMailing\Classes\UserClass;
13 -use AcyMailerPhp\Exception;
14 -use AcyMailerPhp\OAuth;
15 -use AcyMailerPhp\Mailer;
16 -use Pelago\Emogrifier\HtmlProcessor\HtmlPruner;
17 -
18 -class MailerHelper extends Mailer
19 -{
20 - const NEW_TRY_ERRORS = [1, 6];
21 -
22 - public $to = [];
23 - public $cc = [];
24 - public $bcc = [];
25 - public $ReplyTo = [];
26 - public $attachment = [];
27 - public $CustomHeader = [];
28 -
29 - public string $preheader;
30 - public string $replyname;
31 - public string $replyemail;
32 - public string $body;
33 - public string $altbody;
34 - public string $subject;
35 - public string $from;
36 - public string $fromName;
37 - public array $replyto;
38 - public bool $custom_view;
39 -
40 - private EncodingHelper $encodingHelper;
41 - private EditorHelper $editorHelper;
42 - private UserClass $userClass;
43 - private MailClass $mailClass;
44 - private MailArchiveClass $mailArchiveClass;
45 - public ConfigurationClass $config;
46 -
47 - public bool $report = true;
48 - public bool $alreadyCheckedAddresses = false;
49 - public int $errorNumber = 0;
50 - public bool $failedCounting = true;
51 -
52 - public bool $autoAddUser = false;
53 - public bool $userCreationTriggers = true;
54 -
55 - public string $reportMessage = '';
56 - public bool $dtextsFailed = false;
57 -
58 - public bool $trackEmail = false;
59 -
60 - public string $externalMailer;
61 -
62 - public string $stylesheet = '';
63 - public array $settings;
64 -
65 - public array $parameters = [];
66 -
67 - private string $userLanguage = '';
68 - private string $receiverEmail;
69 -
70 - private object $overrideEmailToSend;
71 - public bool $isTest = false;
72 - public bool $isSpamTest = false;
73 - public bool $isForward = false;
74 -
75 - public int $mailId = 0;
76 - public int $creator_id;
77 - public string $type;
78 - public string $links_language;
79 - public int $id = 0;
80 - public ?object $mail = null;
81 - private array $defaultMail = [];
82 -
83 - public array $listsIds = [];
84 - private string $currentSendingMethod = '';
85 - private array $currentMethodSetting = [];
86 -
87 - public bool $isAbTest = false;
88 - public bool $isTransactional = false;
89 - public bool $isOneTimeMail = false;
90 - public bool $isSendingMethodByListActive = false;
91 -
92 - public function __construct()
93 - {
94 - parent::__construct();
95 -
96 - $this->XMailer = ' ';
97 - $this->SMTPAutoTLS = false;
98 -
99 - $this->encodingHelper = new EncodingHelper();
100 - $this->editorHelper = new EditorHelper();
101 - $this->userClass = new UserClass();
102 - $this->mailClass = new MailClass();
103 - $this->mailArchiveClass = new MailArchiveClass();
104 - $this->config = acym_config();
105 -
106 - $this->setFrom($this->getSendSettings('from_email'), $this->getSendSettings('from_name'));
107 - $this->Sender = $this->cleanText($this->getSendSettings('bounce_email'));
108 - if (empty($this->Sender)) {
109 - $this->Sender = '';
110 - }
111 - $maxLineLength = $this->config->get('mailer_wordwrap', 0);
112 - if (!empty($maxLineLength) && self::MAX_LINE_LENGTH > $maxLineLength) {
113 - $this->WordWrap = $maxLineLength;
114 - }
115 -
116 - $this->setSendingMethodSetting();
117 -
118 - if ($this->config->get('dkim', 0) && $this->Mailer != 'elasticemail') {
119 - $this->DKIM_domain = $this->config->get('dkim_domain');
120 - $this->DKIM_selector = $this->config->get('dkim_selector', 'acy');
121 - if (empty($this->DKIM_selector)) $this->DKIM_selector = 'acy';
122 - $this->DKIM_passphrase = $this->config->get('dkim_passphrase');
123 - $this->DKIM_identity = $this->config->get('dkim_identity');
124 - $this->DKIM_private = trim($this->config->get('dkim_private'));
125 - $this->DKIM_private_string = trim($this->config->get('dkim_private'));
126 - }
127 -
128 - $this->CharSet = strtolower($this->config->get('charset'));
129 - if (empty($this->CharSet)) {
130 - $this->CharSet = 'utf-8';
131 - }
132 -
133 - $this->clearAll();
134 -
135 - $this->Encoding = $this->config->get('encoding_format');
136 - if (empty($this->Encoding)) {
137 - $this->Encoding = '8bit';
138 - }
139 -
140 - @ini_set('pcre.backtrack_limit', 1000000);
141 -
142 - $this->SMTPOptions = ['ssl' => ['verify_peer' => false, 'verify_peer_name' => false, 'allow_self_signed' => true]];
143 -
144 - $this->addParamInfo();
145 - }
146 -
147 - public function setSendingMethodSetting(): void
148 - {
149 - $externalSendingMethod = [];
150 - acym_trigger('onAcymGetSendingMethods', [&$externalSendingMethod, true]);
151 - $externalSendingMethod = array_keys($externalSendingMethod['sendingMethods']);
152 -
153 - $mailerMethodConfig = $this->getSendingMethod();
154 - $this->currentSendingMethod = $mailerMethodConfig;
155 -
156 - if ($mailerMethodConfig === 'google') {
157 - $this->isSMTP();
158 - $this->Host = 'smtp.gmail.com:465';
159 - $this->SMTPAuth = true;
160 - $this->Username = trim($this->getSendingMethodSettings('google_username'));
161 - $this->AuthType = 'XOAUTH2';
162 - $this->SMTPSecure = 'ssl';
163 -
164 - $this->setOAuth(
165 - new OAuth(
166 - [
167 - 'sendingMethod' => 'google',
168 - 'tokenGenerationUrl' => 'https://oauth2.googleapis.com/token',
169 - 'userName' => $this->Username,
170 - 'clientId' => trim($this->getSendingMethodSettings('google_client_id')),
171 - 'clientSecret' => trim($this->getSendingMethodSettings('google_client_secret')),
172 - 'oauthToken' => trim($this->getSendingMethodSettings('google_access_token')),
173 - 'oauthTokenExpiration' => trim($this->getSendingMethodSettings('google_access_token_expiration')),
174 - 'refreshToken' => trim($this->getSendingMethodSettings('google_refresh_token')),
175 - ]
176 - )
177 - );
178 -
179 - if (empty($this->Sender)) {
180 - $this->Sender = strpos($this->Username, '@') ? $this->Username : $this->getSendingMethodSettings('from_email');
181 - }
182 - } elseif ($mailerMethodConfig === 'outlook') {
183 - $this->isSMTP();
184 - $tenant = trim($this->getSendingMethodSettings('outlook_tenant', 'consumers'));
185 - $host = $tenant === 'consumers' ? 'smtp-mail.outlook.com' : 'smtp.office365.com';
186 - $this->Host = $host.':587';
187 - $this->SMTPAuth = true;
188 - $this->Username = trim($this->getSendingMethodSettings('outlook_username'));
189 - $this->AuthType = 'XOAUTH2';
190 - $this->SMTPSecure = 'tls';
191 -
192 - $this->setOAuth(
193 - new OAuth(
194 - [
195 - 'sendingMethod' => 'outlook',
196 - 'tokenGenerationUrl' => 'https://login.microsoftonline.com/'.$tenant.'/oauth2/v2.0/token',
197 - 'userName' => $this->Username,
198 - 'clientId' => trim($this->getSendingMethodSettings('outlook_client_id')),
199 - 'clientSecret' => trim($this->getSendingMethodSettings('outlook_client_secret')),
200 - 'oauthToken' => trim($this->getSendingMethodSettings('outlook_access_token')),
201 - 'oauthTokenExpiration' => trim($this->getSendingMethodSettings('outlook_access_token_expiration')),
202 - 'refreshToken' => trim($this->getSendingMethodSettings('outlook_refresh_token')),
203 - ]
204 - )
205 - );
206 -
207 - if (empty($this->Sender)) {
208 - $this->Sender = strpos($this->Username, '@') ? $this->Username : $this->getSendingMethodSettings('from_email');
209 - }
210 - } elseif ($mailerMethodConfig === 'smtp') {
211 - $this->isSMTP();
212 - $this->Host = trim($this->getSendingMethodSettings('smtp_host'));
213 - $port = $this->getSendingMethodSettings('smtp_port');
214 - if (empty($port) && $this->getSendingMethodSettings('smtp_secured') === 'ssl') {
215 - $port = 465;
216 - }
217 - if (!empty($port)) {
218 - $this->Host .= ':'.$port;
219 - }
220 - $this->SMTPAuth = (bool)$this->getSendingMethodSettings('smtp_auth', '1');
221 - $this->Username = trim($this->getSendingMethodSettings('smtp_username'));
222 -
223 - $authMethod = $this->getSendingMethodSettings('smtp_method');
224 - if (in_array($authMethod, ['CRAM-MD5', 'LOGIN', 'PLAIN'])) {
225 - $this->AuthType = $authMethod;
226 - }
227 - if ($this->SMTPAuth) {
228 - $this->Password = trim($this->getSendingMethodSettings('smtp_password'));
229 - }
230 -
231 - $this->SMTPSecure = trim($this->getSendingMethodSettings('smtp_secured'));
232 -
233 - if (empty($this->Sender)) {
234 - $this->Sender = strpos($this->Username, '@') ? $this->Username : $this->getSendingMethodSettings('from_email');
235 - }
236 - } elseif ($mailerMethodConfig === 'sendmail') {
237 - $this->isSendmail();
238 - $this->Sendmail = trim($this->getSendingMethodSettings('sendmail_path'));
239 - if (empty($this->Sendmail)) {
240 - $this->Sendmail = '/usr/sbin/sendmail';
241 - }
242 - } elseif ($mailerMethodConfig === 'qmail') {
243 - $this->isQmail();
244 - } elseif ($mailerMethodConfig === 'amazon') {
245 - $this->isSMTP();
246 - $amazonCredentials = [];
247 - acym_trigger('onAcymGetCredentialsSendingMethod', [&$amazonCredentials, 'amazon', $this->currentMethodSetting], 'plgAcymAmazon');
248 - $this->Host = trim($amazonCredentials['amazon_host']).':587';
249 - $this->Username = trim($amazonCredentials['amazon_username']);
250 - $this->Password = trim($amazonCredentials['amazon_password']);
251 - $this->SMTPAuth = true;
252 - $this->SMTPSecure = 'tls';
253 - } elseif ($mailerMethodConfig === 'brevo-smtp') {
254 - $this->isSMTP();
255 - $brevoSmtpCredentials = [];
256 - acym_trigger('onAcymGetCredentialsSendingMethod', [&$brevoSmtpCredentials, 'brevo-smtp', $this->currentMethodSetting], 'plgAcymBrevo');
257 - $this->Host = trim($brevoSmtpCredentials['brevo-smtp_host']).':587';
258 - $this->Username = trim($brevoSmtpCredentials['brevo-smtp_username']);
259 - $this->Password = trim($brevoSmtpCredentials['brevo-smtp_password']);
260 - $this->SMTPAuth = true;
261 - $this->SMTPSecure = 'tls';
262 - } elseif (in_array($mailerMethodConfig, $externalSendingMethod)) {
263 - $this->isExternal($mailerMethodConfig);
264 - } else {
265 - $this->isMail();
266 - }
267 - }
268 -
269 - protected function externalSend(string $MIMEHeader, string $MIMEBody): bool
270 - {
271 - $fromName = empty($this->FromName) ? $this->config->get('from_name') : $this->FromName;
272 - $reply_to = array_shift($this->ReplyTo);
273 -
274 - $attachments = [];
275 - if (!empty($this->attachment) && $this->config->get('embed_files')) {
276 - foreach ($this->attachment as $i => $oneAttach) {
277 - $encodedContent = $this->encodeFile($oneAttach[0], $oneAttach[3]);
278 - $this->attachment[$i]['contentEncoded'] = $encodedContent;
279 - }
280 - $attachments = $this->attachment;
281 - }
282 -
283 - $response = [];
284 - $data = [
285 - &$response,
286 - $this,
287 - ['email' => $this->to[0][0], 'name' => $this->to[0][1]],
288 - ['email' => $this->From, 'name' => $fromName],
289 - ['email' => $reply_to[0], 'name' => $reply_to[1]],
290 - !empty($this->bcc) ? $this->bcc : [],
291 - $attachments,
292 - $this->currentMethodSetting,
293 - ];
294 - acym_trigger('onAcymSendEmail', $data);
295 -
296 - if (!empty($response['error'])) {
297 - $this->setError($response['message']);
298 -
299 - return false;
300 - }
301 -
302 - return true;
303 - }
304 -
305 - public function send(): bool
306 - {
307 - if (!file_exists(ACYM_LIBRARIES.'Mailer'.DS.'Mailer.php')) {
308 - $this->reportMessage = acym_translationSprintf('ACYM_X_FILE_MISSING', 'Mailer', ACYM_LIBRARIES.'Mailer'.DS);
309 - if ($this->report) {
310 - acym_enqueueMessage($this->reportMessage, 'error');
311 - }
312 -
313 - return false;
314 - }
315 -
316 - if (empty($this->Subject) || empty($this->Body)) {
317 - if ($this->isTest && empty($this->Subject)) {
318 - $this->Subject = acym_translation('ACYM_EMAIL_SUBJECT');
319 - } else {
320 - $this->reportMessage = acym_translation('ACYM_SEND_EMPTY');
321 - $this->errorNumber = 8;
322 - if ($this->report) {
323 - acym_enqueueMessage($this->reportMessage, 'error');
324 - }
325 -
326 - return false;
327 - }
328 - }
329 -
330 - if (empty($this->ReplyTo) && empty($this->ReplyToQueue)) {
331 - if (!empty($this->replyemail)) {
332 - $replyToEmail = $this->replyemail;
333 - } elseif ($this->config->get('from_as_replyto', 1) == 1) {
334 - $replyToEmail = $this->getSendSettings('from_email');
335 - } else {
336 - $replyToEmail = $this->getSendSettings('replyto_email');
337 - }
338 -
339 - if (!empty($this->replyname)) {
340 - $replyToName = $this->replyname;
341 - } elseif ($this->config->get('from_as_replyto', 1) == 1) {
342 - $replyToName = $this->getSendSettings('from_name');
343 - } else {
344 - $replyToName = $this->getSendSettings('replyto_name');
345 - }
346 -
347 - $this->acymAddReplyTo($replyToEmail, $replyToName);
348 - }
349 -
350 - $shouldEmbed = $this->config->get('embed_images', 0);
351 - if (intval($shouldEmbed) === 1 && $this->Mailer !== 'elasticemail') {
352 - $this->embedImages();
353 - }
354 -
355 - if (!$this->alreadyCheckedAddresses) {
356 - $this->alreadyCheckedAddresses = true;
357 -
358 - $replyToTmp = '';
359 - if (!empty($this->ReplyTo)) {
360 - $replyToTmp = reset($this->ReplyTo);
361 - $replyToTmp = $replyToTmp[0];
362 - } elseif (!empty($this->ReplyToQueue)) {
363 - $replyToTmp = reset($this->ReplyToQueue);
364 - $replyToTmp = $replyToTmp[1];
365 - }
366 -
367 - if (empty($replyToTmp) || !acym_isValidEmail($replyToTmp)) {
368 - $this->reportMessage = acym_translation('ACYM_VALID_EMAIL').' ( '.acym_translation('ACYM_REPLYTO_EMAIL').' : '.(empty($this->ReplyTo) ? '' : $replyToTmp).' ) ';
369 - $this->errorNumber = 9;
370 - if ($this->report) {
371 - acym_enqueueMessage($this->reportMessage, 'error');
372 - }
373 -
374 - return false;
375 - }
376 -
377 - if (empty($this->From) || !acym_isValidEmail($this->From)) {
378 - $this->reportMessage = acym_translation('ACYM_VALID_EMAIL').' ( '.acym_translation('ACYM_FROM_EMAIL').' : '.$this->From.' ) ';
379 - $this->errorNumber = 9;
380 - if ($this->report) {
381 - acym_enqueueMessage($this->reportMessage, 'error');
382 - }
383 -
384 - return false;
385 - }
386 -
387 - if (!empty($this->Sender) && !acym_isValidEmail($this->Sender)) {
388 - $this->reportMessage = acym_translation('ACYM_VALID_EMAIL').' ( '.acym_translation('ACYM_BOUNCE_EMAIL').' : '.$this->Sender.' ) ';
389 - $this->errorNumber = 9;
390 - if ($this->report) {
391 - acym_enqueueMessage($this->reportMessage, 'error');
392 - }
393 -
394 - return false;
395 - }
396 - }
397 -
398 - if ($this->config->get('save_body') === '1') {
399 - @file_put_contents(ACYM_ROOT.'acydebug_mail.html', $this->Body);
400 - }
401 -
402 - $this->Body = htmlentities($this->Body);
403 - $this->Body = htmlspecialchars_decode($this->Body);
404 - $this->Body = str_replace(['&amp;', '&sigmaf;'], ['&', 'ς'], $this->Body);
405 -
406 - if ($this->CharSet !== 'utf-8') {
407 - $this->Body = $this->encodingHelper->change($this->Body, 'UTF-8', $this->CharSet);
408 - $this->Subject = $this->encodingHelper->change($this->Subject, 'UTF-8', $this->CharSet);
409 - }
410 -
411 - $this->Subject = str_replace(
412 - ['’', '“', '”', '–'],
413 - ["'", '"', '"', '-'],
414 - $this->Subject
415 - );
416 -
417 - $this->Body = str_replace(" ", ' ', $this->Body);
418 -
419 - $externalSending = false;
420 -
421 - $this->isOneTimeMail = $this->isTransactional = $this->isForward || $this->isTest || $this->isSpamTest;
422 - if (!empty($this->mailId) && !empty($this->defaultMail[$this->mailId])) {
423 - if ($this->mailClass->isTransactionalMail($this->defaultMail[$this->mailId])) {
424 - $this->isTransactional = true;
425 - }
426 -
427 - if ($this->mailClass->isOneTimeMail($this->defaultMail[$this->mailId])) {
428 - $this->isOneTimeMail = true;
429 - }
430 - }
431 -
432 - acym_trigger('onAcymProcessQueueExternalSendingCampaign', [&$externalSending, $this->isTransactional]);
433 -
434 - $warnings = '';
435 -
436 - if (ACYM_PRODUCTION) {
437 - if ($externalSending) {
438 - $result = false;
439 - acym_trigger('onAcymRegisterReceiverContentAndList', [&$result, $this->Subject, $this->Body, $this->receiverEmail, $this->mailId, &$warnings]);
440 - } else {
441 - acym_trigger('onAcymBeforeEmailSend', [&$this]);
442 - ob_start();
443 - $result = parent::send();
444 - $warnings = ob_get_clean();
445 - }
446 - }
447 -
448 -
449 - if (!empty($warnings) && strpos($warnings, 'bloque')) {
450 - $result = false;
451 - }
452 -
453 - $this->mailHeader = '';
454 -
455 - $receivers = [];
456 - foreach ($this->to as $oneReceiver) {
457 - $receivers[] = $oneReceiver[0];
458 - }
459 -
460 - if (!$result) {
461 - $this->reportMessage = acym_translationSprintf('ACYM_SEND_ERROR', '<b>'.$this->Subject.'</b>', '<b>'.implode(' , ', $receivers).'</b>');
462 - if (!empty($this->ErrorInfo)) {
463 - $this->reportMessage .= " \n\n ".$this->ErrorInfo;
464 - }
465 - if (!empty($warnings)) {
466 - $this->reportMessage .= " \n\n ".$warnings;
467 - }
468 - $this->errorNumber = 1;
469 - if ($this->report) {
470 - $this->reportMessage = str_replace(
471 - 'Could not instantiate mail function',
472 - '<a target="_blank" href="'.ACYM_DOCUMENTATION.'faq/could-not-instantiate-mail-function">'.acym_translation('ACYM_COUND_NOT_INSTANCIATE_MAIL_FUCNTION').'</a>',
473 - $this->reportMessage
474 - );
475 - acym_enqueueMessage(nl2br($this->reportMessage), 'error');
476 - }
477 - } else {
478 - if ($this->isSendingMethodByListActive) {
479 - $this->reportMessage = acym_translationSprintf(
480 - 'ACYM_SEND_SUCCESS_WITH_SENDING_METHOD',
481 - '<b>'.$this->Subject.'</b>',
482 - '<b>'.implode(' , ', $receivers).'</b>',
483 - '<b>'.$this->currentSendingMethod.'</b>'
484 - );
485 - } else {
486 - $this->reportMessage = acym_translationSprintf('ACYM_SEND_SUCCESS', '<b>'.$this->Subject.'</b>', '<b>'.implode(' , ', $receivers).'</b>');
487 - }
488 -
489 - if (!empty($warnings)) {
490 - $this->reportMessage .= " \n\n ".$warnings;
491 - }
492 -
493 - if ($this->report && acym_isAdmin()) {
494 - acym_enqueueMessage(preg_replace('#(<br( ?/)?>){2}#', '<br />', nl2br($this->reportMessage)), 'info');
495 - }
496 - }
497 -
498 - return $result;
499 - }
500 -
501 - public function clearAll(): void
502 - {
503 - $this->Subject = '';
504 - $this->Body = '';
505 - $this->AltBody = '';
506 - $this->ClearAllRecipients();
507 - $this->ClearAttachments();
508 - $this->ClearCustomHeaders();
509 - $this->ClearReplyTos();
510 - $this->errorNumber = 0;
511 - $this->MessageID = '';
512 - $this->ErrorInfo = '';
513 - $this->setFrom($this->getSendSettings('from_email'), $this->getSendSettings('from_name'));
514 - }
515 -
516 - public function load(int $mailId, ?object $user = null): ?object
517 - {
518 - if (isset($this->defaultMail[$mailId])) {
519 - return $this->defaultMail[$mailId];
520 - }
521 -
522 - if (!empty($this->overrideEmailToSend)) {
523 - $this->defaultMail[$mailId] = $this->overrideEmailToSend;
524 - } else {
525 - $this->defaultMail[$mailId] = $this->mailClass->getOneById($mailId, true);
526 - }
527 -
528 - global $acymLanguages;
529 - if (!$this->isAbTest && empty($this->overrideEmailToSend) && acym_isMultilingual()) {
530 - $defaultLanguage = $this->config->get('multilingual_default', ACYM_DEFAULT_LANGUAGE);
531 - $mails = $this->mailClass->getMultilingualMails($mailId);
532 -
533 - $this->userLanguage = !empty($user->language) ? $user->language : $defaultLanguage;
534 -
535 - if (!empty($mails)) {
536 - $languages = array_keys($mails);
537 - if (count($languages) == 1) {
538 - $key = $languages[0];
539 - } elseif (empty($mails[$this->userLanguage])) {
540 - $key = $defaultLanguage;
541 - } else {
542 - $key = $this->userLanguage;
543 - }
544 -
545 - if (isset($mails[$key])) {
546 - $this->defaultMail[$mailId] = $mails[$key];
547 - }
548 - } else {
549 - unset($this->defaultMail[$mailId]);
550 -
551 - return null;
552 - }
553 -
554 - $acymLanguages['userLanguage'] = $this->userLanguage;
555 - $this->setFrom($this->getSendSettings('from_email'), $this->getSendSettings('from_name'));
556 - }
557 -
558 - if (empty($this->defaultMail[$mailId]->id)) {
559 - unset($this->defaultMail[$mailId]);
560 -
561 - return null;
562 - }
563 -
564 - if (!empty($this->defaultMail[$mailId]->attachments)) {
565 - $this->defaultMail[$mailId]->attach = [];
566 -
567 - $attachments = json_decode($this->defaultMail[$mailId]->attachments);
568 - foreach ($attachments as $oneAttach) {
569 - $attach = new \stdClass();
570 - $attach->name = basename($oneAttach->filename);
571 - $attach->filename = str_replace(['/', '\\'], DS, ACYM_ROOT).$oneAttach->filename;
572 - $attach->url = ACYM_LIVE.$oneAttach->filename;
573 - $this->defaultMail[$mailId]->attach[] = $attach;
574 - }
575 - }
576 -
577 -
578 - $this->mailId = $mailId;
579 - $this->id = $this->mailId;
580 - $this->mail = clone $this->defaultMail[$mailId];
581 - acym_trigger('replaceContent', [&$this->defaultMail[$mailId], true]);
582 -
583 - $this->prepareEmailContent($mailId);
584 - if (!$this->isTest) {
585 - $this->storeArchiveVersion($mailId);
586 - }
587 -
588 - return $this->defaultMail[$mailId];
589 - }
590 -
591 - public function sendOne($mailId, $user, array $options = []): bool
592 - {
593 - $this->clearAll();
594 -
595 - $receiver = $this->loadUser($user);
596 - $this->isTest = !empty($options['isTest']);
597 - $this->dtextsFailed = false;
598 -
599 - if (empty($receiver->email)) {
600 - $this->errorNumber = 4;
601 - $this->reportMessage = acym_translationSprintf('ACYM_SEND_ERROR_USER', '<b><i>'.acym_escape($user).'</i></b>');
602 - if ($this->report) {
603 - acym_enqueueMessage($this->reportMessage, 'error');
604 - }
605 -
606 - return false;
607 - }
608 -
609 - $mailId = intval($mailId);
610 - $receiver->id = intval($receiver->id);
611 -
612 - if (!$this->load($mailId, $receiver)) {
613 - $this->reportMessage = 'Can not load the email with ID n°'.$mailId;
614 - $this->errorNumber = 2;
615 -
616 - if ($this->report) {
617 - acym_enqueueMessage($this->reportMessage, 'error');
618 - }
619 -
620 - return false;
621 - }
622 -
623 - $this->prepareContent($mailId, $options);
624 - $this->prepareHeaders($mailId, $receiver->id, $options);
625 - $this->prepareAddresses($mailId, $receiver);
626 - $this->prepareBcc($mailId, $options);
627 - $this->prepareAttachments($mailId, $options);
628 - $this->replaceDynamicContent($mailId);
629 - $this->prepareTracking($mailId, $receiver);
630 -
631 - if (!$this->handleDtexts($receiver)) {
632 - $this->dtextsFailed = true;
633 -
634 - return false;
635 - }
636 - $status = $this->send();
637 -
638 - $this->initStatistics($status, $receiver->id);
639 -
640 - return $status;
641 - }
642 -
643 - public function triggerFollowUpAgain(string $mailId, string $userId): void
644 - {
645 - if ($this->defaultMail[$mailId]->type !== MailClass::TYPE_FOLLOWUP) {
646 - return;
647 - }
648 -
649 - $followUpClass = new FollowupClass();
650 - $followUp = $followUpClass->getOneByMailId(intval($mailId));
651 -
652 - if (empty($followUp)) {
653 - return;
654 - }
655 -
656 - if (empty($followUp->loop)) {
657 - return;
658 - }
659 -
660 - $lastEmail = $followUpClass->getLastEmail(intval($followUp->id));
661 - if (empty($lastEmail) || $lastEmail->id != $mailId) {
662 - return;
663 - }
664 -
665 - $delay = 0;
666 - if (!empty($followUp->loop_delay)) {
667 - $delay = $followUp->loop_delay;
668 - }
669 -
670 - $mailToSkip = [];
671 - if (!empty($followUp->loop_mail_skip)) {
672 - $mailToSkip = json_decode($followUp->loop_mail_skip);
673 - }
674 -
675 - $followUpClass->triggerFollowUp(intval($followUp->id), intval($userId), $delay, $mailToSkip);
676 - }
677 -
678 - public function statClick(int $mailId, int $userid, bool $fromStat = false): void
679 - {
680 - if (!$fromStat && !in_array($this->type, MailClass::TYPES_WITH_STATS)) {
681 - return;
682 - }
683 -
684 - $urlClass = new UrlClass();
685 - $urls = [];
686 -
687 - $trackingSystemExternalWebsite = $this->config->get('trackingsystemexternalwebsite', 1);
688 - $trackingSystem = $this->config->get('trackingsystem', 'acymailing');
689 - if (false === strpos($trackingSystem, 'acymailing') && false === strpos($trackingSystem, 'google')) {
690 - return;
691 - }
692 -
693 - if (strpos($trackingSystem, 'google') !== false) {
694 - $mail = $this->mailClass->getOneById($mailId);
695 - $campaignClass = new CampaignClass();
696 - $campaign = $campaignClass->getOneCampaignByMailId($mailId);
697 -
698 - $utmCampaign = acym_getAlias($mail->subject);
699 - }
700 -
701 - preg_match_all('#<[^>]* href[ ]*=[ ]*"(?!mailto:|\#|ymsgr:|callto:|file:|ftp:|webcal:|skype:|tel:)([^"]+)"#Ui', $this->body, $results);
702 - if (empty($results)) {
703 - return;
704 - }
705 -
706 - $countLinks = array_count_values($results[1]);
707 - if (array_product($countLinks) != 1) {
708 - $previousLinkHandled = '';
709 - foreach ($results[1] as $key => $url) {
710 - if ($countLinks[$url] === 1) {
711 - continue;
712 - }
713 -
714 - $previousIsOutlook = false;
715 - if (strpos($results[0][$key], '<v:roundrect') === 0) {
716 - $previousLinkHandled = $results[0][$key];
717 - if ($countLinks[$url] === 2) {
718 - $countLinks[$url] = 1;
719 - continue;
720 - }
721 - } elseif (strpos($previousLinkHandled, '<v:roundrect') === 0) {
722 - $previousIsOutlook = true;
723 - }
724 - $previousLinkHandled = $results[0][$key];
725 -
726 - if (!$previousIsOutlook) {
727 - $countLinks[$url]--;
728 - }
729 -
730 - $toAddUrl = (strpos($url, '?') === false ? '?' : '&').'idU='.$countLinks[$url];
731 -
732 - if ($previousIsOutlook) {
733 - $countLinks[$url]--;
734 - }
735 -
736 - $posHash = strpos($url, '#');
737 - if ($posHash !== false) {
738 - $newURL = substr($url, 0, $posHash).$toAddUrl.substr($url, $posHash);
739 - } else {
740 - $newURL = $url.$toAddUrl;
741 - }
742 -
743 - $this->body = preg_replace('#href="('.preg_quote($url, '#').')"#Uis', 'href="'.$newURL.'"', $this->body, 1);
744 -
745 - $results[0][$key] = 'href="'.$newURL.'"';
746 - $results[1][$key] = $newURL;
747 - }
748 - }
749 -
750 - foreach ($results[1] as $i => $url) {
751 - $urlsNotToTrack = [
752 - 'task=unsub',
753 - 'fonts.googleapis.com',
754 - ];
755 -
756 - $track = true;
757 -
758 - foreach ($urlsNotToTrack as $urlNotToTrack) {
759 - if (strpos($url, $urlNotToTrack)) {
760 - $track = false;
761 - break;
762 - }
763 - }
764 -
765 - if (isset($urls[$results[0][$i]]) || !$track) {
766 - continue;
767 - }
768 -
769 - $simplifiedUrl = str_replace(['https://', 'http://', 'www.'], '', $url);
770 - $simplifiedWebsite = str_replace(['https://', 'http://', 'www.'], '', ACYM_LIVE);
771 - $internalUrl = strpos($simplifiedUrl, rtrim($simplifiedWebsite, '/')) === 0;
772 -
773 - $subfolder = false;
774 - if ($internalUrl) {
775 - $urlWithoutBase = str_replace($simplifiedWebsite, '', $simplifiedUrl);
776 - if (strpos($urlWithoutBase, '/') || strpos($urlWithoutBase, '?')) {
777 - $slashPosition = strpos($urlWithoutBase, '/');
778 - $folderName = substr($urlWithoutBase, 0, !$slashPosition ? strpos($urlWithoutBase, '?') : $slashPosition);
779 - if (strpos($folderName, '.') === false) {
780 - $subfolder = @is_dir(ACYM_ROOT.$folderName);
781 - }
782 - }
783 - }
784 -
785 - if ((!$internalUrl || $subfolder) && $trackingSystemExternalWebsite != 1) {
786 - continue;
787 - }
788 -
789 - if (strpos($url, 'utm_source') === false && strpos($trackingSystem, 'google') !== false) {
790 - $idToUse = empty($campaign) ? $mailId : $campaign->id;
791 - $args = [];
792 - $args[] = empty($campaign->sending_params['utm_source']) ? 'utm_source=newsletter_'.$idToUse : 'utm_source='.urlencode($campaign->sending_params['utm_source']);
793 - $args[] = empty($campaign->sending_params['utm_medium']) ? 'utm_medium=email' : 'utm_medium='.urlencode($campaign->sending_params['utm_medium']);
794 - $args[] = empty($campaign->sending_params['utm_campaign']) ? 'utm_campaign='.$utmCampaign : 'utm_campaign='.urlencode($campaign->sending_params['utm_campaign']);
795 - $anchor = '';
796 - if (strpos($url, '#') !== false) {
797 - $anchor = substr($url, strpos($url, '#'));
798 - $url = substr($url, 0, strpos($url, '#'));
799 - }
800 -
801 - if (strpos($url, '?')) {
802 - $mytracker = $url.'&'.implode('&', $args);
803 - } else {
804 - $mytracker = $url.'?'.implode('&', $args);
805 - }
806 - $mytracker .= $anchor;
807 - $urls[$results[0][$i]] = str_replace($results[1][$i], $mytracker, $results[0][$i]);
808 -
809 - $url = $mytracker;
810 - }
811 -
812 - if (strpos($trackingSystem, 'acymailing') !== false) {
813 - $isAutologin = false;
814 - $autologinParams = 'autoSubId=%7Bsubscriber:id%7D&amp;subKey=%7Bsubscriber:key%7Curlencode%7D';
815 - if (strpos($url, $autologinParams) !== false) {
816 - $isAutologin = true;
817 - $url = str_replace(
818 - [
819 - '?'.$autologinParams.'&amp;',
820 - '?'.$autologinParams,
821 - '&amp;'.$autologinParams,
822 - ],
823 - [
824 - '?',
825 - '',
826 - '',
827 - ],
828 - $url
829 - );
830 - }
831 -
832 - if (preg_match('#passw|modify|\{|%7B#i', $url)) {
833 - continue;
834 - }
835 -
836 - if (!$fromStat) {
837 - $mytracker = $urlClass->getUrl($url, $mailId, $userid);
838 - }
839 -
840 - if (empty($mytracker)) {
841 - continue;
842 - }
843 -
844 - if ($isAutologin) {
845 - $mytracker .= strpos($mytracker, '?') === false ? '?' : '&amp;';
846 - $mytracker .= $autologinParams;
847 - }
848 -
849 - $urls[$results[0][$i]] = str_replace($results[1][$i], $mytracker, $results[0][$i]);
850 - }
851 - }
852 -
853 - $this->body = str_replace(array_keys($urls), $urls, $this->body);
854 - }
855 -
856 - public function textVersion(string $html, bool $fullConvert = true): string
857 - {
858 - $html = acym_absoluteURL($html);
859 -
860 - if ($fullConvert) {
861 - $html = preg_replace('# +#', ' ', $html);
862 - $html = str_replace(["\n", "\r", "\t"], '', $html);
863 - }
864 -
865 - $removepictureslinks = "#< *a[^>]*> *< *img[^>]*> *< *\/ *a *>#isU";
866 - $removeScript = "#< *script(?:(?!< */ *script *>).)*< */ *script *>#isU";
867 - $removeStyle = "#< *style(?:(?!< */ *style *>).)*< */ *style *>#isU";
868 - $removeStrikeTags = '#< *strike(?:(?!< */ *strike *>).)*< */ *strike *>#iU';
869 - $replaceByTwoReturnChar = '#< *(h1|h2)[^>]*>#Ui';
870 - $replaceByStars = '#< *li[^>]*>#Ui';
871 - $replaceByReturnChar1 = '#< */ *(li|td|dt|tr|div|p)[^>]*> *< *(li|td|dt|tr|div|p)[^>]*>#Ui';
872 - $replaceByReturnChar = '#< */? *(br|p|h1|h2|legend|h3|li|ul|dd|dt|h4|h5|h6|tr|td|div)[^>]*>#Ui';
873 - $replaceLinks = '/< *a[^>]*href *= *"([^#][^"]*)"[^>]*>(.+)< *\/ *a *>/Uis';
874 -
875 - $text = preg_replace(
876 - [
877 - $removepictureslinks,
878 - $removeScript,
879 - $removeStyle,
880 - $removeStrikeTags,
881 - $replaceByTwoReturnChar,
882 - $replaceByStars,
883 - $replaceByReturnChar1,
884 - $replaceByReturnChar,
885 - $replaceLinks,
886 - ],
887 - ['', '', '', '', "\n\n", "\n* ", "\n", "\n", '${2} ( ${1} )'],
888 - $html
889 - );
890 -
891 - $text = preg_replace('#(&lt;|&\#60;)([^ \n\r\t])#i', '&lt; ${2}', $text);
892 -
893 - $text = str_replace([" ", "&nbsp;"], ' ', strip_tags($text));
894 -
895 - $text = trim(@html_entity_decode($text, ENT_QUOTES, 'UTF-8'));
896 -
897 - if ($fullConvert) {
898 - $text = preg_replace('# +#', ' ', $text);
899 - $text = preg_replace('#\n *\n\s+#', "\n\n", $text);
900 - }
901 -
902 - return $text;
903 - }
904 -
905 - protected function embedImages(): bool
906 - {
907 - preg_match_all('/(src|background)=[\'|"]([^"\']*)[\'|"]/Ui', $this->Body, $images);
908 -
909 - if (empty($images[2])) {
910 - return true;
911 - }
912 -
913 - $embedSuccess = true;
914 -
915 - $mimetypes = [
916 - 'bmp' => 'image/bmp',
917 - 'gif' => 'image/gif',
918 - 'jpeg' => 'image/jpeg',
919 - 'jpg' => 'image/jpeg',
920 - 'jpe' => 'image/jpeg',
921 - 'png' => 'image/png',
922 - 'tiff' => 'image/tiff',
923 - 'tif' => 'image/tiff',
924 - ];
925 -
926 - $allImages = [];
927 -
928 - foreach ($images[2] as $i => $url) {
929 - if (isset($allImages[$url])) {
930 - continue;
931 - }
932 -
933 - if (strpos($url, 'ctrl=') !== false) {
934 - continue;
935 - }
936 -
937 - $allImages[$url] = 1;
938 -
939 - $path = acym_internalUrlToPath($url);
940 - $path = $this->removeAdditionalParams($path);
941 -
942 - $filename = str_replace(['%', ' '], '_', basename($url));
943 - $filename = $this->removeAdditionalParams($filename);
944 -
945 - $md5 = md5($filename);
946 - $cid = 'cid:'.$md5;
947 - $fileParts = explode(".", $filename);
948 - if (empty($fileParts[1])) {
949 - continue;
950 - }
951 - $ext = strtolower($fileParts[1]);
952 - if (!isset($mimetypes[$ext])) {
953 - continue;
954 - }
955 -
956 - if ($this->addEmbeddedImage($path, $md5, $filename, 'base64', $mimetypes[$ext])) {
957 - $this->Body = preg_replace('/'.preg_quote($images[0][$i], '/').'/Ui', $images[1][$i].'="'.$cid.'"', $this->Body);
958 - } else {
959 - $embedSuccess = false;
960 - }
961 - }
962 -
963 - return $embedSuccess;
964 - }
965 -
966 - public function cleanText(?string $text): string
967 - {
968 - return trim(preg_replace('/(%0A|%0D|\n+|\r+)/i', '', (string)$text));
969 - }
970 -
971 - public function addParamInfo(): void
972 - {
973 - if (!empty($_SERVER)) {
974 - $serverinfo = [];
975 - foreach ($_SERVER as $oneKey => $oneInfo) {
976 - $serverinfo[] = $oneKey.' => '.strip_tags(print_r($oneInfo, true));
977 - }
978 - $this->addParam('serverinfo', implode('<br />', $serverinfo));
979 - }
980 -
981 - if (!empty($_REQUEST)) {
982 - $postinfo = [];
983 - foreach ($_REQUEST as $oneKey => $oneInfo) {
984 - $postinfo[] = $oneKey.' => '.strip_tags(print_r($oneInfo, true));
985 - }
986 - $this->addParam('postinfo', implode('<br />', $postinfo));
987 - }
988 - }
989 -
990 - public function addParam(string $name, $value): void
991 - {
992 - $tagName = '{'.$name.'}';
993 - $this->parameters[$tagName] = $value;
994 - }
995 -
996 - public function overrideEmail(array $options): bool
997 - {
998 - $overrideAllEmails = $this->config->get('send_website_emails', 0) == 1;
999 -
1000 - $overrideClass = new OverrideClass();
1001 - $override = $overrideClass->getMailByBaseContent($options['subject'], $options['message']);
1002 -
1003 - if (empty($override) && !$overrideAllEmails) {
1004 - return false;
1005 - }
1006 -
1007 - $this->autoAddUser = true;
1008 -
1009 - if (empty($override)) {
1010 - $this->trackEmail = false;
1011 -
1012 - return $this->overrideAllEmails($options);
1013 - } else {
1014 - $this->trackEmail = true;
1015 -
1016 - return $this->sendOverride($override, $options);
1017 - }
1018 - }
1019 -
1020 - private function getSendingMethodSettings(string $settingName, string $default = ''): string
1021 - {
1022 - if (empty($this->currentMethodSetting)) {
1023 - return $this->config->get($settingName, $default);
1024 - }
1025 -
1026 - return $this->currentMethodSetting[$settingName] ?? $default;
1027 - }
1028 -
1029 - private function getSendingMethod(): string
1030 - {
1031 - $this->currentMethodSetting = [];
1032 -
1033 - $sendingMethods = $this->config->get('sending_method_list', '{}');
1034 - $sendingMethods = json_decode($sendingMethods, true);
1035 - $sendingMethodsByList = $this->config->get('sending_method_list_by_list', '{}');
1036 - $sendingMethodsByList = json_decode($sendingMethodsByList, true);
1037 -
1038 - if (empty($this->listsIds) || empty($sendingMethods) || empty($sendingMethodsByList) || empty($sendingMethodsByList[$this->listsIds[0]])) {
1039 - return $this->config->get('mailer_method', 'phpmail');
1040 - }
1041 -
1042 - $sendingMethodIds = [];
1043 -
1044 - foreach ($this->listsIds as $listId) {
1045 - if (!empty($sendingMethodsByList[$listId])) {
1046 - $sendingMethodIds[] = $sendingMethodsByList[$listId];
1047 - }
1048 - }
1049 -
1050 - if (count($sendingMethodIds) !== count($this->listsIds) || count(array_unique($sendingMethodIds)) !== 1) {
1051 - return $this->config->get('mailer_method', 'phpmail');
1052 - }
1053 -
1054 - $sendingMethodId = $sendingMethodIds[0];
1055 -
1056 - if (empty($sendingMethods[$sendingMethodId])) {
1057 - return $this->config->get('mailer_method', 'phpmail');
1058 - }
1059 -
1060 - $this->currentMethodSetting = $sendingMethods[$sendingMethodId];
1061 -
1062 - return $sendingMethods[$sendingMethodId]['mailer_method'];
1063 - }
1064 -
1065 - private function isExternal(string $method): void
1066 - {
1067 - $this->Mailer = 'external';
1068 - $this->externalMailer = $method;
1069 - }
1070 -
1071 - private function storeArchiveVersion(int $mailId): void
1072 - {
1073 - if ($this->defaultMail[$mailId]->type !== MailClass::TYPE_STANDARD) {
1074 - return;
1075 - }
1076 -
1077 - $mailArchive = new \stdClass();
1078 -
1079 - $alreadyExisting = $this->mailArchiveClass->getOneByMailId($mailId);
1080 - if (!empty($alreadyExisting)) {
1081 - $mailArchive->id = $alreadyExisting->id;
1082 - }
1083 -
1084 - $mailArchive->mail_id = $mailId;
1085 - $mailArchive->date = time();
1086 - $mailArchive->body = $this->defaultMail[$mailId]->body;
1087 - $mailArchive->subject = $this->defaultMail[$mailId]->subject;
1088 - $mailArchive->settings = $this->defaultMail[$mailId]->settings;
1089 - $mailArchive->stylesheet = $this->defaultMail[$mailId]->stylesheet;
1090 - $mailArchive->attachments = $this->defaultMail[$mailId]->attachments;
1091 - $this->mailArchiveClass->save($mailArchive);
1092 - }
1093 -
1094 - private function canTrack(int $mailId, object $user): bool
1095 - {
1096 - if ($this->isTest || empty($mailId) || empty($user) || !isset($user->tracking) || $user->tracking != 1) {
1097 - return false;
1098 - }
1099 -
1100 - $mail = $this->mailClass->getOneById($mailId);
1101 - if (!empty($mail) && $mail->tracking != 1) {
1102 - return false;
1103 - }
1104 -
1105 - $lists = $this->mailClass->getAllListsByMailIdAndUserId($mailId, $user->id);
1106 -
1107 - foreach ($lists as $list) {
1108 - if ($list->tracking != 1) {
1109 - return false;
1110 - }
1111 - }
1112 -
1113 - return true;
1114 - }
1115 -
1116 - private function loadUser($user, bool $force = false): object
1117 - {
1118 - if (is_string($user) && strpos($user, '@')) {
1119 - $receiver = $this->userClass->getOneByEmail($user);
1120 -
1121 - if (empty($receiver)) {
1122 - if (($force || $this->autoAddUser) && acym_isValidEmail($user)) {
1123 - $newUser = new \stdClass();
1124 - $newUser->email = $user;
1125 - $this->userClass->checkVisitor = false;
1126 - $this->userClass->sendConf = false;
1127 - acym_setVar('acy_source', 'When sending a test');
1128 - $this->userClass->triggers = $this->userCreationTriggers;
1129 - $userId = $this->userClass->save($newUser);
1130 - $receiver = $this->userClass->getOneById($userId);
1131 - } else {
1132 - throw new Exception(acym_translation('ACYM_USER_NOT_FOUND'));
1133 - }
1134 - }
1135 - } elseif (is_object($user)) {
1136 - $receiver = $user;
1137 - } else {
1138 - $receiver = $this->userClass->getOneById($user);
1139 - }
1140 -
1141 - $this->userLanguage = empty($receiver->language) ? acym_getLanguageTag() : $receiver->language;
1142 - $this->receiverEmail = $receiver->email;
1143 -
1144 - return $receiver;
1145 - }
1146 -
1147 - private function prepareContent(int $mailId, array $options): void
1148 - {
1149 - $this->isHTML();
1150 -
1151 - if (!empty($this->defaultMail[$mailId]->stylesheet)) {
1152 - $this->stylesheet = $this->defaultMail[$mailId]->stylesheet;
1153 - }
1154 - $this->settings = empty($this->defaultMail[$mailId]->settings) ? [] : json_decode($this->defaultMail[$mailId]->settings, true);
1155 -
1156 - $this->Subject = $this->defaultMail[$mailId]->subject;
1157 - $this->Body = $this->defaultMail[$mailId]->body;
1158 - if ($this->isTest && !empty($options['testNote'])) {
1159 - $this->Body = '<div style="text-align: center; padding: 25px; font-family: Poppins; font-size: 20px">'.$options['testNote'].'</div>'.$this->Body;
1160 - }
1161 -
1162 - if (!empty($this->introtext)) {
1163 - $this->Body = $this->introtext.$this->Body;
1164 - }
1165 -
1166 - if (!empty($this->defaultMail[$mailId]->preheader)) {
1167 - $preHeader = '<!--[if !mso 9]><!--><div style="visibility:hidden;mso-hide:all;font-size:0;color:transparent;height:0;line-height:0;max-height:0;max-width:0;opacity:0;overflow:hidden;">';
1168 - $preHeader .= $this->defaultMail[$mailId]->preheader.str_repeat('&nbsp;&zwnj;', 100);
1169 - $preHeader .= '</div><!--<![endif]-->';
1170 -
1171 - preg_match('#(<(.*)<body(.*)>)#Uis', $this->Body, $matches);
1172 - if (empty($matches) || empty($matches[1])) {
1173 - $this->Body = $preHeader.$this->Body;
1174 - } else {
1175 - $this->Body = $matches[1].$preHeader.str_replace($matches[1], '', $this->Body);
1176 - }
1177 - }
1178 -
1179 - if (ACYM_CMS === 'wordpress') {
1180 - ob_start();
1181 - $this->Body = do_shortcode($this->Body);
1182 - ob_end_clean();
1183 - }
1184 - }
1185 -
1186 - private function prepareHeaders(int $mailId, int $receiverId, array $options): void
1187 - {
1188 - $subject = base64_encode(rand(0, 9999999)).'AC'.$receiverId.'Y'.$this->defaultMail[$mailId]->id.'BA'.base64_encode(time().rand(0, 99999));
1189 - $this->MessageID = '<'.preg_replace('|[^a-z0-9+_]|i', '', $subject).'@'.$this->serverHostname().'>';
1190 - $this->addCustomHeader('Feedback-ID', $this->defaultMail[$mailId]->id.':'.$receiverId.':'.$this->defaultMail[$mailId]->type.':'.base64_encode(ACYM_ROOT));
1191 -
1192 - if (!empty($this->defaultMail[$mailId]->headers)) {
1193 - $this->mailHeader = $this->defaultMail[$mailId]->headers;
1194 - }
1195 -
1196 - if (!empty($options['headers'])) {
1197 - foreach ($options['headers'] as $headerName => $headerValue) {
1198 - $this->addCustomHeader(trim($headerName), trim($headerValue));
1199 - }
1200 - }
1201 - }
1202 -
1203 - private function prepareAddresses(int $mailId, object $receiver): void
1204 - {
1205 - $receiverName = '';
1206 - if ($this->config->get('add_names', true)) {
1207 - $receiverName = $this->cleanText($receiver->name);
1208 - if ($receiverName == $this->cleanText($receiver->email)) {
1209 - $receiverName = '';
1210 - }
1211 - }
1212 - $this->addAddress($this->cleanText($receiver->email), $receiverName);
1213 -
1214 - $this->setFrom($this->getSendSettings('from_email', $mailId), $this->getSendSettings('from_name', $mailId));
1215 - $this->acymAddReplyTo($this->defaultMail[$mailId]->reply_to_email ?? '', $this->defaultMail[$mailId]->reply_to_name ?? '');
1216 -
1217 - if (!empty($this->defaultMail[$mailId]->bounce_email)) {
1218 - $this->Sender = $this->cleanText($this->defaultMail[$mailId]->bounce_email);
1219 - } else {
1220 - $this->Sender = $this->cleanText($this->config->get('bounce_email'));
1221 - }
1222 - }
1223 -
1224 - private function prepareBcc(int $mailId, array $options): void
1225 - {
1226 - $bccAddresses = [];
1227 -
1228 - if (!empty($options['bcc'])) {
1229 - $bccAddresses = $options['bcc'];
1230 - }
1231 -
1232 - if (!empty($this->defaultMail[$mailId]->bcc)) {
1233 - $emailBccAddresses = explode(';', trim(str_replace([',', ' '], ';', $this->defaultMail[$mailId]->bcc)));
1234 - $bccAddresses = array_unique(array_merge($bccAddresses, $emailBccAddresses));
1235 - }
1236 -
1237 - if (!empty($bccAddresses)) {
1238 - $bccAddresses = array_filter($bccAddresses);
1239 - foreach ($bccAddresses as $oneBccAddress) {
1240 - $this->loadUser($oneBccAddress, true);
1241 - $this->addBCC($oneBccAddress);
1242 - }
1243 - }
1244 - }
1245 -
1246 - private function prepareAttachments(int $mailId, array $options): void
1247 - {
1248 - $attachments = [];
1249 -
1250 - if (!empty($this->defaultMail[$mailId]->attach)) {
1251 - $attachments = $this->defaultMail[$mailId]->attach;
1252 - }
1253 -
1254 - if (!empty($options['attachments'])) {
1255 - $attachments = array_merge($attachments, $options['attachments']);
1256 - }
1257 -
1258 - if (empty($attachments)) {
1259 - return;
1260 - }
1261 -
1262 - if ($this->config->get('embed_files')) {
1263 - foreach ($attachments as $attachment) {
1264 - $this->addAttachment($attachment->filename, $attachment->name);
1265 - }
1266 - } else {
1267 - $attachStringHTML = '<fieldset><legend>'.acym_translation('ACYM_ATTACHMENTS').'</legend><table>';
1268 - foreach ($attachments as $attachment) {
1269 - $attachStringHTML .= '<tr><td><a href="'.$attachment->url.'" target="_blank">'.$attachment->name.'</a></td></tr>';
1270 - }
1271 - $attachStringHTML .= '</table></fieldset>';
1272 -
1273 - if ($this->config->get('attachments_position', 'bottom') === 'top') {
1274 - $this->Body = $attachStringHTML.'<br />'.$this->Body;
1275 - } else {
1276 - $this->Body .= '<br />'.$attachStringHTML;
1277 - }
1278 - }
1279 - }
1280 -
1281 - private function replaceDynamicContent(int $mailId): void
1282 - {
1283 - $this->replaceParams();
1284 -
1285 - $this->body = &$this->Body;
1286 - $this->altbody = &$this->AltBody;
1287 - $this->subject = &$this->Subject;
1288 - $this->from = &$this->From;
1289 - $this->fromName = &$this->FromName;
1290 - $this->replyto = &$this->ReplyTo;
1291 - $this->replyname = $this->defaultMail[$mailId]->reply_to_name ?? '';
1292 - $this->replyemail = $this->defaultMail[$mailId]->reply_to_email ?? '';
1293 - $this->mailId = intval($this->defaultMail[$mailId]->id);
1294 - $this->id = $this->mailId;
1295 - $this->creator_id = intval($this->defaultMail[$mailId]->creator_id);
1296 - $this->type = $this->defaultMail[$mailId]->type;
1297 - $this->stylesheet = &$this->stylesheet;
1298 - $this->links_language = $this->defaultMail[$mailId]->links_language;
1299 - }
1300 -
1301 - private function prepareTracking(int $mailId, object $receiver): void
1302 - {
1303 - if ($this->canTrack($mailId, $receiver)) {
1304 - $receiver->id = intval($receiver->id);
1305 - $this->statPicture($this->mailId, $receiver->id);
1306 - $this->body = acym_absoluteURL($this->body);
1307 - $this->statClick($this->mailId, $receiver->id);
1308 - if (acym_isTrackingSalesActive()) {
1309 - $this->trackingSales($this->mailId, $receiver->id);
1310 - }
1311 - }
1312 - }
1313 -
1314 - private function handleDtexts(object $receiver): bool
1315 - {
1316 - $this->replaceParams();
1317 -
1318 - if (strpos($receiver->email, '@mt.acyba.com') !== false) {
1319 - $currentUser = $this->userClass->getOneByEmail(acym_currentUserEmail());
1320 - if (empty($currentUser)) {
1321 - $currentUser = $receiver;
1322 - }
1323 - $result = acym_trigger('replaceUserInformation', [&$this, &$currentUser, true]);
1324 - } else {
1325 - $result = acym_trigger('replaceUserInformation', [&$this, &$receiver, true]);
1326 - if (!empty($result)) {
1327 - foreach ($result as $oneResult) {
1328 - if (!empty($oneResult) && !$oneResult['send']) {
1329 - $this->reportMessage = $oneResult['message'];
1330 -
1331 - return false;
1332 - }
1333 - }
1334 - }
1335 - }
1336 -
1337 - global $acymLanguages;
1338 - if (!empty($acymLanguages['userLanguage'])) {
1339 - unset($acymLanguages['userLanguage']);
1340 - }
1341 -
1342 - foreach ($result as $oneResult) {
1343 - if (!empty($oneResult['emogrifier'])) {
1344 - $this->prepareEmailContent();
1345 - break;
1346 - }
1347 - }
1348 -
1349 - if ($this->config->get('multiple_part', false)) {
1350 - $this->altbody = $this->textVersion($this->Body);
1351 - }
1352 -
1353 - $this->replaceParams();
1354 -
1355 - return true;
1356 - }
1357 -
1358 - private function initStatistics(bool $status, int $receiverId): void
1359 - {
1360 - if ($this->trackEmail) {
1361 - $statsAdd = [];
1362 - $statsAdd[$this->mailId][intval($status)][] = $receiverId;
1363 -
1364 - $queueHelper = new QueueHelper();
1365 - $queueHelper->statsAdd($statsAdd);
1366 - $this->trackEmail = false;
1367 - }
1368 - }
1369 -
1370 - private function trackingSales(int $mailId, int $userId): void
1371 - {
1372 - preg_match_all('#href[ ]*=[ ]*"(?!mailto:|\#|ymsgr:|callto:|file:|ftp:|webcal:|skype:|tel:)([^"]+)"#Ui', $this->body, $results);
1373 - if (empty($results)) {
1374 - return;
1375 - }
1376 -
1377 - foreach ($results[1] as $url) {
1378 - $simplifiedUrl = str_replace(['https://', 'http://', 'www.'], '', $url);
1379 - $simplifiedWebsite = str_replace(['https://', 'http://', 'www.'], '', ACYM_LIVE);
1380 - if (strpos($simplifiedUrl, rtrim($simplifiedWebsite, '/')) === false || strpos($url, 'task=unsub')) continue;
1381 -
1382 - $toAddUrl = (strpos($url, '?') === false ? '?' : '&').'linkReferal='.$mailId.'-'.$userId;
1383 -
1384 - $posHash = strpos($url, '#');
1385 - if ($posHash !== false) {
1386 - $newURL = substr($url, 0, $posHash).$toAddUrl.substr($url, $posHash);
1387 - } else {
1388 - $newURL = $url.$toAddUrl;
1389 - }
1390 -
1391 - $this->body = preg_replace('#href="('.preg_quote($url, '#').')"#Uis', 'href="'.$newURL.'"', $this->body);
1392 - }
1393 - }
1394 -
1395 - private function statPicture(int $mailId, int $userId): void
1396 - {
1397 - $pictureLink = acym_frontendLink('frontstats&task=openStats&id='.$mailId.'&userid='.$userId, true, false);
1398 -
1399 - $statPicture = '<img class="spict" alt="Statistics image" src="'.$pictureLink.'" border="0" width="50" height="1" />';
1400 -
1401 - if (strpos($this->body, '</body>')) {
1402 - $this->body = str_replace('</body>', $statPicture.'</body>', $this->body);
1403 - } else {
1404 - $this->body .= $statPicture;
1405 - }
1406 - }
1407 -
1408 - private function removeAdditionalParams(string $url): string
1409 - {
1410 - $additionalParamsPos = strpos($url, '?');
1411 - if (!empty($additionalParamsPos)) {
1412 - $url = substr($url, 0, $additionalParamsPos);
1413 - }
1414 -
1415 - return $url;
1416 - }
1417 -
1418 - private function replaceParams(): void
1419 - {
1420 - if (empty($this->parameters)) {
1421 - return;
1422 - }
1423 -
1424 - $pluginHelper = new PluginHelper();
1425 -
1426 - $this->generateAllParams();
1427 -
1428 - $vars = [
1429 - 'Subject',
1430 - 'Body',
1431 - 'From',
1432 - 'FromName',
1433 - 'replyname',
1434 - 'replyemail',
1435 - ];
1436 -
1437 - foreach ($vars as $oneVar) {
1438 - if (!empty($this->$oneVar)) {
1439 - $this->$oneVar = $pluginHelper->replaceDText($this->$oneVar, $this->parameters);
1440 - }
1441 - }
1442 -
1443 - if (!empty($this->ReplyTo)) {
1444 - foreach ($this->ReplyTo as $i => $replyto) {
1445 - foreach ($replyto as $a => $oneval) {
1446 - $this->ReplyTo[$i][$a] = $pluginHelper->replaceDText($this->ReplyTo[$i][$a], $this->parameters);
1447 - }
1448 - }
1449 - }
1450 - }
1451 -
1452 - private function generateAllParams(): void
1453 - {
1454 - $result = '<table style="border:1px solid;border-collapse:collapse;" border="1" cellpadding="10"><tr><td>Tag</td><td>Value</td></tr>';
1455 - foreach ($this->parameters as $name => $value) {
1456 - if (!is_string($value)) continue;
1457 -
1458 - $result .= '<tr><td>'.trim($name, '{}').'</td><td>'.$value.'</td></tr>';
1459 - }
1460 - $result .= '</table>';
1461 - $this->addParam('allshortcodes', $result);
1462 - }
1463 -
1464 - private function sendOverride(object $override, array $options): bool
1465 - {
1466 - for ($i = 1 ; $i < count($override->parameters) ; $i++) {
1467 - $oneParam = $override->parameters[$i];
1468 -
1469 - $unmodified = $oneParam;
1470 - $oneParam = preg_replace(
1471 - '/(http|https):\/\/(.*)/',
1472 - '<a href="$1://$2" target="_blank">$1://$2</a>',
1473 - $oneParam,
1474 - -1,
1475 - $count
1476 - );
1477 - if ($count > 0) {
1478 - $this->addParam('link'.$i, $unmodified);
1479 - }
1480 - $this->addParam('param'.$i, $oneParam);
1481 - }
1482 -
1483 - $this->addParam('subject', $options['subject']);
1484 -
1485 - $this->overrideEmailToSend = $override;
1486 - $statusSend = $this->sendOne($override->id, $options['to'], $options);
1487 - if (!$statusSend && !empty($this->reportMessage)) {
1488 - $cronHelper = new CronHelper();
1489 - $cronHelper->saveReport([$this->reportMessage]);
1490 - }
1491 -
1492 - return $statusSend;
1493 - }
1494 -
1495 - public function getSendSettings(string $type, int $mailId = 0): string
1496 - {
1497 - if (!in_array($type, ['from_name', 'from_email', 'replyto_name', 'replyto_email', 'bounce_email'])) {
1498 - return '';
1499 - }
1500 -
1501 - $mailType = strpos($type, 'replyto') !== false ? str_replace('replyto', 'reply_to', $type) : $type;
1502 - if (!empty($mailId) && !empty($this->defaultMail[$mailId]->$mailType)) {
1503 - return $this->defaultMail[$mailId]->$mailType;
1504 - }
1505 -
1506 - $lang = empty($this->userLanguage) ? acym_getLanguageTag() : $this->userLanguage;
1507 - $setting = $this->config->get($type);
1508 - $translation = $this->config->get('sender_info_translation');
1509 -
1510 - if (!empty($translation)) {
1511 - $translation = json_decode($translation, true);
1512 -
1513 - if (!empty($translation[$lang][$type])) {
1514 - $setting = $translation[$lang][$type];
1515 - }
1516 - }
1517 -
1518 - return $setting;
1519 - }
1520 -
1521 - private function prepareEmailContent(int $mailId = 0): void
1522 - {
1523 - $this->handleRelativeURLs($mailId);
1524 - $this->inlineCSS($mailId);
1525 - $this->finalizeHtmlStructure($mailId);
1526 - }
1527 -
1528 - private function handleRelativeURLs(int $mailId): void
1529 - {
1530 - $mail = empty($mailId) ? $this : $this->defaultMail[$mailId];
1531 - $mail->body = acym_absoluteURL($mail->body);
1532 - }
1533 -
1534 - private function inlineCSS(int $mailId): void
1535 - {
1536 - $mail = empty($mailId) ? $this : $this->defaultMail[$mailId];
1537 -
1538 - global $emogrifiedMediaCSS;
1539 - $emogrifiedMediaCSS = '';
1540 -
1541 - $style = $this->getEmailStylesheet($mail);
1542 - $cssInliner = CssInlinerHelper::fromHtml($mail->body)->inlineCss(implode('', $style));
1543 - $domDocument = $cssInliner->getDomDocument();
1544 -
1545 - $mail->body = preg_replace(
1546 - [
1547 - '# id="mce_\d+"#Ui',
1548 - '#(style="[^"]+);"#Ui',
1549 - ],
1550 - [
1551 - '',
1552 - '$1"',
1553 - ],
1554 - HtmlPruner::fromDomDocument($domDocument)
1555 - ->removeRedundantClassesAfterCssInlined($cssInliner)
1556 - ->renderBodyContent()
1557 - );
1558 -
1559 - $mail->body = str_replace('&zwj;', '', $mail->body);
1560 -
1561 - $mail->body = preg_replace_callback(
1562 - '#style="([^"]+)"#Ui',
1563 - function ($matches) {
1564 - return 'style="'.str_replace(['; ', ': '], [';', ':'], $matches[1]).'"';
1565 - },
1566 - $mail->body
1567 - );
1568 - }
1569 -
1570 - private function finalizeHtmlStructure(int $mailId): void
1571 - {
1572 - $mail = empty($mailId) ? $this : $this->defaultMail[$mailId];
1573 -
1574 - $finalContent = '<html xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office">';
1575 - $finalContent .= '<head>';
1576 - $finalContent .= '<!--[if gte mso 9]><xml><o:OfficeDocumentSettings><o:AllowPNG/><o:PixelsPerInch>96</o:PixelsPerInch></o:OfficeDocumentSettings></xml><![endif]-->';
1577 - $finalContent .= '<meta http-equiv="Content-Type" content="text/html; charset='.strtolower($this->config->get('charset')).'" />'."\n";
1578 - $finalContent .= '<meta name="viewport" content="width=device-width, initial-scale=1.0" />'."\n";
1579 - $finalContent .= '<title>'.$mail->subject.'</title>'."\n";
1580 -
1581 - global $emogrifiedMediaCSS;
1582 - $finalContent .= '<style>'.$emogrifiedMediaCSS.'</style>';
1583 - $finalContent .= '<!--[if mso]><style type="text/css">#acym__wysid__template center > table { width: 580px; }</style><![endif]-->';
1584 - $finalContent .= '<!--[if !mso]><!--><style>#acym__wysid__template center > table { width: 100%; }</style><!--<![endif]-->';
1585 -
1586 - if (!empty($mail->headers)) {
1587 - $finalContent .= $mail->headers;
1588 - }
1589 - $finalContent .= '</head>';
1590 -
1591 - preg_match('@<[^>"t]*body[^>]*>@', $mail->body, $matches);
1592 - if (empty($matches[0])) {
1593 - $mail->body = '<body>'.$mail->body.'</body>';
1594 - } else {
1595 - preg_match('@<[^>"t]*/body[^>]*>@', $mail->body, $matches);
1596 - if (empty($matches[0])) {
1597 - $mail->body .= '</body>';
1598 - }
1599 - }
1600 -
1601 - $finalContent .= $mail->body;
1602 - $finalContent .= '</html>';
1603 -
1604 - $mail->body = $finalContent;
1605 - }
1606 -
1607 - private function getEmailStylesheet(object $mail): array
1608 - {
1609 - $style = [];
1610 -
1611 - if (strpos($mail->body, 'acym__wysid__template') !== false) {
1612 - static $foundationCSS = null;
1613 - if (empty($foundationCSS)) {
1614 - $foundationCSS = acym_fileGetContent(ACYM_MEDIA.'css'.DS.'libraries'.DS.'foundation_email.min.css');
1615 - $foundationCSS = str_replace('#acym__wysid__template ', '', $foundationCSS);
1616 - }
1617 - $style['foundation'] = $foundationCSS;
1618 - }
1619 -
1620 - static $emailFixes = null;
1621 - if (empty($emailFixes)) {
1622 - $emailFixes = acym_getEmailCssFixes();
1623 - }
1624 - $style['fixes'] = $emailFixes;
1625 -
1626 - if (!empty($mail->stylesheet)) {
1627 - $style['custom_stylesheet'] = $mail->stylesheet;
1628 - }
1629 -
1630 - $settingsStyles = $this->editorHelper->getSettingsStyle($mail->settings);
1631 - if (!empty($settingsStyles)) {
1632 - $style['settings_stylesheet'] = $settingsStyles;
1633 - }
1634 -
1635 - return $style;
1636 - }
1637 -
1638 - private function overrideAllEmails(array $options): bool
1639 - {
1640 - $this->trackEmail = false;
1641 -
1642 - $this->addParam('subject', $options['subject']);
1643 -
1644 - if (isset($options['isHtml']) && !$options['isHtml']) {
1645 - $options['message'] = nl2br($options['message']);
1646 - }
1647 - $this->addParam('body', $options['message']);
1648 -
1649 - $mailClass = new MailClass();
1650 - $this->overrideEmailToSend = $mailClass->getOneByName('acy_notification_cms');
1651 -
1652 - if (empty($this->overrideEmailToSend)) {
1653 - return false;
1654 - }
1655 -
1656 - $statusSend = $this->sendOne($this->overrideEmailToSend->id, $options['to'], $options);
1657 - if (!$statusSend && !empty($this->reportMessage)) {
1658 - $cronHelper = new CronHelper();
1659 - $cronHelper->addMessage($this->reportMessage);
1660 - $cronHelper->saveReport();
1661 - }
1662 -
1663 - return $statusSend;
1664 - }
1665 -
1666 -
1667 - private function acymAddReplyTo(string $email, string $name): void
1668 - {
1669 - if (empty($email)) {
1670 - return;
1671 - }
1672 -
1673 - $replyToName = $this->config->get('add_names', true) ? $this->cleanText(trim($name)) : '';
1674 - $replyToEmail = trim($email);
1675 -
1676 - if (substr_count($replyToEmail, '@') > 1) {
1677 - $replyToEmailArray = explode(';', str_replace([';', ','], ';', $replyToEmail));
1678 - $replyToNameArray = explode(';', str_replace([';', ','], ';', $replyToName));
1679 - foreach ($replyToEmailArray as $i => $oneReplyTo) {
1680 - $this->addReplyTo($this->cleanText($oneReplyTo), @$replyToNameArray[$i]);
1681 - }
1682 - } else {
1683 - $this->addReplyTo($this->cleanText($replyToEmail), $replyToName);
1684 - }
1685 - }
1686 -
1687 - public function setFrom($email, $name = '', $auto = false)
1688 - {
1689 - if (!empty($email)) {
1690 - $this->From = $this->cleanText($email);
1691 - }
1692 - if (!empty($name) && $this->config->get('add_names', true)) {
1693 - $this->FromName = $this->cleanText($name);
1694 - }
1695 - }
1696 -
1697 - protected function edebug($str)
1698 - {
1699 - if (strpos($this->ErrorInfo, $str) === false) {
1700 - $this->ErrorInfo .= ' '.$str;
1701 - }
1702 - }
1703 -
1704 - public function getMailMIME()
1705 - {
1706 - $result = parent::getMailMIME();
1707 -
1708 - $result = rtrim($result, static::$LE);
1709 -
1710 - if ($this->Mailer != 'mail') {
1711 - $result .= static::$LE.static::$LE;
1712 - }
1713 -
1714 - return $result;
1715 - }
1716 -
1717 - public static function validateAddress($address, $patternselect = null)
1718 - {
1719 - return true;
1720 - }
1721 -}