38 'newMessagesNotify' => 0,
39 'deletedMessages' => 0,
40 'updatedMessages' => 0,
41 'newMessageId' =>
null,
46 return Loader::includeModule(
'bitrix24')
47 ? in_array(\CBitrix24::getPortalZone(), [
'ru',
'kz',
'by'])
48 : in_array(LANGUAGE_ID, [
'ru',
'kz',
'by']);
53 $res = MailServicesTable::getList([
56 '=SITE_ID' => SITE_ID,
66 while ($service = $res->fetch())
68 if(!self::isRuZone() && in_array($service[
'NAME'], self::MAIL_SERVICES_ONLY_FOR_THE_RU_ZONE,
true))
74 'id' => $service[
'ID'],
75 'type' => $service[
'SERVICE_TYPE'],
76 'name' => $service[
'NAME'],
77 'link' => $service[
'LINK'],
79 'server' => $service[
'SERVER'],
80 'port' => $service[
'PORT'],
81 'encryption' => $service[
'ENCRYPTION'],
82 'token' => $service[
'TOKEN'],
83 'flags' => $service[
'FLAGS'],
84 'sort' => $service[
'SORT']
87 $services[] = $serviceFinal;
103 return static::rawInstance(array(
'=ID' => (
int) $id,
'=ACTIVE' =>
'Y'), $throw);
108 if($this->dirsMd5WithCounter)
110 return $this->dirsMd5WithCounter;
114 $counterResult = Mail\Internals\MailCounterTable::getList([
116 'DIRECTORY_ID' =>
'ENTITY_ID',
120 '=ENTITY_TYPE' =>
'DIR',
121 '=MAILBOX_ID' => $mailboxId,
124 while ($item = $counterResult->fetch()) {
125 $countersById[(int)$item[
'DIRECTORY_ID']] = (
int)$item[
'UNSEEN'];
128 if (empty($countersById)) {
132 $directoriesWithCounter = [];
133 $res = Mail\Internals\MailboxDirectoryTable::query()
134 ->whereIn(
'ID', array_keys($countersById))
139 ->where(
'MAILBOX_ID', $mailboxId)
141 while ($item = $res->fetch()) {
143 $dirMd5 = $item[
'DIR_MD5'];
144 $directoriesWithCounter[$dirMd5] = [
145 'UNSEEN' => $countersById[$id] ?? 0,
146 'DIR_MD5' => $dirMd5,
150 $this->dirsMd5WithCounter = $directoriesWithCounter;
152 return $directoriesWithCounter;
157 \CPullWatch::addToStack(
158 'mail_mailbox_' . $this->mailbox[
'ID'],
163 'module_id' =>
'mail',
164 'command' =>
'counters_is_synchronized',
167 \Bitrix\Pull\Event::send();
173 $mailboxId = $this->mailbox[
'ID'];
175 if (!
Helper\Message::isMailboxOwner($mailboxId, $USER->GetID()))
181 $defaultDirPath = $this->
getDirsHelper()->getDefaultDirPath();
186 $defaultDirPathId =
null;
188 foreach ($syncDirs as $dir)
191 $newDir[
'path'] = $dir->getPath(
true);
192 $newDir[
'name'] = $dir->getName();
193 $newDir[
'count'] = 0;
194 $currentDirMd5WithCountsOfUnseenMails = $dirsMd5WithCountOfUnseenMails[$dir->getDirMd5()];
196 if ($currentDirMd5WithCountsOfUnseenMails !==
null)
198 $newDir[
'count'] = $currentDirMd5WithCountsOfUnseenMails[
'UNSEEN'];
201 if($newDir[
'path'] === $defaultDirPath)
203 $defaultDirPathId = count($dirs);
214 'path' => $defaultDirPath,
215 'name' => $defaultDirPath,
221 array_unshift( $dirs, array_splice($dirs, $defaultDirPathId, 1)[0] );
238 $mailbox = static::prepareMailbox($filter);
242 catch (\Exception $e)
259 'imap' =>
'Bitrix\Mail\Helper\Mailbox\Imap',
260 'controller' =>
'Bitrix\Mail\Helper\Mailbox\Imap',
261 'domain' =>
'Bitrix\Mail\Helper\Mailbox\Imap',
262 'crdomain' =>
'Bitrix\Mail\Helper\Mailbox\Imap',
270 if (empty($mailbox[
'SERVER_TYPE']) || !array_key_exists($mailbox[
'SERVER_TYPE'], $types))
275 return new $types[$mailbox[
'SERVER_TYPE']]($mailbox);
280 if (is_scalar($filter))
282 $filter = array(
'=ID' => (
int) $filter);
285 $mailbox = Mail\MailboxTable::getList(array(
287 'select' => array(
'*',
'LANG_CHARSET' =>
'SITE.CULTURE.CHARSET'),
289 ))->fetch() ?: array();
293 if (in_array(
$mailbox[
'SERVER_TYPE'], array(
'controller',
'crdomain',
'domain')))
295 $result = \CMailDomain2::getImapData();
297 $mailbox[
'SERVER'] = $result[
'server'];
299 $mailbox[
'USE_TLS'] = $result[
'secure'];
302 Mail\MailboxTable::normalizeEmail(
$mailbox);
310 $this->syncParams = $params;
315 $this->startTime = time();
316 if (defined(
'START_EXEC_PROLOG_BEFORE_1'))
319 if (is_float(START_EXEC_PROLOG_BEFORE_1))
323 elseif (preg_match(
'/ (\d+)$/', START_EXEC_PROLOG_BEFORE_1, $matches))
334 $this->syncTimeout = static::getTimeout();
342 $this->session = md5(uniqid(
''));
349 if (empty($this->mailbox[
'OPTIONS']) || !is_array($this->mailbox[
'OPTIONS']))
351 $this->mailbox[
'OPTIONS'] = array();
357 return $this->mailbox;
390 return time() - $this->startTime > ceil(static::getTimeout() * 0.9);
395 $this->checkpoint = time();
403 Message::getCountersForUserMailboxes($userId,
true),
404 $this->mailbox[
'LID']
413 private function findMessagesWithAnEmptyBody(
int $count, $mailboxId)
415 $reSyncTime = (
new Main\Type\DateTime())->add(
'- '.static::MESSAGE_RESYNCHRONIZATION_TIME.
' seconds');
417 $ids = Mail\Internals\MailEntityOptionsTable::getList(
419 'select' => [
'ENTITY_ID'],
422 '=MAILBOX_ID' => $mailboxId,
423 '=ENTITY_TYPE' =>
'MESSAGE',
424 '=PROPERTY_NAME' =>
'UNSYNC_BODY',
426 '<=DATE_INSERT' => $reSyncTime,
436 return $item[
'ENTITY_ID'];
443 private function findIncompleteMessages(
int $count)
446 $resyncTime->add(
'- '.static::MESSAGE_RESYNCHRONIZATION_TIME.
' seconds');
448 return Mail\MailMessageUidTable::getList([
454 '=MAILBOX_ID' => $this->mailbox[
'ID'],
455 '=MESSAGE_ID' =>
'0',
459 '<=DATE_INSERT' => $resyncTime,
465 private function syncIncompleteMessages($messages)
467 while ($item = $messages->fetch())
469 $dirPath = $this->getDirsHelper()->getDirPathByHash($item[
'DIR_MD5']);
470 $this->syncMessages($this->mailbox[
'ID'], $dirPath, [$item[
'MSG_UID']]);
476 $this->resyncDir($this->
getDirsHelper()->getDefaultDirPath(),25);
481 $this->syncIncompleteMessages($this->findIncompleteMessages(static::NUMBER_OF_BROKEN_MESSAGES_TO_RESYNCHRONIZE));
482 \Bitrix\Mail\Helper\Message::reSyncBody($this->mailbox[
'ID'],$this->findMessagesWithAnEmptyBody(static::NUMBER_OF_BROKEN_MESSAGES_TO_RESYNCHRONIZE, $this->mailbox[
'ID']));
489 $usersWithAccessToMailbox = Mailbox\SharedMailboxesManager::getUserIdsWithAccessToMailbox($this->mailbox[
'ID']);
491 foreach ($usersWithAccessToMailbox as $userId)
497 public function sync($syncCounters =
true)
507 $this->mailbox[
'OPTIONS'][
'next_sync'] = time() + 3600 * 24;
515 if (time() - $this->mailbox[
'SYNC_LOCK'] < static::getTimeout())
520 $this->mailbox[
'SYNC_LOCK'] = time();
531 $this->session = md5(uniqid(
''));
538 'UPDATE b_mail_mailbox SET SYNC_LOCK = %u WHERE ID = %u AND (SYNC_LOCK IS NULL OR SYNC_LOCK < %u)',
539 $this->mailbox[
'SYNC_LOCK'], $this->mailbox[
'ID'], $this->mailbox[
'SYNC_LOCK'] - static::getTimeout()
546 if (!$DB->query($lockSql)->affectedRowsCount())
552 if ($this->mailbox[
'USER_ID'] > 0)
554 $mailboxSyncManager->setSyncStartedData($this->mailbox[
'ID']);
558 $count = $syncReport[
'syncCount'];
560 if($syncReport[
'reSyncStatus'])
566 Mail\MailMessageUidTable::updateList(
568 '=MAILBOX_ID' => $this->mailbox[
'ID'],
578 $success = $count !==
false && $this->errors->isEmpty();
582 $interval = max(1, (
int) $this->mailbox[
'PERIOD_CHECK']) * 60;
583 $syncErrors = max(0, (
int) $this->mailbox[
'OPTIONS'][
'sync_errors']);
585 if ($count ===
false)
589 $maxInterval = 3600 * 24 * 7;
590 for ($i = 1; $i < $syncErrors && $interval < $maxInterval; $i++)
592 $interval = min($interval * ($i + 1), $maxInterval);
599 $interval = $syncUnlock < 0 ? $interval : min($count > 0 ? 60 : 600, $interval);
602 $this->mailbox[
'OPTIONS'][
'sync_errors'] = $syncErrors;
603 $this->mailbox[
'OPTIONS'][
'next_sync'] = time() + $interval;
605 $optionsValue = $this->mailbox[
'OPTIONS'];
607 $unlockSql = sprintf(
608 "UPDATE b_mail_mailbox SET SYNC_LOCK = %d, OPTIONS = '%s' WHERE ID = %u AND SYNC_LOCK = %u",
610 $DB->forSql(serialize($optionsValue)),
611 $this->mailbox[
'ID'],
612 $this->mailbox[
'SYNC_LOCK']
614 if ($DB->query($unlockSql)->affectedRowsCount())
616 $this->mailbox[
'SYNC_LOCK'] = $syncUnlock;
626 'complete' => $this->mailbox[
'SYNC_LOCK'] < 0,
633 if ($this->mailbox[
'USER_ID'] > 0)
635 $mailboxSyncManager->setSyncStatus($this->mailbox[
'ID'], $success, time());
653 if (Loader::includeModule(
'pull'))
657 \CPullWatch::addToStack(
658 'mail_mailbox_' . $this->mailbox[
'ID'],
660 'module_id' =>
'mail',
661 'command' =>
'mailbox_sync_status',
662 'params' => array_merge(
664 'id' => $this->mailbox[
'ID'],
665 'status' => sprintf(
'%.3f', $status),
666 'sessid' => $this->syncParams[
'sessid'] ?? $this->session,
667 'timestamp' => microtime(
true),
676 \Bitrix\Pull\Event::send();
692 if (time() - $this->mailbox[
'SYNC_LOCK'] < static::getTimeout())
702 $syncUnlock = $this->mailbox[
'SYNC_LOCK'];
705 'UPDATE b_mail_mailbox SET SYNC_LOCK = %u WHERE ID = %u AND (SYNC_LOCK IS NULL OR SYNC_LOCK < %u)',
708 if ($DB->query($lockSql)->affectedRowsCount())
719 $entity = Mail\MailMessageUidTable::getEntity();
720 $connection = $entity->getConnection();
722 $whereConditionForOldMessages = sprintf(
724 ORM\
Query\Query::buildFilterSql(
727 '=MAILBOX_ID' => $this->mailbox[
'ID'],
736 ' (%s) AND NOT EXISTS (SELECT 1 FROM %s WHERE (%s) AND (%s)) ',
737 ORM\
Query\Query::buildFilterSql(
740 '=MAILBOX_ID' => $this->mailbox[
'ID'],
745 $connection->getSqlHelper()->quote(
Mail\Internals\MessageAccessTable::getTableName()),
746 ORM\
Query\Query::buildFilterSql(
749 '=MAILBOX_ID' =>
new Main\DB\
SqlExpression(
'?#',
'MAILBOX_ID'),
750 '=MESSAGE_ID' =>
new Main\DB\
SqlExpression(
'?#',
'MESSAGE_ID'),
753 ORM\
Query\Query::buildFilterSql(
754 Mail\Internals\MessageAccessTable::getEntity(),
756 '=ENTITY_TYPE' => array(
757 Mail\Internals\MessageAccessTable::ENTITY_TYPE_TASKS_TASK,
758 Mail\Internals\MessageAccessTable::ENTITY_TYPE_BLOG_POST,
764 $sqlHelper = $connection->getSqlHelper();
766 $entityTable = $sqlHelper->quote($entity->getDbTableName());
769 $selectFrom = sprintf(
770 'SELECT ID, MAILBOX_ID, MESSAGE_ID FROM %s WHERE %s ORDER BY ID LIMIT 1000',
774 $connection->query($sqlHelper
775 ->getInsertIgnore($messageDeleteTable,
' (ID, MAILBOX_ID, MESSAGE_ID) ',
"($selectFrom)"));
777 $connection->query(sprintf(
778 "UPDATE %s SET IS_OLD = 'Y', IS_SEEN = 'Y' WHERE %s ORDER BY ID LIMIT 1000",
779 $connection->getSqlHelper()->quote($entity->getDbTableName()),
780 $whereConditionForOldMessages
783 $connection->query(sprintf(
784 'UPDATE %s SET MESSAGE_ID = 0 WHERE %s ORDER BY ID LIMIT 1000',
785 $connection->getSqlHelper()->quote($entity->getDbTableName()),
796 while ($connection->getAffectedRowsCount() >= 1000);
798 $unlockSql = sprintf(
799 "UPDATE b_mail_mailbox SET SYNC_LOCK = %d WHERE ID = %u AND SYNC_LOCK = %u",
800 $syncUnlock, $this->mailbox[
'ID'], $this->mailbox[
'SYNC_LOCK']
802 if ($DB->query($unlockSql)->affectedRowsCount())
804 $this->mailbox[
'SYNC_LOCK'] = $syncUnlock;
816 if (time() - $this->mailbox[
'SYNC_LOCK'] < static::getTimeout())
826 $syncUnlock = $this->mailbox[
'SYNC_LOCK'];
829 'UPDATE b_mail_mailbox SET SYNC_LOCK = %u WHERE ID = %u AND (SYNC_LOCK IS NULL OR SYNC_LOCK < %u)',
832 if ($DB->query($lockSql)->affectedRowsCount())
841 $minSyncTime = Mail\MailboxDirectory::getMinSyncTime($this->mailbox[
'ID']);
843 Mail\MailMessageUidTable::deleteList(
845 '=MAILBOX_ID' => $this->mailbox[
'ID'],
848 '<DELETE_TIME' => $minSyncTime,
851 static::MESSAGE_DELETION_LIMIT_AT_A_TIME
854 $unlockSql = sprintf(
855 "UPDATE b_mail_mailbox SET SYNC_LOCK = %d WHERE ID = %u AND SYNC_LOCK = %u",
856 $syncUnlock, $this->mailbox[
'ID'], $this->mailbox[
'SYNC_LOCK']
858 if ($DB->query($unlockSql)->affectedRowsCount())
860 $this->mailbox[
'SYNC_LOCK'] = $syncUnlock;
870 $res = Mail\Internals\MessageDeleteQueueTable::getList(array(
874 'Bitrix\Mail\MailMessageUidTable',
876 '=this.MAILBOX_ID' =>
'ref.MAILBOX_ID',
877 '=this.MESSAGE_ID' =>
'ref.MESSAGE_ID',
881 'select' => array(
'MESSAGE_ID',
'UID' =>
'MESSAGE_UID.ID'),
883 '=MAILBOX_ID' => $this->mailbox[
'ID'],
889 while ($item = $res->fetch())
893 if (empty($item[
'UID']))
895 \CMailMessage::delete($item[
'MESSAGE_ID']);
898 Mail\Internals\MessageDeleteQueueTable::deleteList(array(
899 '=MAILBOX_ID' => $this->mailbox[
'ID'],
900 '=MESSAGE_ID' => $item[
'MESSAGE_ID'],
917 '=MAILBOX_ID' => $this->mailbox[
'ID'],
920 if (!empty($params[
'filter']))
922 $filter = array_merge((array) $params[
'filter'], $filter);
925 $params[
'filter'] = $filter;
927 $result = Mail\MailMessageUidTable::getList($params);
929 return $fetch ? $result->fetchAll() : $result;
936 if (!empty($replaces))
944 if (!is_array($replaces))
951 $exists = Mail\MailMessageUidTable::getList([
958 '=MAILBOX_ID' => $this->mailbox[
'ID'],
959 '==DELETE_TIME' => 0,
967 'MESSAGE_ID' => $fields[
'MESSAGE_ID'],
974 $fields[
'MESSAGE_ID'] = $exists[
'MESSAGE_ID'];
978 '=ID' => $exists[
'ID'],
979 '=MAILBOX_ID' => $this->mailbox[
'ID'],
980 '==DELETE_TIME' => 0,
985 'TIMESTAMP_X' => $now,
991 'MAILBOX_USER_ID' => $this->mailbox[
'USER_ID'],
999 $addFields = array_merge(
1006 'MAILBOX_ID' => $this->mailbox[
'ID'],
1007 'SESSION_ID' => $this->session,
1008 'TIMESTAMP_X' => $now,
1009 'DATE_INSERT' => $now,
1013 Mail\MailMessageUidTable::checkFields($checkResult,
null, $addFields);
1014 if (!$checkResult->isSuccess())
1019 Mail\MailMessageUidTable::mergeData($addFields, [
1020 'MSG_UID' => $addFields[
'MSG_UID'],
1021 'HEADER_MD5' => $addFields[
'HEADER_MD5'],
1022 'SESSION_ID' => $addFields[
'SESSION_ID'],
1023 'TIMESTAMP_X' => $addFields[
'TIMESTAMP_X'],
1034 return Mail\MailMessageUidTable::updateList(
1039 '=MAILBOX_ID' => $this->mailbox[
'ID'],
1049 $messageExistInTheOriginalMailbox =
false;
1050 $messagesForRemove = [];
1051 $filterForCheck = [];
1053 if(!$ignoreDeletionCheck)
1055 $filterForCheck = array_merge(
1059 '=MAILBOX_ID' => $this->mailbox[
'ID'],
1066 '!=MESSAGE_ID' => 0,
1070 $messagesForRemove = Mail\MailMessageUidTable::getList([
1083 'filter' => $filterForCheck,
1088 if (!empty($messagesForRemove))
1090 if (isset($messagesForRemove[0][
'DIR_MD5']))
1092 $dirMD5 = $messagesForRemove[0][
'DIR_MD5'];
1093 $dirPath = $this->
getDirsHelper()->getDirPathByHash($dirMD5);
1096 return $item[
'MSG_UID'];
1106 if($messageExistInTheOriginalMailbox ===
false)
1108 return Mail\MailMessageUidTable::deleteListSoft(
1112 '=MAILBOX_ID' => $this->mailbox[
'ID'],
1119 $messageForLog = isset($messagesForRemove[0]) ? $messagesForRemove[0] : [];
1125 foreach($messagesForRemove as $message)
1127 if(isset($message[
'MSG_UID']) && (
int)$message[
'MSG_UID'] === (
int)$messageExistInTheOriginalMailbox)
1129 $messageForLog = $message;
1134 if(isset($messageForLog[
'INTERNALDATE']) && $messageForLog[
'INTERNALDATE'] instanceof Main\
Type\
DateTime)
1136 $messageForLog[
'INTERNALDATE'] = $messageForLog[
'INTERNALDATE']->getTimestamp();
1138 if(isset($messageForLog[
'DATE_INSERT']) && $messageForLog[
'DATE_INSERT'] instanceof Main\
Type\
DateTime)
1140 $messageForLog[
'DATE_INSERT'] = $messageForLog[
'DATE_INSERT']->getTimestamp();
1143 if(isset($filterForCheck[
'@ID']))
1145 $filterForCheck[
'@ID'] =
'[hidden for the log]';
1148 AddMessage2Log(array_merge($eventData,[
1149 'filter' => $filterForCheck,
1150 'message-data' => $messageForLog,
1159 $result = Mail\MailMessageUidTable::update(
1162 'MAILBOX_ID' => $this->mailbox[
'ID'],
1165 'MESSAGE_ID' => $id,
1169 return $result->isSuccess();
1174 if (empty($params[
'origin']) && empty($params[
'replaces']))
1180 return \CMailMessage::addMessage(
1181 $this->mailbox[
'ID'],
1183 $this->mailbox[
'CHARSET'] ?: $this->mailbox[
'LANG_CHARSET'],
1188 public function mail(array $params)
1190 class_exists(
'Bitrix\Mail\Helper');
1192 $message =
new Mail\DummyMail($params);
1196 Mail\Internals\MessageUploadQueueTable::add(array(
1197 'ID' => $messageUid,
1198 'MAILBOX_ID' => $this->mailbox[
'ID'],
1203 'Bitrix\Mail\Helper::syncOutgoingAgent(%u);',
1204 $this->mailbox[
'ID']
1212 $messageUid = sprintf(
'%x%x', time(), rand(0, 0xffffffff));
1215 $message->getHeaders(),
1216 $message->getBody(),
1217 $message->getMailEol()
1228 'trackable' =>
true,
1233 $fields = array_merge(
1236 'ID' => $messageUid,
1239 'MESSAGE_ID' => $messageId,
1255 'Bitrix\Mail\Internals\MessageUploadQueueTable',
1257 '=this.ID' =>
'ref.ID',
1258 '=this.MAILBOX_ID' =>
'ref.MAILBOX_ID',
1261 'join_type' =>
'INNER',
1267 '__' =>
'MESSAGE.*',
1268 'UPLOAD_LOCK' =>
'UPLOAD_QUEUE.SYNC_LOCK',
1269 'UPLOAD_STAGE' =>
'UPLOAD_QUEUE.SYNC_STAGE',
1270 'UPLOAD_ATTEMPTS' =>
'UPLOAD_QUEUE.ATTEMPTS',
1273 '>=UPLOAD_QUEUE.SYNC_STAGE' => 0,
1274 '<UPLOAD_QUEUE.SYNC_LOCK' => time() - static::getTimeout(),
1275 '<UPLOAD_QUEUE.ATTEMPTS' => 5,
1278 'UPLOAD_QUEUE.SYNC_LOCK' =>
'ASC',
1279 'UPLOAD_QUEUE.SYNC_STAGE' =>
'ASC',
1280 'UPLOAD_QUEUE.ATTEMPTS' =>
'ASC',
1286 while ($excerpt = $res->fetch())
1288 $n = $excerpt[
'UPLOAD_ATTEMPTS'] + 1;
1289 $interval = min(static::getTimeout() * pow($n, $n), 3600 * 24 * 7);
1291 if ($excerpt[
'UPLOAD_LOCK'] > time() - $interval)
1310 "UPDATE b_mail_message_upload_queue SET SYNC_LOCK = %u, SYNC_STAGE = %u, ATTEMPTS = ATTEMPTS + 1
1311 WHERE ID = '%s' AND MAILBOX_ID = %u AND SYNC_LOCK < %u",
1313 max(1, $excerpt[
'UPLOAD_STAGE']),
1314 $DB->forSql($excerpt[
'ID']),
1315 $excerpt[
'MAILBOX_ID'],
1316 $syncLock - static::getTimeout()
1318 if (!$DB->query($lockSql)->affectedRowsCount())
1323 $outgoingBody = $excerpt[
'__BODY_HTML'];
1325 $excerpt[
'__files'] = Mail\Internals\MailMessageAttachmentTable::getList(array(
1327 'ID',
'FILE_ID',
'FILE_NAME',
1330 '=MESSAGE_ID' => $excerpt[
'__ID'],
1334 $attachments = array();
1335 if (!empty($excerpt[
'__files']) && is_array($excerpt[
'__files']))
1337 $hostname = \COption::getOptionString(
'main',
'server_name',
'localhost');
1338 if (defined(
'BX24_HOST_NAME') && BX24_HOST_NAME !=
'')
1340 $hostname = BX24_HOST_NAME;
1342 else if (defined(
'SITE_SERVER_NAME') && SITE_SERVER_NAME !=
'')
1344 $hostname = SITE_SERVER_NAME;
1347 foreach ($excerpt[
'__files'] as $item)
1349 $file = \CFile::makeFileArray($item[
'FILE_ID']);
1351 $contentId = sprintf(
1352 'bxacid.%s@%s.mail',
1353 hash(
'crc32b', $file[
'external_id'].$file[
'size'].$file[
'name']),
1354 hash(
'crc32b', $hostname)
1357 $attachments[] = array(
1359 'NAME' => $item[
'FILE_NAME'],
1360 'PATH' => $file[
'tmp_name'],
1361 'CONTENT_TYPE' => $file[
'type'],
1364 $outgoingBody = preg_replace(
1365 sprintf(
'/aid:%u/i', $item[
'ID']),
1366 sprintf(
'cid:%s', $contentId),
1372 foreach (array(
'FROM',
'REPLY_TO',
'TO',
'CC',
'BCC') as $field)
1374 $field = sprintf(
'__FIELD_%s', $field);
1376 if (mb_strlen($excerpt[$field]) == 255 &&
'' != $excerpt[
'__HEADER'] && empty($parsedHeader))
1378 $parsedHeader = \CMailMessage::parseHeader($excerpt[
'__HEADER'], LANG_CHARSET);
1380 $excerpt[
'__FIELD_FROM'] = $parsedHeader->getHeader(
'FROM');
1381 $excerpt[
'__FIELD_REPLY_TO'] = $parsedHeader->getHeader(
'REPLY-TO');
1382 $excerpt[
'__FIELD_TO'] = $parsedHeader->getHeader(
'TO');
1383 $excerpt[
'__FIELD_CC'] = $parsedHeader->getHeader(
'CC');
1384 $excerpt[
'__FIELD_BCC'] = join(
', ', array_merge(
1385 (array) $parsedHeader->getHeader(
'X-Original-Rcpt-to'),
1386 (array) $parsedHeader->getHeader(
'BCC')
1390 $excerpt[$field] = explode(
',', $excerpt[$field]);
1392 foreach ($excerpt[$field] as $k => $item)
1394 unset($excerpt[$field][$k]);
1398 if ($address->validate())
1400 if ($address->getName())
1402 $excerpt[$field][] = sprintf(
1404 sprintf(
'=?%s?B?%s?=', SITE_CHARSET, base64_encode($address->getName())),
1405 $address->getEmail()
1410 $excerpt[$field][] = $address->getEmail();
1415 $excerpt[$field] = join(
', ', $excerpt[$field]);
1419 'CHARSET' => LANG_CHARSET,
1420 'CONTENT_TYPE' =>
'html',
1421 'ATTACHMENT' => $attachments,
1422 'TO' => $excerpt[
'__FIELD_TO'],
1423 'SUBJECT' => $excerpt[
'__SUBJECT'],
1424 'BODY' => $outgoingBody,
1426 'From' => $excerpt[
'__FIELD_FROM'],
1427 'Reply-To' => $excerpt[
'__FIELD_REPLY_TO'],
1428 'Cc' => $excerpt[
'__FIELD_CC'],
1429 'Bcc' => $excerpt[
'__FIELD_BCC'],
1430 'Message-Id' => sprintf(
'<%s>', $excerpt[
'__MSG_ID']),
1431 'X-Bitrix-Mail-Message-UID' => $excerpt[
'ID'],
1435 if(isset($excerpt[
'__IN_REPLY_TO']))
1437 $outgoingParams[
'HEADER'][
'In-Reply-To'] = sprintf(
'<%s>', $excerpt[
'__IN_REPLY_TO']);
1441 $context->setCategory(Main\
Mail\Context::CAT_EXTERNAL);
1442 $context->setPriority(Main\
Mail\Context::PRIORITY_NORMAL);
1444 $eventManager = \Bitrix\Main\EventManager::getInstance();
1445 $eventKey = $eventManager->addEventHandler(
1448 function () use (&$excerpt)
1450 if ($excerpt[
'UPLOAD_STAGE'] >= 2)
1457 $success = Main\Mail\Mail::send(array_merge(
1460 'TRACK_READ' => array(
1461 'MODULE_ID' =>
'mail',
1462 'FIELDS' => array(
'msgid' => $excerpt[
'__MSG_ID']),
1463 'URL_PAGE' =>
'/pub/mail/read.php',
1469 'CONTEXT' => $context,
1473 $eventManager->removeEventHandler(
'main',
'OnBeforeMailSend', $eventKey);
1475 if ($excerpt[
'UPLOAD_STAGE'] < 2 && !$success)
1481 if ($context->getSmtp() && $context->getSmtp()->getFrom() == $this->mailbox[
'EMAIL'])
1483 $needUpload = !in_array(
'deny_upload', (array) $this->mailbox[
'OPTIONS'][
'flags']);
1488 if ($excerpt[
'UPLOAD_STAGE'] < 2)
1490 Mail\Internals\MessageUploadQueueTable::update(
1492 'ID' => $excerpt[
'ID'],
1493 'MAILBOX_ID' => $excerpt[
'MAILBOX_ID'],
1502 class_exists(
'Bitrix\Mail\Helper');
1504 $message =
new Mail\DummyMail(array_merge(
1507 'HEADER' => array_merge(
1508 $outgoingParams[
'HEADER'],
1510 'To' => $outgoingParams[
'TO'],
1511 'Subject' => $outgoingParams[
'SUBJECT'],
1519 Mail\Internals\MessageUploadQueueTable::delete(array(
1520 'ID' => $excerpt[
'ID'],
1521 'MAILBOX_ID' => $excerpt[
'MAILBOX_ID'],
1527 Mail\Internals\MessageUploadQueueTable::update(
1529 'ID' => $excerpt[
'ID'],
1530 'MAILBOX_ID' => $excerpt[
'MAILBOX_ID'],
1550 'replaces' => $excerpt[
'ID'],
1563 [,,, $attachments] = \CMailMessage::parseMessage($body, $this->mailbox[
'LANG_CHARSET']);
1565 return $attachments;
1575 foreach ($filter[
'__actions'] as $action)
1577 if (empty($action[
'LAZY_ATTACHMENTS']))
1589 if (is_null($this->filters) || $force)
1591 $this->filters = Mail\MailFilterTable::getList(array(
1592 'filter' => ORM\
Query\Query::filter()
1593 ->where(
'ACTIVE',
'Y')
1595 ORM\
Query\Query::filter()->logic(
'or')
1596 ->where(
'MAILBOX_ID', $this->mailbox[
'ID'])
1597 ->where(
'MAILBOX_ID',
null)
1605 foreach ($this->filters as $k => $item)
1607 $this->filters[$k][
'__actions'] = array();
1609 $res = \CMailFilter::getFilterList($item[
'ACTION_TYPE']);
1610 while ($row = $res->fetch())
1612 $this->filters[$k][
'__actions'][] = $row;
1617 return $this->filters;
1627 $worker =
function ($id, $msgId, &$i)
1633 array($id, $msgId,
false),
1641 $level = array_pop($stack);
1645 [$id, $msgId, $skip] = array_shift($level);
1652 'UPDATE b_mail_message SET LEFT_MARGIN = %2$u, RIGHT_MARGIN = %3$u WHERE ID = %1$u',
1660 $res = Mail\MailMessageTable::getList(array(
1666 '=MAILBOX_ID' => $this->mailbox[
'ID'],
1667 '=IN_REPLY_TO' => $msgId,
1670 'FIELD_DATE' =>
'ASC',
1674 while ($item = $res->fetch())
1676 if (!in_array($item[
'ID'], $excerpt))
1678 $replies[] = array($item[
'ID'], $item[
'MSG_ID'],
false);
1684 array_unshift($level, array($id, $msgId,
true));
1686 array_push($stack, $level, $replies);
1696 'UPDATE b_mail_message SET RIGHT_MARGIN = %2$u WHERE ID = %1$u',
1705 if (!empty($message))
1707 if (empty($message[
'ID']))
1712 $item = $DB->query(sprintf(
1713 'SELECT GREATEST(M1, M2) AS I FROM (SELECT
1714 (SELECT RIGHT_MARGIN FROM b_mail_message WHERE MAILBOX_ID = %1$u AND RIGHT_MARGIN > 0 ORDER BY LEFT_MARGIN ASC LIMIT 1) M1,
1715 (SELECT RIGHT_MARGIN FROM b_mail_message WHERE MAILBOX_ID = %1$u AND RIGHT_MARGIN > 0 ORDER BY LEFT_MARGIN DESC LIMIT 1) M2
1717 $this->mailbox[
'ID']
1720 $i = empty($item[
'I']) ? 0 : $item[
'I'];
1722 $worker($message[
'ID'], $message[
'MSG_ID'], $i);
1727 'UPDATE b_mail_message SET LEFT_MARGIN = 0, RIGHT_MARGIN = 0 WHERE MAILBOX_ID = %u',
1728 $this->mailbox[
'ID']
1733 $res = $DB->query(sprintf(
1734 "SELECT ID, MSG_ID FROM b_mail_message M WHERE MAILBOX_ID = %u AND (
1735 IN_REPLY_TO IS NULL OR IN_REPLY_TO = '' OR NOT EXISTS (
1736 SELECT 1 FROM b_mail_message WHERE MAILBOX_ID = M.MAILBOX_ID AND MSG_ID = M.IN_REPLY_TO
1739 $this->mailbox[
'ID']
1742 while ($item = $res->fetch())
1744 $worker($item[
'ID'], $item[
'MSG_ID'], $i);
1749 'SELECT ID, MSG_ID FROM b_mail_message
1750 WHERE MAILBOX_ID = %u AND LEFT_MARGIN = 0
1751 ORDER BY FIELD_DATE ASC LIMIT 1',
1752 $this->mailbox[
'ID']
1754 while ($item = $DB->query($query)->fetch())
1756 $worker($item[
'ID'], $item[
'MSG_ID'], $i);
1766 if (empty($message[
'ID']))
1771 if (!empty($message[
'IN_REPLY_TO']))
1773 $item = Mail\MailMessageTable::getList(array(
1775 'ID',
'MSG_ID',
'LEFT_MARGIN',
'RIGHT_MARGIN',
1778 '=MAILBOX_ID' => $this->mailbox[
'ID'],
1779 '=MSG_ID' => $message[
'IN_REPLY_TO'],
1782 'LEFT_MARGIN' =>
'ASC',
1790 $item = Mail\MailMessageTable::getList(array(
1795 '=MAILBOX_ID' => $this->mailbox[
'ID'],
1796 '<LEFT_MARGIN' => $item[
'LEFT_MARGIN'],
1797 '>RIGHT_MARGIN' => $item[
'RIGHT_MARGIN'],
1800 'LEFT_MARGIN' =>
'ASC',
1819 abstract public function listDirs($pattern, $useDb =
false);
1827 return $this->errors;
1832 return $this->warnings;
1837 return $this->lastSyncResult;
1842 $this->lastSyncResult = array_merge($this->lastSyncResult, $data);
1847 if (!$this->dirsHelper)
1852 return $this->dirsHelper;
1857 $options = $this->mailbox[
'OPTIONS'];
1859 if (!isset($options[
'activateSync']) || $options[
'activateSync'] ===
true)
1864 $entity = MailboxTable::getEntity();
1865 $connection = $entity->getConnection();
1867 $options[
'activateSync'] =
true;
1870 'UPDATE %s SET %s WHERE %s',
1871 $connection->getSqlHelper()->quote($entity->getDbTableName()),
1872 $connection->getSqlHelper()->prepareUpdate($entity->getDbTableName(), [
1874 'OPTIONS' => serialize($options),
1876 Query::buildFilterSql(
1879 'ID' => $this->mailbox[
'ID']
1884 return $connection->query($query);
1889 if (Loader::includeModule(
'im'))
1901 if ($newMessageId > 0 && $count === 1)
1903 $message = Mail\MailMessageTable::getByPrimary($newMessageId)->fetch();
1905 if (!empty($message))
1907 Mail\Helper\Message::prepare($message);
1911 Mail\Integration\Im\Notification::add(
1912 $this->mailbox[
'USER_ID'],
1915 'mailboxOwnerId' => $this->mailbox[
'USER_ID'],
1916 'mailboxId' => $this->mailbox[
'ID'],
1918 'message' => $message,
1932 $supportedActionTypes = [
1941 !in_array($filter[
'ACTION_TYPE'], $supportedActionTypes,
true)
1943 $this->hasActionWithoutSanitizeSupport($filter[
'__actions'])
1944 || !empty($filter[
'PHP_CONDITION'])
1945 || !empty($filter[
'ACTION_PHP'])
1962 private function hasActionWithoutSanitizeSupport($actions): bool
1964 if (is_array($actions))
1966 foreach ($actions as $action)
1968 if (empty($action[
'SANITIZE_ON_VIEW']))
1983 return min(max(0, ini_get(
'max_execution_time')) ?: static::SYNC_TIMEOUT, static::SYNC_TIMEOUT);
1988 $mailbox = Mail\MailboxTable::getUserMailboxWithEmail($email);
1991 return static::createInstance(
$mailbox[
'ID'],
false);
2005 $instance = static::createInstance(
$mailbox[
'ID'],
false);
2009 if (!empty($email) && empty($instance))
2011 $instance = static::getForUserByEmail($email);
2014 if (!empty($instance))
static isCleanupOldEnabled()
static checkTheMailboxForSyncAvailability(int $checkedMailboxId)
static createInstance($id, $throw=true)
downloadAttachments(array &$excerpt)
resortTree($message=null)
createMessage(Main\Mail\Mail $message, array $fields=array())
getDirsMd5WithCounter($mailboxId)
listDirs($pattern, $useDb=false)
uploadMessage(Main\Mail\Mail $message, array &$excerpt)
setSyncParams(array $params=array())
syncOutgoingMessage($excerpt)
updateGlobalCounterForCurrentUser()
registerMessage(&$fields, $replaces=null, $isOutgoing=false)
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
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 setMailboxUnseenCounter($mailboxId, $count)
static updateMailCounters($mailbox)
const FIELD_SANITIZE_ON_VIEW
static updateList(array $filter, array $fields, array $eventData=[])
static getPresetRemoveFilters()
static getIconSrc($serviceName, $iconId=null)
static getUserMailbox($mailboxId, $userId=null)
static createFromTimestamp($timestamp)