3namespace Bitrix\Mail\Helper;
6use Bitrix\Mail\Internals\MessageUploadQueueTable;
7use Bitrix\Mail\MailboxTable;
8use Bitrix\Mail\MailMessageUidTable;
9use Bitrix\Mail\MailServicesTable;
11use Bitrix\Main\Config\Option;
12use Bitrix\Main\Loader;
14use Bitrix\Main\ORM\Query\Query;
15use Bitrix\Mail\Helper;
16use Bitrix\Mail\MailMessageTable;
17use Bitrix\Main\ORM\Query\Result;
45 'newMessagesNotify' => 0,
46 'deletedMessages' => 0,
47 'updatedMessages' => 0,
48 'newMessageId' =>
null,
53 return Loader::includeModule(
'bitrix24')
54 ? in_array(\CBitrix24::getPortalZone(), [
'ru',
'kz',
'by'])
55 : in_array(LANGUAGE_ID, [
'ru',
'kz',
'by']);
60 $res = MailServicesTable::getList([
75 if(!self::isRuZone() && in_array(
$service[
'NAME'], self::MAIL_SERVICES_ONLY_FOR_THE_RU_ZONE,
true))
88 'encryption' =>
$service[
'ENCRYPTION'],
94 $services[] = $serviceFinal;
110 return static::rawInstance(
array(
'=ID' => (
int) $id,
'=ACTIVE' =>
'Y'), $throw);
115 if($this->dirsMd5WithCounter)
117 return $this->dirsMd5WithCounter;
123 'DIRECTORY_ID' =>
'ENTITY_ID',
127 '=ENTITY_TYPE' =>
'DIR',
128 '=MAILBOX_ID' => $mailboxId,
131 while ($item = $counterResult->fetch()) {
132 $countersById[(int)$item[
'DIRECTORY_ID']] = (
int)$item[
'UNSEEN'];
135 if (empty($countersById)) {
139 $directoriesWithCounter = [];
141 ->whereIn(
'ID', array_keys($countersById))
146 ->where(
'MAILBOX_ID', $mailboxId)
148 while ($item =
$res->fetch()) {
150 $dirMd5 = $item[
'DIR_MD5'];
151 $directoriesWithCounter[$dirMd5] = [
152 'UNSEEN' => $countersById[$id] ?? 0,
153 'DIR_MD5' => $dirMd5,
157 $this->dirsMd5WithCounter = $directoriesWithCounter;
159 return $directoriesWithCounter;
164 \CPullWatch::addToStack(
165 'mail_mailbox_' . $this->mailbox[
'ID'],
168 'mailboxId' => $this->mailbox[
'ID'],
171 'module_id' =>
'mail',
172 'command' =>
'counters_is_synchronized',
181 $mailboxId = $this->mailbox[
'ID'];
183 if (!
Helper\Message::isMailboxOwner($mailboxId,
$USER->GetID()))
189 $defaultDirPath = $this->
getDirsHelper()->getDefaultDirPath();
194 $defaultDirPathId =
null;
196 foreach ($syncDirs as
$dir)
199 $newDir[
'path'] =
$dir->getPath(
true);
200 $newDir[
'name'] =
$dir->getName();
201 $newDir[
'count'] = 0;
202 $currentDirMd5WithCountsOfUnseenMails = $dirsMd5WithCountOfUnseenMails[
$dir->getDirMd5()];
204 if ($currentDirMd5WithCountsOfUnseenMails !==
null)
206 $newDir[
'count'] = $currentDirMd5WithCountsOfUnseenMails[
'UNSEEN'];
209 if($newDir[
'path'] === $defaultDirPath)
211 $defaultDirPathId =
count($dirs);
222 'path' => $defaultDirPath,
223 'name' => $defaultDirPath,
229 array_unshift( $dirs, array_splice($dirs, $defaultDirPathId, 1)[0] );
267 'imap' =>
'Bitrix\Mail\Helper\Mailbox\Imap',
268 'controller' =>
'Bitrix\Mail\Helper\Mailbox\Imap',
269 'domain' =>
'Bitrix\Mail\Helper\Mailbox\Imap',
270 'crdomain' =>
'Bitrix\Mail\Helper\Mailbox\Imap',
278 if (empty(
$mailbox[
'SERVER_TYPE']) || !array_key_exists(
$mailbox[
'SERVER_TYPE'], $types))
293 static $cachedMailboxes = [];
303 if (is_null($cacheKey) || !isset($cachedMailboxes[$cacheKey]))
305 $mailbox = Mail\MailboxTable::getList([
309 'LANG_CHARSET' =>
'SITE.CULTURE.CHARSET'
314 if (!is_null($cacheKey))
316 $cachedMailboxes[$cacheKey] =
$mailbox;
321 $mailbox = $cachedMailboxes[$cacheKey];
326 if (in_array(
$mailbox[
'SERVER_TYPE'],
array(
'controller',
'crdomain',
'domain')))
348 $this->startTime = time();
349 if (defined(
'START_EXEC_PROLOG_BEFORE_1'))
352 if (is_float(START_EXEC_PROLOG_BEFORE_1))
356 elseif (preg_match(
'/ (\d+)$/', START_EXEC_PROLOG_BEFORE_1,
$matches))
367 $this->syncTimeout = static::getTimeout();
375 $this->session = md5(uniqid(
''));
382 if (empty($this->mailbox[
'OPTIONS']) || !is_array($this->mailbox[
'OPTIONS']))
384 $this->mailbox[
'OPTIONS'] =
array();
390 return $this->mailbox;
423 return time() - $this->startTime > ceil(static::getTimeout() * 0.9);
428 $this->checkpoint = time();
436 Message::getCountersForUserMailboxes(
$userId,
true),
437 $this->mailbox[
'LID']
446 private function findMessagesWithAnEmptyBody(
int $count, $mailboxId)
448 $reSyncTime = (
new Main\Type\DateTime())->add(
'- '.static::MESSAGE_RESYNCHRONIZATION_TIME.
' seconds');
452 'select' => [
'ENTITY_ID'],
455 '=MAILBOX_ID' => $mailboxId,
456 '=ENTITY_TYPE' =>
'MESSAGE',
457 '=PROPERTY_NAME' =>
'UNSYNC_BODY',
459 '<=DATE_INSERT' => $reSyncTime,
469 return $item[
'ENTITY_ID'];
475 private function getLostMessages(
int $count,
array $additionalFilters = []):
Main\ORM\Query\Result
477 return MailMessageUidTable::getList([
482 'filter' => array_merge([
483 '=MAILBOX_ID' => $this->mailbox[
'ID'],
485 ], $additionalFilters),
490 private function removeOldUnderloadedMessages(
int $limit,
array $additionalFilters = []): bool
492 $resyncTime =
new Main\Type\DateTime();
493 $resyncTime->add(
'- '.static::INCOMPLETE_MESSAGE_REMOVE_TIMEOUT.
' seconds');
497 '=MAILBOX_ID' => $this->mailbox[
'ID'],
498 '=MESSAGE_ID' =>
'0',
500 '<=DATE_INSERT' => $resyncTime,
501 ], $additionalFilters),
509 $mailboxId = $this->mailbox[
'ID'];
511 while ($item = $messages->fetch())
513 $dirPath = $this->
getDirsHelper()->getDirPathByHash($item[
'DIR_MD5']);
514 $this->
syncMessages($mailboxId, $dirPath, [$item[
'MSG_UID']],
true);
516 if(
Main\Loader::includeModule(
'pull'))
518 \CPullWatch::addToStack(
519 'mail_mailbox_' . $mailboxId,
523 'mailboxId' => $mailboxId,
525 'module_id' =>
'mail',
526 'command' =>
'recovered_message_is_synchronized',
529 \Bitrix\Pull\Event::send();
536 $this->resyncDir($this->
getDirsHelper()->getDefaultDirPath(),25);
541 $dirsSync = $this->
getDirsHelper()->getSyncDirsOrderByTime();
543 foreach ($dirsSync as
$dir)
545 $messageInFolderFilter = $this->getMessageInFolderFilter(
$dir);
546 $this->removeOldUnderloadedMessages(static::NUMBER_OF_INCOMPLETE_MESSAGES_TO_REMOVE, $messageInFolderFilter);
547 $this->syncIncompleteMessages($this->getLostMessages(static::NUMBER_OF_BROKEN_MESSAGES_TO_RESYNCHRONIZE, $messageInFolderFilter));
550 \Bitrix\Mail\Helper\Message::reSyncBody($this->mailbox[
'ID'], $this->findMessagesWithAnEmptyBody(static::NUMBER_OF_BROKEN_MESSAGES_TO_RESYNCHRONIZE, $this->mailbox[
'ID']));
555 Helper::setMailboxUnseenCounter($this->mailbox[
'ID'],Helper::updateMailCounters($this->mailbox));
559 foreach ($usersWithAccessToMailbox as
$userId)
565 public function sync($syncCounters =
true)
575 $this->mailbox[
'OPTIONS'][
'next_sync'] = time() + 3600 * 24;
583 if (time() - $this->mailbox[
'SYNC_LOCK'] < static::getTimeout())
588 $this->mailbox[
'SYNC_LOCK'] = time();
599 $this->session = md5(uniqid(
''));
606 'UPDATE b_mail_mailbox SET SYNC_LOCK = %u WHERE ID = %u AND (SYNC_LOCK IS NULL OR SYNC_LOCK < %u)',
607 $this->mailbox[
'SYNC_LOCK'], $this->mailbox[
'ID'], $this->mailbox[
'SYNC_LOCK'] - static::getTimeout()
614 if (!
$DB->query($lockSql)->affectedRowsCount())
620 if ($this->mailbox[
'USER_ID'] > 0)
622 $mailboxSyncManager->setSyncStartedData($this->mailbox[
'ID']);
626 $count = $syncReport[
'syncCount'];
628 if($syncReport[
'reSyncStatus'])
636 '=MAILBOX_ID' => $this->mailbox[
'ID'],
650 $interval = max(1, (
int) $this->mailbox[
'PERIOD_CHECK']) * 60;
651 $syncErrors = max(0, (
int) $this->mailbox[
'OPTIONS'][
'sync_errors']);
657 $maxInterval = 3600 * 24 * 7;
658 for (
$i = 1;
$i < $syncErrors && $interval < $maxInterval;
$i++)
660 $interval = min($interval * (
$i + 1), $maxInterval);
667 $interval = $syncUnlock < 0 ? $interval : min(
$count > 0 ? 60 : 600, $interval);
670 $this->mailbox[
'OPTIONS'][
'sync_errors'] = $syncErrors;
671 $this->mailbox[
'OPTIONS'][
'next_sync'] = time() + $interval;
673 $optionsValue = $this->mailbox[
'OPTIONS'];
675 $unlockSql = sprintf(
676 "UPDATE b_mail_mailbox SET SYNC_LOCK = %d, OPTIONS = '%s' WHERE ID = %u AND SYNC_LOCK = %u",
678 $DB->forSql(serialize($optionsValue)),
679 $this->mailbox[
'ID'],
680 $this->mailbox[
'SYNC_LOCK']
682 if (
$DB->query($unlockSql)->affectedRowsCount())
684 $this->mailbox[
'SYNC_LOCK'] = $syncUnlock;
694 'complete' => $this->mailbox[
'SYNC_LOCK'] < 0,
701 if ($this->mailbox[
'USER_ID'] > 0)
703 $mailboxSyncManager->setSyncStatus($this->mailbox[
'ID'],
$success, time());
721 if (Loader::includeModule(
'pull'))
725 \CPullWatch::addToStack(
726 'mail_mailbox_' . $this->mailbox[
'ID'],
728 'module_id' =>
'mail',
729 'command' =>
'mailbox_sync_status',
730 'params' => array_merge(
732 'id' => $this->mailbox[
'ID'],
733 'status' => sprintf(
'%.3f',
$status),
734 'sessid' => $this->syncParams[
'sessid'] ?? $this->session,
735 'timestamp' => microtime(
true),
760 if (time() - $this->mailbox[
'SYNC_LOCK'] < static::getTimeout())
770 $syncUnlock = $this->mailbox[
'SYNC_LOCK'];
773 'UPDATE b_mail_mailbox SET SYNC_LOCK = %u WHERE ID = %u AND (SYNC_LOCK IS NULL OR SYNC_LOCK < %u)',
776 if (
$DB->query($lockSql)->affectedRowsCount())
787 $entity = MailMessageUidTable::getEntity();
790 $whereConditionForOldMessages = sprintf(
795 '=MAILBOX_ID' => $this->mailbox[
'ID'],
807 $oldMessages = \Bitrix\Mail\MailMessageUidTable::query()
814 '=MAILBOX_ID' => $this->mailbox[
'ID'],
823 MAILBOX_ID = " . \
Bitrix\
Mail\MailMessageUidTable::query()->getInitAlias() .
".MAILBOX_ID
824 AND MESSAGE_ID = " . \
Bitrix\
Mail\MailMessageUidTable::query()->getInitAlias() .
".MESSAGE_ID
827 )->setLimit(static::MESSAGE_DELETION_LIMIT_AT_A_TIME)->exec()
830 $messageAsStringForSql = [];
833 while ($oldMessage = $oldMessages->fetch())
835 $id = $oldMessage[
'ID'];
836 $oldMessageIds[] = $id;
841 'MAILBOX_ID' => (
int)$oldMessage[
'MAILBOX_ID'],
842 'MESSAGE_ID' => (
int)$oldMessage[
'MESSAGE_ID'],
846 $messageAsStringForSql[] =
"($insert)";
849 if (empty($oldMessageIds))
857 '=MAILBOX_ID' => $this->mailbox[
'ID'],
858 '@ID' => $oldMessageIds,
867 $sqlHelper->getInsertIgnore(
869 '(ID, MAILBOX_ID, MESSAGE_ID)',
870 'VALUES ' . implode(
', ', $messageAsStringForSql)
887 "UPDATE %s SET IS_OLD = 'Y', IS_SEEN = 'Y' WHERE %s ORDER BY ID LIMIT " . static::MESSAGE_SET_OLD_STATUS_LIMIT_AT_A_TIME,
889 $whereConditionForOldMessages
900 while (
$connection->getAffectedRowsCount() >= static::MESSAGE_SET_OLD_STATUS_LIMIT_AT_A_TIME);
903 $unlockSql = sprintf(
904 "UPDATE b_mail_mailbox SET SYNC_LOCK = %d WHERE ID = %u AND SYNC_LOCK = %u",
905 $syncUnlock, $this->mailbox[
'ID'], $this->mailbox[
'SYNC_LOCK']
907 if (
$DB->query($unlockSql)->affectedRowsCount())
909 $this->mailbox[
'SYNC_LOCK'] = $syncUnlock;
921 if (time() - $this->mailbox[
'SYNC_LOCK'] < static::getTimeout())
931 $syncUnlock = $this->mailbox[
'SYNC_LOCK'];
934 'UPDATE b_mail_mailbox SET SYNC_LOCK = %u WHERE ID = %u AND (SYNC_LOCK IS NULL OR SYNC_LOCK < %u)',
937 if (
$DB->query($lockSql)->affectedRowsCount())
950 '=MAILBOX_ID' => $this->mailbox[
'ID'],
954 '<DELETE_TIME' => $minSyncTime,
957 static::MESSAGE_DELETION_LIMIT_AT_A_TIME
960 $unlockSql = sprintf(
961 "UPDATE b_mail_mailbox SET SYNC_LOCK = %d WHERE ID = %u AND SYNC_LOCK = %u",
962 $syncUnlock, $this->mailbox[
'ID'], $this->mailbox[
'SYNC_LOCK']
964 if (
$DB->query($unlockSql)->affectedRowsCount())
966 $this->mailbox[
'SYNC_LOCK'] = $syncUnlock;
980 'Bitrix\Mail\MailMessageUidTable',
982 '=this.MAILBOX_ID' =>
'ref.MAILBOX_ID',
983 '=this.MESSAGE_ID' =>
'ref.MESSAGE_ID',
987 'select' =>
array(
'MESSAGE_ID',
'UID' =>
'MESSAGE_UID.ID'),
989 '=MAILBOX_ID' => $this->mailbox[
'ID'],
995 while ($item =
$res->fetch())
999 if (empty($item[
'UID']))
1001 \CMailMessage::delete($item[
'MESSAGE_ID']);
1005 '=MAILBOX_ID' => $this->mailbox[
'ID'],
1006 '=MESSAGE_ID' => $item[
'MESSAGE_ID'],
1023 '=MAILBOX_ID' => $this->mailbox[
'ID'],
1026 if (!empty(
$params[
'filter']))
1039 $idFromHeaderMessage,
1042 return MessageUploadQueueTable::getList([
1045 'MESSAGE_ID' =>
'UID_TABLE.MESSAGE_ID',
1048 '=SYNC_STAGE' => -1,
1050 '=MAILBOX_ID'=> $this->mailbox[
'ID'],
1052 '=UID_TABLE.DELETE_TIME' => 0,
1053 '=UID_TABLE.MESSAGE_TABLE.MSG_ID' => $idFromHeaderMessage,
1063 $replacingMessageFromQueue =
false;
1065 if (!empty($replaces))
1073 if (!is_array($replaces))
1080 $exists = MailMessageUidTable::getList([
1087 '=MAILBOX_ID' => $this->mailbox[
'ID'],
1088 '==DELETE_TIME' => 0,
1096 'MESSAGE_ID' =>
$fields[
'MESSAGE_ID'],
1100 else if ($isOutgoing && $idFromHeaderMessage !==
'')
1107 $idFromHeaderMessage,
1110 $replacingMessageFromQueue =
true;
1113 if (!empty($exists))
1115 $fields[
'MESSAGE_ID'] = $exists[
'MESSAGE_ID'];
1119 '=ID' => $exists[
'ID'],
1120 '=MAILBOX_ID' => $this->mailbox[
'ID'],
1121 '==DELETE_TIME' => 0,
1126 'TIMESTAMP_X' => $now,
1132 'MAILBOX_USER_ID' => $this->mailbox[
'USER_ID'],
1137 if ($replacingMessageFromQueue &&
$result)
1140 'ID' => $exists[
'ID'],
1141 'MAILBOX_ID' => (
int) $this->mailbox[
'ID'],
1148 $addFields = array_merge(
1154 'IS_OLD' => $messageStatus,
1155 'MAILBOX_ID' => $this->mailbox[
'ID'],
1156 'SESSION_ID' => $this->session,
1157 'TIMESTAMP_X' => $now,
1161 if ($redefineInsertDate || !array_key_exists(
'DATE_INSERT',
$fields))
1163 $addFields[
'DATE_INSERT'] = $now;
1166 MailMessageUidTable::checkFields($checkResult,
null, $addFields);
1167 if (!$checkResult->isSuccess())
1173 'MSG_UID' => $addFields[
'MSG_UID'],
1174 'HEADER_MD5' => $addFields[
'HEADER_MD5'],
1175 'SESSION_ID' => $addFields[
'SESSION_ID'],
1176 'TIMESTAMP_X' => $addFields[
'TIMESTAMP_X'],
1192 '=MAILBOX_ID' => $this->mailbox[
'ID'],
1202 $messageExistInTheOriginalMailbox =
false;
1203 $messagesForRemove = [];
1204 $filterForCheck = [];
1206 if(!$ignoreDeletionCheck)
1208 $filterForCheck = array_merge(
1212 '=MAILBOX_ID' => $this->mailbox[
'ID'],
1219 '!=MESSAGE_ID' => 0,
1223 $messagesForRemove = MailMessageUidTable::getList([
1236 'filter' => $filterForCheck,
1240 if (!empty($messagesForRemove))
1242 if (isset($messagesForRemove[0][
'DIR_MD5']))
1244 $dirMD5 = $messagesForRemove[0][
'DIR_MD5'];
1245 $dirPath = $this->
getDirsHelper()->getDirPathByHash($dirMD5);
1248 return $item[
'MSG_UID'];
1258 if($messageExistInTheOriginalMailbox ===
false)
1264 '=MAILBOX_ID' => $this->mailbox[
'ID'],
1271 $messageForLog = isset($messagesForRemove[0]) ? $messagesForRemove[0] : [];
1277 foreach($messagesForRemove as
$message)
1279 if(isset(
$message[
'MSG_UID']) && (
int)
$message[
'MSG_UID'] === (
int)$messageExistInTheOriginalMailbox)
1286 if(isset($messageForLog[
'INTERNALDATE']) && $messageForLog[
'INTERNALDATE'] instanceof
Main\
Type\
DateTime)
1288 $messageForLog[
'INTERNALDATE'] = $messageForLog[
'INTERNALDATE']->getTimestamp();
1290 if(isset($messageForLog[
'DATE_INSERT']) && $messageForLog[
'DATE_INSERT'] instanceof
Main\
Type\
DateTime)
1292 $messageForLog[
'DATE_INSERT'] = $messageForLog[
'DATE_INSERT']->getTimestamp();
1295 if(isset($filterForCheck[
'@ID']))
1297 $filterForCheck[
'@ID'] =
'[hidden for the log]';
1314 $result = MailMessageUidTable::update(
1317 'MAILBOX_ID' => $this->mailbox[
'ID'],
1320 'MESSAGE_ID' => $id,
1335 return \CMailMessage::addMessage(
1336 $this->mailbox[
'ID'],
1338 $this->mailbox[
'CHARSET'] ?: $this->mailbox[
'LANG_CHARSET'],
1345 class_exists(
'Bitrix\Mail\Helper');
1352 'ID' => $messageUid,
1353 'MAILBOX_ID' => $this->mailbox[
'ID'],
1358 'Bitrix\Mail\Helper::syncOutgoingAgent(%u);',
1359 $this->mailbox[
'ID']
1367 $messageUid = sprintf(
'%x%x', time(), rand(0, 0xffffffff));
1383 'trackable' =>
true,
1391 'ID' => $messageUid,
1410 'Bitrix\Mail\Internals\MessageUploadQueueTable',
1412 '=this.ID' =>
'ref.ID',
1413 '=this.MAILBOX_ID' =>
'ref.MAILBOX_ID',
1416 'join_type' =>
'INNER',
1422 '__' =>
'MESSAGE.*',
1423 'UPLOAD_LOCK' =>
'UPLOAD_QUEUE.SYNC_LOCK',
1424 'UPLOAD_STAGE' =>
'UPLOAD_QUEUE.SYNC_STAGE',
1425 'UPLOAD_ATTEMPTS' =>
'UPLOAD_QUEUE.ATTEMPTS',
1428 '>=UPLOAD_QUEUE.SYNC_STAGE' => 0,
1429 '<UPLOAD_QUEUE.SYNC_LOCK' => time() - static::getTimeout(),
1430 '<UPLOAD_QUEUE.ATTEMPTS' => 5,
1433 'UPLOAD_QUEUE.SYNC_LOCK' =>
'ASC',
1434 'UPLOAD_QUEUE.SYNC_STAGE' =>
'ASC',
1435 'UPLOAD_QUEUE.ATTEMPTS' =>
'ASC',
1441 while ($excerpt =
$res->fetch())
1443 $n = $excerpt[
'UPLOAD_ATTEMPTS'] + 1;
1444 $interval = min(static::getTimeout() * pow(
$n,
$n), 3600 * 24 * 7);
1446 if ($excerpt[
'UPLOAD_LOCK'] > time() - $interval)
1465 "UPDATE b_mail_message_upload_queue SET SYNC_LOCK = %u, SYNC_STAGE = %u, ATTEMPTS = ATTEMPTS + 1
1466 WHERE ID = '%s' AND MAILBOX_ID = %u AND SYNC_LOCK < %u",
1468 max(1, $excerpt[
'UPLOAD_STAGE']),
1469 $DB->forSql($excerpt[
'ID']),
1470 $excerpt[
'MAILBOX_ID'],
1471 $syncLock - static::getTimeout()
1473 if (!
$DB->query($lockSql)->affectedRowsCount())
1478 $outgoingBody = $excerpt[
'__BODY_HTML'];
1482 'ID',
'FILE_ID',
'FILE_NAME',
1485 '=MESSAGE_ID' => $excerpt[
'__ID'],
1489 $attachments =
array();
1490 if (!empty($excerpt[
'__files']) && is_array($excerpt[
'__files']))
1492 $hostname = \COption::getOptionString(
'main',
'server_name',
'localhost');
1493 if (defined(
'BX24_HOST_NAME') && BX24_HOST_NAME !=
'')
1495 $hostname = BX24_HOST_NAME;
1497 else if (defined(
'SITE_SERVER_NAME') && SITE_SERVER_NAME !=
'')
1499 $hostname = SITE_SERVER_NAME;
1502 foreach ($excerpt[
'__files'] as $item)
1504 $file = \CFile::makeFileArray($item[
'FILE_ID']);
1507 'bxacid.%s@%s.mail',
1508 hash(
'crc32b', $file[
'external_id'].$file[
'size'].$file[
'name']),
1509 hash(
'crc32b', $hostname)
1512 $attachments[] =
array(
1514 'NAME' => $item[
'FILE_NAME'],
1515 'PATH' => $file[
'tmp_name'],
1516 'CONTENT_TYPE' => $file[
'type'],
1519 $outgoingBody = preg_replace(
1520 sprintf(
'/aid:%u/i', $item[
'ID']),
1527 foreach (
array(
'FROM',
'REPLY_TO',
'TO',
'CC',
'BCC') as $field)
1529 $field = sprintf(
'__FIELD_%s', $field);
1531 if (mb_strlen($excerpt[$field]) == 255 &&
'' != $excerpt[
'__HEADER'] && empty($parsedHeader))
1535 $excerpt[
'__FIELD_FROM'] = $parsedHeader->getHeader(
'FROM');
1536 $excerpt[
'__FIELD_REPLY_TO'] = $parsedHeader->getHeader(
'REPLY-TO');
1537 $excerpt[
'__FIELD_TO'] = $parsedHeader->getHeader(
'TO');
1538 $excerpt[
'__FIELD_CC'] = $parsedHeader->getHeader(
'CC');
1539 $excerpt[
'__FIELD_BCC'] = join(
', ', array_merge(
1540 (
array) $parsedHeader->getHeader(
'X-Original-Rcpt-to'),
1541 (
array) $parsedHeader->getHeader(
'BCC')
1545 $excerpt[$field] = explode(
',', $excerpt[$field]);
1547 foreach ($excerpt[$field] as
$k => $item)
1549 unset($excerpt[$field][
$k]);
1553 if ($address->validate())
1555 if ($address->getName())
1557 $excerpt[$field][] = sprintf(
1559 sprintf(
'=?%s?B?%s?=',
SITE_CHARSET, base64_encode($address->getName())),
1560 $address->getEmail()
1565 $excerpt[$field][] = $address->getEmail();
1570 $excerpt[$field] = join(
', ', $excerpt[$field]);
1575 'CONTENT_TYPE' =>
'html',
1576 'ATTACHMENT' => $attachments,
1577 'TO' => $excerpt[
'__FIELD_TO'],
1578 'SUBJECT' => $excerpt[
'__SUBJECT'],
1579 'BODY' => $outgoingBody,
1581 'From' => $excerpt[
'__FIELD_FROM'],
1582 'Reply-To' => $excerpt[
'__FIELD_REPLY_TO'],
1583 'Cc' => $excerpt[
'__FIELD_CC'],
1584 'Bcc' => $excerpt[
'__FIELD_BCC'],
1585 'Message-Id' => sprintf(
'<%s>', $excerpt[
'__MSG_ID']),
1589 if (Option::get(
'mail',
'embed_local_id_in_outgoing_message_header',
'Y') ==
'Y')
1591 $outgoingParams[
'HEADER'][
'X-Bitrix-Mail-Message-UID'] = $excerpt[
'ID'];
1594 if(isset($excerpt[
'__IN_REPLY_TO']))
1596 $outgoingParams[
'HEADER'][
'In-Reply-To'] = sprintf(
'<%s>', $excerpt[
'__IN_REPLY_TO']);
1607 function () use (&$excerpt)
1609 if ($excerpt[
'UPLOAD_STAGE'] >= 2)
1619 'TRACK_READ' =>
array(
1620 'MODULE_ID' =>
'mail',
1621 'FIELDS' =>
array(
'msgid' => $excerpt[
'__MSG_ID']),
1622 'URL_PAGE' =>
'/pub/mail/read.php',
1632 $eventManager->removeEventHandler(
'main',
'OnBeforeMailSend', $eventKey);
1634 if ($excerpt[
'UPLOAD_STAGE'] < 2 && !
$success)
1640 if (
$context->getSmtp() &&
$context->getSmtp()->getFrom() == $this->mailbox[
'EMAIL'])
1642 $needUpload = !in_array(
'deny_upload', (
array) $this->mailbox[
'OPTIONS'][
'flags']);
1647 if ($excerpt[
'UPLOAD_STAGE'] < 2)
1651 'ID' => $excerpt[
'ID'],
1652 'MAILBOX_ID' => $excerpt[
'MAILBOX_ID'],
1661 class_exists(
'Bitrix\Mail\Helper');
1666 'HEADER' => array_merge(
1667 $outgoingParams[
'HEADER'],
1669 'To' => $outgoingParams[
'TO'],
1670 'Subject' => $outgoingParams[
'SUBJECT'],
1679 'ID' => $excerpt[
'ID'],
1680 'MAILBOX_ID' => $excerpt[
'MAILBOX_ID'],
1688 'ID' => $excerpt[
'ID'],
1689 'MAILBOX_ID' => $excerpt[
'MAILBOX_ID'],
1709 'replaces' => $excerpt[
'ID'],
1724 return $attachments;
1736 if (empty(
$action[
'LAZY_ATTACHMENTS']))
1748 if (is_null($this->filters) || $force)
1750 $this->filters = Mail\MailFilterTable::getList(
array(
1751 'filter' =>
ORM\
Query\Query::filter()
1752 ->where(
'ACTIVE',
'Y')
1754 ORM\
Query\Query::filter()->logic(
'or')
1755 ->where(
'MAILBOX_ID', $this->mailbox[
'ID'])
1756 ->where(
'MAILBOX_ID',
null)
1764 foreach ($this->filters as
$k => $item)
1766 $this->filters[
$k][
'__actions'] =
array();
1768 $res = \CMailFilter::getFilterList($item[
'ACTION_TYPE']);
1769 while ($row =
$res->fetch())
1771 $this->filters[
$k][
'__actions'][] = $row;
1776 return $this->filters;
1786 $worker =
function ($id, $msgId, &
$i)
1792 array($id, $msgId,
false),
1800 $level = array_pop($stack);
1804 [$id, $msgId, $skip] = array_shift($level);
1811 'UPDATE b_mail_message SET LEFT_MARGIN = %2$u, RIGHT_MARGIN = %3$u WHERE ID = %1$u',
1819 $res = Mail\MailMessageTable::getList(
array(
1825 '=MAILBOX_ID' => $this->mailbox[
'ID'],
1826 '=IN_REPLY_TO' => $msgId,
1829 'FIELD_DATE' =>
'ASC',
1833 while ($item =
$res->fetch())
1835 if (!in_array($item[
'ID'], $excerpt))
1837 $replies[] =
array($item[
'ID'], $item[
'MSG_ID'],
false);
1843 array_unshift($level,
array($id, $msgId,
true));
1845 array_push($stack, $level, $replies);
1855 'UPDATE b_mail_message SET RIGHT_MARGIN = %2$u WHERE ID = %1$u',
1871 $item =
$DB->query(sprintf(
1872 'SELECT GREATEST(M1, M2) AS I FROM (SELECT
1873 (SELECT RIGHT_MARGIN FROM b_mail_message WHERE MAILBOX_ID = %1$u AND RIGHT_MARGIN > 0 ORDER BY LEFT_MARGIN ASC LIMIT 1) M1,
1874 (SELECT RIGHT_MARGIN FROM b_mail_message WHERE MAILBOX_ID = %1$u AND RIGHT_MARGIN > 0 ORDER BY LEFT_MARGIN DESC LIMIT 1) M2
1876 $this->mailbox[
'ID']
1879 $i = empty($item[
'I']) ? 0 : $item[
'I'];
1886 'UPDATE b_mail_message SET LEFT_MARGIN = 0, RIGHT_MARGIN = 0 WHERE MAILBOX_ID = %u',
1887 $this->mailbox[
'ID']
1893 "SELECT ID, MSG_ID FROM b_mail_message M WHERE MAILBOX_ID = %u AND (
1894 IN_REPLY_TO IS NULL OR IN_REPLY_TO = '' OR NOT EXISTS (
1895 SELECT 1 FROM b_mail_message WHERE MAILBOX_ID = M.MAILBOX_ID AND MSG_ID = M.IN_REPLY_TO
1898 $this->mailbox[
'ID']
1901 while ($item =
$res->fetch())
1903 $worker($item[
'ID'], $item[
'MSG_ID'],
$i);
1908 'SELECT ID, MSG_ID FROM b_mail_message
1909 WHERE MAILBOX_ID = %u AND LEFT_MARGIN = 0
1910 ORDER BY FIELD_DATE ASC LIMIT 1',
1911 $this->mailbox[
'ID']
1913 while ($item =
$DB->query(
$query)->fetch())
1915 $worker($item[
'ID'], $item[
'MSG_ID'],
$i);
1930 if (!empty(
$message[
'IN_REPLY_TO']))
1932 $item = Mail\MailMessageTable::getList(
array(
1934 'ID',
'MSG_ID',
'LEFT_MARGIN',
'RIGHT_MARGIN',
1937 '=MAILBOX_ID' => $this->mailbox[
'ID'],
1938 '=MSG_ID' =>
$message[
'IN_REPLY_TO'],
1941 'LEFT_MARGIN' =>
'ASC',
1949 $item = Mail\MailMessageTable::getList(
array(
1954 '=MAILBOX_ID' => $this->mailbox[
'ID'],
1955 '<LEFT_MARGIN' => $item[
'LEFT_MARGIN'],
1956 '>RIGHT_MARGIN' => $item[
'RIGHT_MARGIN'],
1959 'LEFT_MARGIN' =>
'ASC',
1991 return $this->warnings;
1996 return $this->lastSyncResult;
2001 $this->lastSyncResult = array_merge($this->lastSyncResult,
$data);
2006 if (!$this->dirsHelper)
2011 return $this->dirsHelper;
2016 $options = $this->mailbox[
'OPTIONS'];
2023 $entity = MailboxTable::getEntity();
2029 'UPDATE %s SET %s WHERE %s',
2035 Query::buildFilterSql(
2038 'ID' => $this->mailbox[
'ID']
2048 if (Loader::includeModule(
'im'))
2060 if ($newMessageId > 0 &&
$count === 1)
2062 $message = Mail\MailMessageTable::getByPrimary(
2082 Mail\Helper\Message::prepare(
$message);
2087 $this->mailbox[
'USER_ID'],
2090 'mailboxOwnerId' => $this->mailbox[
'USER_ID'],
2091 'mailboxId' => $this->mailbox[
'ID'],
2107 $supportedActionTypes = [
2116 !in_array(
$filter[
'ACTION_TYPE'], $supportedActionTypes,
true)
2118 $this->hasActionWithoutSanitizeSupport(
$filter[
'__actions'])
2119 || !empty(
$filter[
'PHP_CONDITION'])
2120 || !empty(
$filter[
'ACTION_PHP'])
2137 private function hasActionWithoutSanitizeSupport($actions): bool
2139 if (is_array($actions))
2143 if (empty(
$action[
'SANITIZE_ON_VIEW']))
2158 return min(max(0, ini_get(
'max_execution_time')) ?: static::SYNC_TIMEOUT, static::SYNC_TIMEOUT);
2166 return static::createInstance(
$mailbox[
'ID'],
false);
if(! $messageFields||!isset($messageFields['message_id'])||!isset($messageFields['status'])||!CModule::IncludeModule("messageservice")) $messageId
if(!is_object($USER)||! $USER->IsAuthorized()) $userId
static isCleanupOldEnabled()
static checkTheMailboxForSyncAvailability(int $checkedMailboxId, ?int $ownerMailboxUserId=null)
static getUserIdsWithAccessToMailbox($mailboxId)
static createInstance($id, $throw=true)
downloadAttachments(array &$excerpt)
resortTree($message=null)
createMessage(Main\Mail\Mail $message, array $fields=array())
const NUMBER_OF_INCOMPLETE_MESSAGES_TO_REMOVE
getDirsMd5WithCounter($mailboxId)
listDirs($pattern, $useDb=false)
uploadMessage(Main\Mail\Mail $message, array &$excerpt)
setSyncParams(array $params=array())
syncOutgoingMessage($excerpt)
const MESSAGE_SET_OLD_STATUS_LIMIT_AT_A_TIME
updateGlobalCounterForCurrentUser()
findMessageInUploadQueue( $idFromHeaderMessage,)
registerMessage(&$fields, $replaces=null, $isOutgoing=false, string $idFromHeaderMessage='', $redefineInsertDate=true, string $messageStatus=\Bitrix\Mail\MailMessageUidTable::DOWNLOADED)
static instance(array $mailbox)
updateMessagesRegistry(array $filter, array $fields, $mailData=array())
const MESSAGE_DELETION_LIMIT_AT_A_TIME
downloadMessage(array &$excerpt)
getDirsWithUnseenMailCounters()
const MESSAGE_RESYNCHRONIZATION_TIME
listMessages($params=array(), $fetch=true)
resyncMessage(array &$excerpt)
dismissDeletedUidMessages()
checkMessagesForExistence($dirPath='INBOX', $UIDs=[])
setLastSyncResult(array $data)
const NUMBER_OF_BROKEN_MESSAGES_TO_RESYNCHRONIZE
const INCOMPLETE_MESSAGE_REMOVE_TIMEOUT
cacheMessage(&$body, $params=array())
isSupportLazyAttachments()
syncMessages($mailboxID, $dirPath, $UIDs)
static rawInstance($filter, $throw=true)
unregisterMessages($filter, $eventData=[], $ignoreDeletionCheck=false)
updateGlobalCounter($userId)
normalizeMailboxOptions()
static findBy($id, $email)
const MAIL_SERVICES_ONLY_FOR_THE_RU_ZONE
static prepareMailbox($filter)
static getForUserByEmail($email)
isSupportSanitizeOnView()
pushSyncStatus($params, $force=false)
static add($userId, $type, $fields, $mailboxId=null)
static deleteList(array $filter)
const FIELD_SANITIZE_ON_VIEW
static getPresetRemoveFilters()
static deleteListSoft(array $filter)
static deleteList(array $filter, array $messages=[], $limit=false, bool $sendEvent=true)
static updateList(array $filter, array $fields, array $eventData=[], bool $sendEvent=true)
static mergeData(array $insert, array $update)
static getIconSrc($serviceName, $iconId=null)
static getMinSyncTime($mailboxId)
static getUserMailboxWithEmail($email)
static getUserMailbox($mailboxId, $userId=null)
static normalizeEmail(&$mailbox)
static getList(array $parameters=array())
static update($primary, array $data)
static parseHeader($header, $charset)
static parseMessage($message, $charset)
</td ></tr ></table ></td ></tr >< tr >< td class="bx-popup-label bx-width30"><?=GetMessage("PAGE_NEW_TAGS")?> array( $site)
if( $daysToExpire >=0 &&$daysToExpire< 60 elseif)( $daysToExpire< 0)
</p ></td >< td valign=top style='border-top:none;border-left:none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;padding:0cm 2.0pt 0cm 2.0pt;height:9.0pt'>< p class=Normal align=center style='margin:0cm;margin-bottom:.0001pt;text-align:center;line-height:normal'>< a name=ТекстовоеПоле54 ></a ><?=($taxRate > count( $arTaxList) > 0) ? $taxRate."%"
if($inWords) echo htmlspecialcharsbx(Number2Word_Rus(roundEx($totalVatSum $params['CURRENCY']
if(!Loader::includeModule('sale')) $pattern