• Модуль: crm
  • Путь к файлу: ~/bitrix/modules/crm/classes/general/crm_email.php
  • Класс: \CCrmEMail
  • Вызов: CCrmEMail::imapEmailMessageAdd
static function imapEmailMessageAdd($msgFields, $actionVars = null, &$error = null)
{
	global $DB;

	$error = null;

	if (!\CModule::includeModule('crm'))
		return false;

	$eventTag = sprintf('%x%x', time(), rand(0, 0xffffffff));

	$messageId = isset($msgFields['ID']) ? intval($msgFields['ID']) : 0;
	$mailboxId = isset($msgFields['MAILBOX_ID']) ? intval($msgFields['MAILBOX_ID']) : 0;

	if (empty($mailboxId))
	{
		static::log(
			$eventTag,
			'CCrmEmail: empty MAILBOX_ID',
			array(
				'ID' => $msgFields['ID'],
				'MAILBOX_ID' => $msgFields['MAILBOX_ID'],
			)
		);

		return false;
	}

	$mailbox = \CMailBox::getById($mailboxId)->fetch();

	if (empty($mailbox))
	{
		static::log(
			$eventTag,
			'CCrmEmail: empty mailbox',
			array(
				'ID' => $msgFields['ID'],
				'MAILBOX_ID' => $msgFields['MAILBOX_ID'],
			)
		);

		return false;
	}

	$crmNewEntityOptionName = empty($msgFields['IS_OUTCOME']) ? 'crm_new_entity_in' : 'crm_new_entity_out';
	static::log(
		$eventTag,
		'CCrmEmail: IMAP email message received',
		array(
			'ID' => $msgFields['ID'],
			'MAILBOX_ID' => $msgFields['MAILBOX_ID'],
			'MSG_HASH' => $msgFields['MSG_HASH'],
			'OPTIONS' => array_filter(array(
				'flags' => $mailbox['OPTIONS']['flags'],
				'crm_sync_from' => $mailbox['OPTIONS']['crm_sync_from'],
				//'crm_lead_resp' => $mailbox['OPTIONS']['crm_lead_resp'],
				//'crm_new_lead_for' => $mailbox['OPTIONS']['crm_new_lead_for'],
				$crmNewEntityOptionName => $mailbox['OPTIONS'][$crmNewEntityOptionName],
			)),
			'TAGS' => array_keys(array_filter(array(
				'IS_INCOME' => empty($msgFields['IS_OUTCOME']),
				'IS_OUTCOME' => !empty($msgFields['IS_OUTCOME']),
				'IS_DRAFT' => !empty($msgFields['IS_DRAFT']),
				'IS_TRASH' => !empty($msgFields['IS_TRASH']),
				'IS_SPAM' => !empty($msgFields['IS_SPAM']),
				'__forced' => !empty($msgFields['__forced']),
			))),
		)
	);

	$isForced = !empty($msgFields['__forced']);

	if (!$isForced && !empty($mailbox['OPTIONS']['crm_sync_from']))
	{
		$timestamp = makeTimestamp($msgFields['FIELD_DATE'], FORMAT_DATETIME) - \CTimeZone::getOffset();
		if ($timestamp < (int) $mailbox['OPTIONS']['crm_sync_from'])
		{
			static::log($eventTag, 'CCrmEmail: too old');

			return false;
		}
	}

	$mailbox['__email'] = '';
	if (check_email($mailbox['NAME'], true))
		$mailbox['__email'] = $mailbox['NAME'];
	else if (check_email($mailbox['LOGIN'], true))
		$mailbox['__email'] = $mailbox['LOGIN'];

	$publicBindings = false;
	$denyNewEntityIn = false;
	$denyNewEntityOut = false;
	$denyNewContact = false;

	if (!empty($mailbox['OPTIONS']['flags']) && is_array($mailbox['OPTIONS']['flags']))
	{
		$publicBindings = in_array('crm_public_bind', $mailbox['OPTIONS']['flags']);
		$denyNewContact = in_array('crm_deny_new_contact', $mailbox['OPTIONS']['flags']);

		if (!$isForced)
		{
			$denyNewEntityIn = in_array('crm_deny_new_lead', $mailbox['OPTIONS']['flags']);
			$denyNewEntityIn = $denyNewEntityIn || in_array('crm_deny_entity_in', $mailbox['OPTIONS']['flags']);
			$denyNewEntityOut = in_array('crm_deny_new_lead', $mailbox['OPTIONS']['flags']);
			$denyNewEntityOut = $denyNewEntityOut || in_array('crm_deny_entity_out', $mailbox['OPTIONS']['flags']);
		}
	}

	$isIncome = empty($msgFields['IS_OUTCOME']);
	$isDraft = !empty($msgFields['IS_DRAFT']);
	$isTrash = !empty($msgFields['IS_TRASH']);
	$isSpam = !empty($msgFields['IS_SPAM']);
	$isUnseen = empty($msgFields['IS_SEEN']);

	if (!$isForced and $isDraft || $isTrash || $isSpam)
	{
		static::log($eventTag, 'CCrmEmail: draft|trash|spam');

		return false;
	}

	$userId = 0;

	$ownerTypeId = 0;
	$ownerId     = 0;

	$parentId = 0;

	$msgId     = isset($msgFields['MSG_ID']) ? $msgFields['MSG_ID'] : '';
	$inReplyTo = isset($msgFields['IN_REPLY_TO']) ? $msgFields['IN_REPLY_TO'] : '';

	$from    = isset($msgFields['FIELD_FROM']) ? $msgFields['FIELD_FROM'] : '';
	$replyTo = isset($msgFields['FIELD_REPLY_TO']) ? $msgFields['FIELD_REPLY_TO'] : '';

	$senderAddress = array();
	$sender = array();
	foreach (array_merge(explode(',', $replyTo), explode(',', $from)) as $item)
	{
		if (trim($item))
		{
			$address = new \Bitrix\Main\Mail\Address($item);
			if ($address->validate() && !in_array($address->getEmail(), $sender))
			{
				$senderAddress[] = $address;
				$sender[] = $address->getEmail();
			}
		}
	}

	$to  = isset($msgFields['FIELD_TO']) ? $msgFields['FIELD_TO'] : '';
	$cc  = isset($msgFields['FIELD_CC']) ? $msgFields['FIELD_CC'] : '';
	$bcc = isset($msgFields['FIELD_BCC']) ? $msgFields['FIELD_BCC'] : '';

	$rcptAddress = array();
	$rcpt = array();
	foreach (array_merge(explode(',', $to), explode(',', $cc), explode(',', $bcc)) as $item)
	{
		if (trim($item))
		{
			$address = new \Bitrix\Main\Mail\Address($item);
			if ($address->validate() && !in_array($address->getEmail(), $rcpt))
			{
				$rcptAddress[] = $address;
				$rcpt[] = $address->getEmail();
			}
		}
	}

	$subject   = trim($msgFields['SUBJECT']) ?: getMessage('CRM_EMAIL_DEFAULT_SUBJECT');

	$emailFacility = new Bitrix\Crm\Activity\EmailFacility();

	if (!$isForced && $isIncome && preg_match('/\nX-EVENT_NAME:/i', $msgFields['HEADER']))
	{
		$defaultEmailFrom = \Bitrix\Main\Config\Option::get('main', 'email_from', 'admin@'.$GLOBALS['SERVER_NAME']);
		$defaultEmailFrom = mb_strtolower(trim($defaultEmailFrom));

		foreach ($sender as $item)
		{
			if (mb_strtolower(trim($item)) == $defaultEmailFrom)
			{
				static::log($eventTag, 'CCrmEmail: system email');

				return false;
			}
		}
	}

	// @TODO: killmail

	if (!empty($msgId))
	{
		if (!$isIncome && preg_match('/]+>/i', sprintf('<%s>', $msgId), $matches))
		{
			$matchActivity = \CCrmActivity::getList(
				array(),
				array(
					'ID' => $matches[2],
					'CHECK_PERMISSIONS' => 'N',
				),
				false,
				false,
				array('ID', 'URN', 'UF_MAIL_MESSAGE')
			)->fetch();
			if ($matchActivity && mb_strtolower($matchActivity['URN']) == mb_strtolower($matches[1]))
			{
				\CCrmActivity::update(
					$matchActivity['ID'],
					array(
						'UF_MAIL_MESSAGE' => $messageId,
					),
					false,
					false
				);

				static::log($eventTag, 'CCrmEmail: matches outgoing');

				return true;
			}
		}
	}

	// skip employees
	$employeesEmails = array();
	{
		$filter = array(
			'=ACTIVE' => 'Y',
			'=EMAIL' => $isIncome ? $sender : $rcpt,
			'IS_REAL_USER' => 'Y',
		);

		$res = \Bitrix\Main\UserTable::getList(array(
			'select' => array('ID', 'EMAIL', 'UF_DEPARTMENT'),
			'filter' => $filter,
		));

		if ($isIncome)
		{
			while ($employee = $res->fetch())
			{
				$departments = empty($employee['UF_DEPARTMENT']) ? array() : (array) $employee['UF_DEPARTMENT'];
				if (reset($departments) > 0)
				{
					static::log(
						$eventTag,
						'CCrmEmail: from employee',
						array(
							'USER_ID' => $employee['ID'],
							'USER_EMAIL' => $employee['EMAIL'],
						)
					);

					$error = new \Bitrix\Main\Error(Loc::getMessage('CRM_EMAIL_IMAP_ERROR_EMPLOYE_IN'));
					return false;
				}
			}

			if (CModule::includeModule('mail'))
			{
				// @TODO: index
				$employee = \Bitrix\Mail\MailboxTable::getList(array(
					'select' => array('ID', 'EMAIL', 'NAME', 'LOGIN', 'USER_ID'),
					'filter' => array(
						'=ACTIVE'  => 'Y',
						array(
							'LOGIC' => 'OR',
							'EMAIL' => $sender,
							'NAME'  => $sender,
							'LOGIN' => $sender,
						),
					),
					'limit' => 1,
				))->fetch();

				if (!empty($employee))
				{
					static::log(
						$eventTag,
						'CCrmEmail: from employee',
						array(
							'USER_ID' => $employee['USER_ID'],
							'MAILBOX_ID' => $employee['ID'],
							'MAILBOX_EMAIL' => $employee['EMAIL'],
							'MAILBOX_NAME' => $employee['NAME'],
							'MAILBOX_LOGIN' => $employee['LOGIN'],
						)
					);

					$error = new \Bitrix\Main\Error(Loc::getMessage('CRM_EMAIL_IMAP_ERROR_EMPLOYE_IN'));
					return false;
				}
			}
		}
		else
		{
			$employees = array();

			while ($employee = $res->fetch())
			{
				$departments = empty($employee['UF_DEPARTMENT']) ? array() : (array) $employee['UF_DEPARTMENT'];
				if (reset($departments) > 0)
				{
					$employees[] = array(
						'USER_ID' => $employee['ID'],
						'USER_EMAIL' => $employee['EMAIL'],
					);
					$employeesEmails[] = $employee['EMAIL'];
				}
			}

			$employeesEmails = array_unique(array_map('mb_strtolower', $employeesEmails));

			if (count($employeesEmails) >= count($rcpt))
			{
				static::log(
					$eventTag,
					'CCrmEmail: to employees',
					array(
						'LIST' => $employees,
					)
				);

				$error = new \Bitrix\Main\Error(Loc::getMessage('CRM_EMAIL_IMAP_ERROR_EMPLOYE_OUT'));
				return false;
			}

			if (CModule::includeModule('mail'))
			{
				// @TODO: index
				$res = \Bitrix\Mail\MailboxTable::getList(array(
					'select' => array('ID', 'EMAIL',  'NAME', 'LOGIN', 'USER_ID'),
					'filter' => array(
						'=ACTIVE'  => 'Y',
						array(
							'LOGIC' => 'OR',
							'EMAIL' => $rcpt,
							'NAME'  => $rcpt,
							'LOGIN' => $rcpt,
						),
					),
				));

				$employees = array();

				while ($employee = $res->fetch())
				{
					$employees[] = array(
						'USER_ID' => $employee['USER_ID'],
						'MAILBOX_ID' => $employee['ID'],
						'MAILBOX_EMAIL' => $employee['EMAIL'],
						'MAILBOX_NAME' => $employee['NAME'],
						'MAILBOX_LOGIN' => $employee['LOGIN'],
					);
					$employeesEmails[] = (check_email($employee['EMAIL'], true) ? $employee['EMAIL'] : (check_email($employee['NAME'], true) ? $employee['NAME'] : $employee['LOGIN']));
				}

				$employeesEmails = array_unique(array_map('mb_strtolower', $employeesEmails));

				if (count($employeesEmails) >= count($rcpt))
				{
					static::log(
						$eventTag,
						'CCrmEmail: to employees',
						array(
							'LIST' => $employees,
						)
					);

					$error = new \Bitrix\Main\Error(Loc::getMessage('CRM_EMAIL_IMAP_ERROR_EMPLOYE_OUT'));
					return false;
				}
			}
		}
	}

	$mailboxOwnerId = (int)$mailbox['USER_ID'] ?? 0;

	// initialize responsible queue
	$respQueue = array();
	{
		$respOption = array_values(array_unique((array) $mailbox['OPTIONS']['crm_lead_resp']));
		if (empty($respOption) && $mailboxOwnerId > 0)
		{
			$respOption = array($mailboxOwnerId);
		}

		if (!empty($respOption))
		{
			$res = \Bitrix\Main\UserTable::getList(array(
				'select' => array('ID', 'ACTIVE'),
				'filter' => array(
					'@ID' => $respOption,
					'=ACTIVE' => 'Y',
				),
			));

			$respActive = array();

			while ($resp = $res->fetch())
			{
				$respQueue[] = $resp['ID'];

				if ($resp['ACTIVE'] == 'Y')
				{
					$respActive[] = $resp['ID'];
				}
			}

			if (!empty($respActive))
			{
				$respQueue = $respActive;
			}

			$respOrder = array_flip($respOption);
			usort(
				$respQueue,
				function ($a, $b) use (&$respOrder)
				{
					return isset($respOrder[$a], $respOrder[$b]) ? $respOrder[$a]-$respOrder[$b] : 0;
				}
			);

			if (count($respOption) > 0 && count($respActive) == count($respOption))
			{
				\Bitrix\Main\Config\Option::set('crm', 'email_resp_queue_ok_'.$mailboxId, 'Y');
			}
			else
			{
				$shouldNotify = \Bitrix\Main\Config\Option::get('crm', 'email_resp_queue_ok_' . $mailboxId, 'Y') == 'Y';
				if ($shouldNotify && \CModule::includeModule('im'))
				{
					\Bitrix\Main\Config\Option::set('crm', 'email_resp_queue_ok_' . $mailboxId, 'N');

					$configUrl = str_replace(
						'#id#',
						$mailboxId,
						\Bitrix\Main\Config\Option::get('intranet', 'path_mail_config', '/mail/', $mailbox['LID'])
					);

					$internalMessage = getMessage('CRM_EMAIL_BAD_RESP_QUEUE', array(
						'#EMAIL#'      => htmlspecialcharsbx($mailbox['NAME']),
						'#CONFIG_URL#' => htmlspecialcharsbx($configUrl),
					));
					$externalMessage = getMessage('CRM_EMAIL_BAD_RESP_QUEUE', array(
						'#EMAIL#'      => htmlspecialcharsbx($mailbox['NAME']),
						'#CONFIG_URL#' => htmlspecialcharsbx(\CCrmUrlUtil::toAbsoluteUrl($configUrl)),
					));

					\CCrmNotifier::notify(
						$mailbox['USER_ID'],
						$internalMessage,
						$externalMessage,
						0,
						'email_resp_queue_ok_' . $mailboxId
					);
				}
			}
		}

		if (empty($respQueue))
		{
			$respQueue = array_column(self::getAdminsList(), 'ID') ?: array(1);
		}
	}

	$targetActivity = Bitrix\Crm\Activity\Provider\Email::getParentByEmail($msgFields);
	if (!empty($targetActivity))
	{
		static::log(
			$eventTag,
			'CCrmEmail: parent found',
			array(
				'ACTIVITY_ID' => $targetActivity['ID'],
			)
		);

		$parentId = $targetActivity['ID'];

		$isForced = true;

		switch ($targetActivity['OWNER_TYPE_ID'])
		{
			case \CCrmOwnerType::Deal:
				$owner = \Bitrix\Crm\DealTable::getList(array(
					'select' => array('ID', 'ASSIGNED_BY_ID'),
					'filter' => array(
						'=ID' => $targetActivity['OWNER_ID'],
						$publicBindings ? array() : array('@ASSIGNED_BY_ID' => $respQueue),
						'=STAGE_SEMANTIC_ID' => \Bitrix\Crm\PhaseSemantics::PROCESS,
					),
				))->fetch();
				break;
			case \CCrmOwnerType::Lead:
				$owner = \Bitrix\Crm\LeadTable::getList(array(
					'select' => array('ID', 'ASSIGNED_BY_ID'),
					'filter' => array(
						'=ID' => $targetActivity['OWNER_ID'],
						$publicBindings ? array() : array('@ASSIGNED_BY_ID' => $respQueue),
						'=STATUS_SEMANTIC_ID' => \Bitrix\Crm\PhaseSemantics::PROCESS,
					),
				))->fetch();
				break;
		}

		// @TODO: converted lead

		if (!empty($owner))
		{
			static::log(
				$eventTag,
				'CCrmEmail: parent owner is active lead|deal',
				array(
					'OWNER_TYPE_ID' => $targetActivity['OWNER_TYPE_ID'],
					'OWNER_ID' => $targetActivity['OWNER_ID'],
				)
			);

			$ownerTypeId = $targetActivity['OWNER_TYPE_ID'];
			$ownerId = $targetActivity['OWNER_ID'];
		}
	}

	$forceNewLead = false;
	if ($isIncome && empty($targetActivity)) // @TODO: do not check $targetActivity?
	{
		if (!empty($mailbox['OPTIONS']['crm_new_lead_for']) && is_array($mailbox['OPTIONS']['crm_new_lead_for']))
		{
			$matches = array_intersect(
				array_map('mb_strtolower', array_map('trim', $sender)),
				array_map('mb_strtolower', array_map('trim', $mailbox['OPTIONS']['crm_new_lead_for']))
			);

			if ($forceNewLead = (boolean) $matches)
			{
				static::log($eventTag, 'CCrmEmail: force new lead', $matches);
			}
		}
	}

	$rankingModifier = function ($ranking) use (&$respQueue)
	{
		$knownTypes = array(
			\CCrmOwnerType::Contact => 'CCrmContact',
			\CCrmOwnerType::Company => 'CCrmCompany',
			\CCrmOwnerType::Lead => 'CCrmLead',
		);

		$typeId = $ranking->getEntityTypeId();
		$list = array();

		if (array_key_exists($typeId, $knownTypes) && !empty($ranking->getRankedList()))
		{
			$res = $knownTypes[$typeId]::getListEx(
				array(),
				array(
					'ID' => (array) $ranking->getRankedList(),
					'ASSIGNED_BY_ID' => $respQueue,
					'CHECK_PERMISSIONS' => 'N',
				),
				false,
				false,
				array('ID')
			);

			while ($item = $res->fetch())
			{
				$list[] = $item['ID'];
			}
		}

		$ranking->setModifiedList($list);
		$ranking->setRankedList($list);
	};

	$newEntityTypeId = \CCrmOwnerType::Lead;

	$filteredAddress = array_filter(
		$isIncome ? $senderAddress : $rcptAddress,
		function ($item) use (&$employeesEmails)
		{
			return !in_array($item->getEmail(), $employeesEmails);
		}
	);

	$trace = Tracking\Trace::create()->addChannel(
		new Tracking\Channel\Mail(!empty($rcptAddress) ?
			reset($rcptAddress)->getEmail() : null
		)
	);

	if ($forceNewLead)
	{
		$commAddress = $filteredAddress;

		$facility = new \Bitrix\Crm\EntityManageFacility();
		$facility->setDirection($isIncome ? $facility::DIRECTION_INCOMING : $facility::DIRECTION_OUTGOING);
		$facility->setTrace($trace);

		if ($isForced)
		{
			$facility->getSelector()->disableExclusionChecking();
		}
	}
	else
	{
		$commAddress = array();
		foreach ($filteredAddress as $item)
		{
			$itemSelector = new \Bitrix\Crm\Integrity\ActualEntitySelector();
			$itemSelector->appendEmailCriterion($item->getEmail());

			if (!$publicBindings)
			{
				$itemSelector->getRanking()->addModifier($rankingModifier);
			}

			if ($isForced)
			{
				$itemSelector->disableExclusionChecking();
			}

			$itemSelector->search();

			if ($itemSelector->hasExclusions())
			{
				if ($isIncome)
				{
					$selector = $itemSelector;

					break;
				}
				else
				{
					continue;
				}
			}

			if (empty($firstSelector))
			{
				$firstSelector = $itemSelector;
			}

			if ($itemSelector->hasEntities())
			{
				if (empty($selector))
				{
					$selector = $itemSelector;
					array_unshift($commAddress, $item);
				}
			}
			else
			{
				$commAddress[] = $item;
			}
		}

		if (empty($selector))
		{
			if (empty($firstSelector))
			{
				return false;
			}

			$selector = $firstSelector;
		}
		else
		{
			if (!$isIncome)
			{
				$commAddress = array();
			}
		}

		$facility = new \Bitrix\Crm\EntityManageFacility($selector);
		$facility->setDirection($isIncome ? $facility::DIRECTION_INCOMING : $facility::DIRECTION_OUTGOING);
		$facility->setTrace($trace);

		$emailFacility->setBindings($facility->getActivityBindings());

		$criterions = $selector->getCriteria();
		static::log(
			$eventTag,
			'CCrmEmail: search results',
			array(
				'SEARCH_VALUE' => reset($criterions)->getValue(),
				'IS_EXCLUSION' => $selector->hasExclusions(),
				'LIST' => $facility->getActivityBindings(),
			)
		);

		if ($parentId > 0 && ($ownerTypeId > 0 && $ownerId > 0))
		{
			$cantCreate = true;

			$emailFacility->setOwner($ownerTypeId, $ownerId);
			$emailFacility->setBindings(array_filter(
				$emailFacility->getBindings(),
				function ($item)
				{
					return !in_array($item['OWNER_TYPE_ID'], array(\CCrmOwnerType::Deal, \CCrmOwnerType::Lead));
				}
			));
		}
		else
		{
			$cantCreate = $isIncome
				? ($denyNewEntityIn && empty($emailFacility->getBindings()))
				: ($denyNewEntityOut || !empty($emailFacility->getBindings()));
		}

		if ($cantCreate)
		{
			$facility->setRegisterMode($facility::REGISTER_MODE_ONLY_UPDATE);
		}

		$newEntityType = $mailbox['OPTIONS'][$isIncome ? 'crm_new_entity_in' : 'crm_new_entity_out'];
		if (\CCrmOwnerType::ContactName == $newEntityType && empty($emailFacility->getBindings()))
		{
			$newEntityTypeId = \CCrmOwnerType::Contact;
		}
	}

	if (!empty($emailFacility->getBindings()))
	{
		$userId = $emailFacility->getOwnerResponsibleId();
	}
	else if ($facility->canAddEntity($newEntityTypeId))
	{
		$luckyOne = \Bitrix\Main\Config\Option::get('crm', 'last_resp_' . $mailboxId, -1) + 1;
		if ($luckyOne > count($respQueue) - 1)
		{
			$luckyOne = 0;
		}

		\Bitrix\Main\Config\Option::set('crm', 'last_resp_' . $mailboxId, $luckyOne);

		$userId = $respQueue[$luckyOne];
	}
	else
	{
		return false;
	}

	$contactFields = array();

	$contactTypes = \CCrmStatus::getStatusList('CONTACT_TYPE');
	if (isset($contactTypes['CLIENT']))
	{
		$contactFields['TYPE_ID'] = 'CLIENT';
	}
	else if (isset($contactTypes['OTHER']))
	{
		$contactFields['TYPE_ID'] = 'OTHER';
	}

	$leadFields = array(
		'COMPANY_TITLE' => \CCrmCompany::getDefaultTitle(),
	);

	if (trim($msgFields['SUBJECT']))
	{
		$leadFields['TITLE'] = trim($msgFields['SUBJECT']);
	}
	else
	{
		$leadFields['TITLE'] = getMessage(
			($isIncome ? 'CRM_MAIL_LEAD_FROM_EMAIL_TITLE' : 'CRM_MAIL_LEAD_FROM_USER_EMAIL_TITLE'),
			array('%SENDER%' => $replyTo ?: $from)
		);
	}

	$entityFields = array(
		'COMMENTS' => htmlspecialcharsbx($subject),
		'ORIGINATOR_ID' => 'email-tracker',
		'ORIGIN_ID' => $mailboxId,
	);

	$sourceList = \CCrmStatus::getStatusList('SOURCE');
	$sourceId   = $mailbox['OPTIONS']['crm_lead_source'];
	if (empty($sourceId) || !isset($sourceList[$sourceId]))
	{
		if (isset($sourceList['EMAIL']))
		{
			$sourceId = 'EMAIL';
		}
		else if (isset($sourceList['OTHER']))
		{
			$sourceId = 'OTHER';
		}
	}

	if ($sourceId != '')
		$entityFields['SOURCE_ID'] = $sourceId;

	if (!empty($commAddress))
	{
		$entityFields['FM'] = array('EMAIL' => array());
		foreach ($commAddress as $i => $item)
		{
			$entityFields['FM']['EMAIL'][sprintf('n%u', $i+1)] = array(
				'VALUE_TYPE' => 'WORK',
				'VALUE'      => $item->getEmail(),
			);

			if (empty($entityFields['NAME']) && !empty($item->getName()))
			{
				$entityFields['NAME'] = $item->getName();
			}
		}

		if (empty($entityFields['NAME']))
		{
			$entityFields['NAME'] = reset($commAddress)->getEmail();
		}
	}

	$entitiesFields = array(
		\CCrmOwnerType::Lead => $leadFields + $entityFields,
		\CCrmOwnerType::Contact => $contactFields + $entityFields,
	);

	// @TODO: update lead

	$facility->registerTouch(
		$newEntityTypeId,
		$entitiesFields,
		true,
		array(
			'CURRENT_USER' => $userId,
			'DISABLE_USER_FIELD_CHECK' => true,
			'REGISTER_SONET_EVENT' => true,
		)
	);

	if ($facility->getRegisteredId() > 0)
	{
		static::log(
			$eventTag,
			'CCrmEmail: created entity',
			array(
				'ENTITY_TYPE' => \CCrmOwnerType::resolveName($facility->getRegisteredTypeId()),
				'ENTITY_TYPE_ID' => $facility->getRegisteredTypeId(),
				'ENTITY_ID' => $facility->getRegisteredId(),
			)
		);

		$emailFacility->setBindings($facility->getActivityBindings(), true);

		$channelTrackerParams = array(
			'ORIGIN_ID' => sprintf('%u|%u', $mailbox['USER_ID'], $mailbox['ID'])
		);

		if ($facility->getRegisteredTypeId() == \CCrmOwnerType::Lead)
		{
			Channel\EmailTracker::getInstance()->registerLead($facility->getRegisteredId(), $channelTrackerParams);
		}
		else if ($facility->getRegisteredTypeId() == \CCrmOwnerType::Deal)
		{
			Channel\EmailTracker::getInstance()->registerDeal($facility->getRegisteredId(), $channelTrackerParams);
		}
	}

	if (empty($emailFacility->getBindings()))
	{
		return false;
	}

	$ownerTypeId = $emailFacility->getOwnerTypeId();
	$ownerId     = $emailFacility->getOwnerId();

	$attachmentMaxSizeMb = (int) \COption::getOptionString('crm', 'email_attachment_max_size', 24);
	$attachmentMaxSize = $attachmentMaxSizeMb > 0 ? $attachmentMaxSizeMb*1024*1024 : 0;

	// @TODO: update $msgFields
	if (\Bitrix\Mail\Helper\Message::ensureAttachments($msgFields) > 0)
	{
		if ($message = \CMailMessage::getById($messageId)->fetch())
		{
			$msgFields = $message + $msgFields;
		}
	}

	$body = isset($msgFields['BODY']) ? $msgFields['BODY'] : '';
	$body_bb = isset($msgFields['BODY_BB']) ? $msgFields['BODY_BB'] : '';
	$body_html = isset($msgFields['BODY_HTML']) ? $msgFields['BODY_HTML'] : '';

	$filesData = array();
	$bannedAttachments = array();
	$res = \CMailAttachment::getList(array(), array('MESSAGE_ID' => $messageId));
	while ($attachment = $res->fetch())
	{
		if (getFileExtension(mb_strtolower($attachment['FILE_NAME'])) == 'vcf' && !$denyNewContact)
		{
			if ($attachment['FILE_ID'])
				$attachment['FILE_DATA'] = \CMailAttachment::getContents($attachment);
			self::tryImportVCard($attachment['FILE_DATA'], $userId);
		}

		$fileSize = isset($attachment['FILE_SIZE']) ? intval($attachment['FILE_SIZE']) : 0;
		if ($fileSize <= 0)
			continue;

		if ($attachmentMaxSize > 0 && $fileSize > $attachmentMaxSize)
		{
			$bannedAttachments[] = array(
				'name' => $attachment['FILE_NAME'],
				'size' => $fileSize
			);

			continue;
		}

		if ($attachment['FILE_ID'] && empty($attachment['FILE_DATA']))
			$attachment['FILE_DATA'] = \CMailAttachment::getContents($attachment);

		$filesData[] = array(
			'name'      => $attachment['FILE_NAME'],
			'type'      => $attachment['CONTENT_TYPE'],
			'content'   => $attachment['FILE_DATA'],
			'MODULE_ID' => 'crm',
			'attachment_id' => $attachment['ID'],
		);
	}

	$eventBindings = array();
	foreach ($emailFacility->getBindings() as $item)
	{
		$eventBindings[] = array(
			'USER_ID'     => $userId,
			'ENTITY_TYPE' => \CCrmOwnerType::resolveName($item['OWNER_TYPE_ID']),
			'ENTITY_ID'   => $item['OWNER_ID'],
		);
	}

	$eventText  = ''.getMessage('CRM_EMAIL_SUBJECT').': '.$subject.PHP_EOL;
	$eventText .= ''.getMessage('CRM_EMAIL_FROM').': '.join(', ', $sender).PHP_EOL;
	$eventText .= ''.getMessage('CRM_EMAIL_TO').': '.join(', ', $rcpt).PHP_EOL;

	if (!empty($bannedAttachments))
	{
		$eventText .= ''.getMessage('CRM_EMAIL_BANNENED_ATTACHMENTS', array('%MAX_SIZE%' => $attachmentMaxSizeMb)).': ';
		foreach ($bannedAttachments as $attachmentInfo)
		{
			$eventText .= getMessage(
				'CRM_EMAIL_BANNENED_ATTACHMENT_INFO',
				array(
					'%NAME%' => $attachmentInfo['name'],
					'%SIZE%' => round($attachmentInfo['size']/1024/1024, 1)
				)
			);
		}

		$eventText .= PHP_EOL;
	}

	$eventText .= preg_replace('/(\r\n|\n|\r)+/', PHP_EOL, htmlspecialcharsbx($body));

	$crmEvent = new \CCrmEvent();
	$crmEvent->add(
		array(
			'USER_ID'      => $mailbox['USER_ID'],
			'ENTITY'       => $eventBindings,
			'ENTITY_TYPE'  => \CCrmOwnerType::resolveName($ownerTypeId),
			'ENTITY_ID'    => $ownerId,
			'EVENT_NAME'   => getMessage('CRM_EMAIL_GET_EMAIL'),
			'EVENT_TYPE'   => 2,
			'EVENT_TEXT_1' => $eventText,
			'FILES'        => $filesData,
		),
		false
	);

	$storageTypeId = \CCrmActivity::getDefaultStorageTypeID();
	$elementIds = array();
	foreach ($filesData as $i => $fileData)
	{
		$fileId = \CFile::saveFile($fileData, 'crm', true);
		if (!($fileId > 0))
			continue;

		$fileData = \CFile::getFileArray($fileId);
		if (empty($fileData))
			continue;

		if (trim($fileData['ORIGINAL_NAME']) == '')
			$fileData['ORIGINAL_NAME'] = $fileData['FILE_NAME'];
		$elementId = StorageManager::saveEmailAttachment(
			$fileData, $storageTypeId, '',
			array('USER_ID' => $userId)
		);
		if ($elementId > 0)
		{
			$elementIds[] = (int) $elementId;
			$filesData[$i]['element_id'] = (int) $elementId;
		}
	}

	if (!empty($body_html))
	{
		$checkInlineFiles = true;
		$descr = $body_html;
	}
	else if (!empty($body_bb))
	{
		$bbCodeParser = new \CTextParser();
		$descr = $bbCodeParser->convertText($body_bb);

		foreach ($filesData as $item)
		{
			$descr = preg_replace(
				sprintf('/\[ATTACHMENT=attachment_%u\]/is', $item['attachment_id']),
				sprintf('', $item['attachment_id']),
				$descr, -1, $count
			);

			if ($count > 0)
				$checkInlineFiles = true;
		}
	}
	else
	{
		$descr = preg_replace('/\r\n|\n|\r/', '
', htmlspecialcharsbx($body)); } $isIncomingChannel = false; if ($isIncome) { $direction = \CCrmActivityDirection::Incoming; $completed = $isUnseen ? 'N' : 'Y'; $isIncomingChannel = \Bitrix\Crm\Settings\Crm::isUniversalActivityScenarioEnabled(); } else { $direction = \CCrmActivityDirection::Outgoing; $completed = 'Y'; } $currentUserOffset = \CTimeZone::getOffset(); $userOffset = \CTimeZone::getOffset($userId); $nowTimestamp = time(); $siteId = \Bitrix\Crm\Integration\Main\Site::getPortalSiteId(); $datetime = convertTimeStamp($nowTimestamp + $currentUserOffset, 'FULL', $siteId); if (!empty($msgFields['FIELD_DATE']) && $DB->isDate($msgFields['FIELD_DATE'], FORMAT_DATETIME)) { $datetime = $msgFields['FIELD_DATE']; } $deadlineTimestamp = strtotime('tomorrow') + $currentUserOffset - $userOffset; $deadline = convertTimeStamp($deadlineTimestamp, 'FULL', $siteId); if (CModule::includeModule('calendar')) { $calendarSettings = \CCalendar::getSettings(); $workTimeEndHour = $calendarSettings['work_time_end'] > 0 ? $calendarSettings['work_time_end'] : 19; $dummyDeadline = new \Bitrix\Main\Type\DateTime(); $dummyDeadline->setTime( $workTimeEndHour, 0, $currentUserOffset - $userOffset ); $deadlineTimestamp += $workTimeEndHour * 60 * 60; // work time end in tomorrow $deadline = convertTimeStamp($deadlineTimestamp, 'FULL', $siteId); if ($dummyDeadline->getTimestamp() > $nowTimestamp + $currentUserOffset) { $deadline = $dummyDeadline->format(\Bitrix\Main\Type\DateTime::convertFormatToPhp(FORMAT_DATETIME)); } } $activityFields = array( 'OWNER_ID' => $ownerId, 'OWNER_TYPE_ID' => $ownerTypeId, 'BINDINGS' => $emailFacility->getBindings(), 'TYPE_ID' => \CCrmActivityType::Email, 'ASSOCIATED_ENTITY_ID' => 0, 'PARENT_ID' => $parentId, 'SUBJECT' => \Bitrix\Main\Text\Emoji::encode($subject), 'START_TIME' => (string) $datetime, 'END_TIME' => (string) $deadline, 'COMPLETED' => $completed, 'AUTHOR_ID' => $mailbox['USER_ID'], 'RESPONSIBLE_ID' => $userId, 'EDITOR_ID' => $userId, 'PRIORITY' => \CCrmActivityPriority::Medium, 'DESCRIPTION' => \Bitrix\Main\Text\Emoji::encode($descr), 'DESCRIPTION_TYPE' => \CCrmContentType::Html, 'DIRECTION' => $direction, 'LOCATION' => '', 'NOTIFY_TYPE' => \CCrmActivityNotifyType::None, 'STORAGE_TYPE_ID' => $storageTypeId, 'STORAGE_ELEMENT_IDS' => $elementIds, 'SETTINGS' => array( 'EMAIL_META' => array( '__email' => $mailbox['__email'], 'from' => $from, 'replyTo' => $replyTo, 'to' => $to, 'cc' => $cc, 'bcc' => $bcc, ), ), 'UF_MAIL_MESSAGE' => $messageId, 'IS_INCOMING_CHANNEL' => $isIncomingChannel ? 'Y' : 'N', ); if (!empty($isIncome ? $sender : $rcpt)) { $subfilter = array( 'LOGIC' => 'OR', ); foreach ($activityFields['BINDINGS'] as $item) { $subfilter[] = array( '=ENTITY_ID' => \CCrmOwnerType::resolveName($item['OWNER_TYPE_ID']), '=ELEMENT_ID' => $item['OWNER_ID'], ); } $res = \Bitrix\Crm\FieldMultiTable::getList(array( 'select' => array('ENTITY_ID', 'ELEMENT_ID', 'VALUE'), 'group' => array('ENTITY_ID', 'ELEMENT_ID', 'VALUE'), 'filter' => array( $subfilter, '=TYPE_ID' => 'EMAIL', '@VALUE' => $isIncome ? $sender : $rcpt, ), )); while ($item = $res->fetch()) { $activityFields['COMMUNICATIONS'][] = array( 'ENTITY_TYPE_ID' => \CCrmOwnerType::resolveId($item['ENTITY_ID']), 'ENTITY_ID' => $item['ELEMENT_ID'], 'VALUE' => $item['VALUE'], 'TYPE' => 'EMAIL', ); } } $activityId = \CCrmActivity::add($activityFields, false, false, array('REGISTER_SONET_EVENT' => true)); if ($activityId > 0) { static::log( $eventTag, 'CCrmEmail: created activity', array( 'ID' => $activityId, 'OWNER_ID' => $ownerId, 'OWNER_TYPE_ID' => $ownerTypeId, 'RESPONSIBLE_ID' => $userId, ) ); if (!empty($checkInlineFiles)) { foreach ($filesData as $item) { $info = \Bitrix\Crm\Integration\DiskManager::getFileInfo( $item['element_id'], false, array('OWNER_TYPE_ID' => \CCrmOwnerType::Activity, 'OWNER_ID' => $activityId) ); $descr = preg_replace( sprintf('/]+)src\s*=\s*(\'|\")?\s*(aid:%u)\s*\2([^>]*)>/is', $item['attachment_id']), sprintf('', $info['VIEW_URL']), $descr, -1, $count ); if ($count > 0) $descrUpdated = true; } if (!empty($descrUpdated)) { \CCrmActivity::update($activityId, array( 'DESCRIPTION' => $descr, ), false, false); } } \Bitrix\Crm\Activity\MailMetaTable::add(array( 'ACTIVITY_ID' => $activityId, 'MSG_ID_HASH' => !empty($msgId) ? md5(mb_strtolower($msgId)) : '', 'MSG_INREPLY_HASH' => !empty($inReplyTo) ? md5(mb_strtolower($inReplyTo)) : '', 'MSG_HEADER_HASH' => $msgFields['MSG_HASH'], )); $res = \Bitrix\Crm\Activity\MailMetaTable::getList(array( 'select' => array('ACTIVITY_ID'), 'filter' => array( '=MSG_INREPLY_HASH' => md5(mb_strtolower($msgId)), ), )); while ($mailMeta = $res->fetch()) { \CCrmActivity::update($mailMeta['ACTIVITY_ID'], array( 'PARENT_ID' => $activityId, ), false, false); } if ($isIncome) { \Bitrix\Crm\Automation\Trigger\EmailTrigger::execute($activityFields['BINDINGS'], $activityFields); } Channel\EmailTracker::getInstance()->registerActivity($activityId, array('ORIGIN_ID' => sprintf('%u|%u', $mailbox['USER_ID'], $mailbox['ID']))); } //Notify the responsible user if a message has been added from ajax sync to CRM if ($userId > 0 && $isIncome && $completed != 'Y') { \CCrmActivity::notify( $activityFields, \CCrmNotifierSchemeType::IncomingEmail, sprintf('crm_email_%u_%u', $activityFields['OWNER_TYPE_ID'], $activityFields['OWNER_ID']), $isForced, [], ); } return true; }