• Модуль: crm
  • Путь к файлу: ~/bitrix/modules/crm/lib/integration/mailmanager.php
  • Класс: Bitrix\Crm\Integration\MailManager
  • Вызов: MailManager::sendMessage
static function sendMessage(array $messageFields)
{
	$options = $messageFields['OPTIONS'] ?? null;
	$commonOptions = $messageFields['COMMON'] ?? null;
	if (!is_array($options) || !is_array($commonOptions))
	{
		return false;
	}

	$userId = $commonOptions['USER_ID'] ?? null;

	if (!self::canSendMessage($userId))
	{
		return false;
	}

	$fromMailboxId = (int)($options['MAILBOX_ID'] ?? 0);
	if ($fromMailboxId <= 0)
	{
		return false;
	}

	if (!\Bitrix\Mail\Helper\LicenseManager::checkTheMailboxForSyncAvailability($fromMailboxId))
	{
		return (new Result())->addError(
			new Error(
				Loc::getMessage('CRM_INTEGRATION_MAIL_MANAGER_ERROR_FROM_MAILBOX_RESTRICTED'),
				Channel\ErrorCode::NOT_AVAILABLE,
			),
		);
	}

	[$entityTypeId, $entityId] = self::resolveItem($commonOptions);

	$now = new DateTime();

	$subject = Loc::getMessage('CRM_INTEGRATION_MAIL_MANAGER_EMPTY_SUBJECT_PLACEHOLDER', ['#DATE#' => $now]);
	if (!empty($options['MESSAGE_SUBJECT']))
	{
		$subject = $options['MESSAGE_SUBJECT'];
	}

	$body = (string)($options['MESSAGE_BODY'] ?? '');

	$bodyContentType = (int)($options['MESSAGE_BODY_CONTENT_TYPE'] ?? \CCrmContentType::Html);
	$bodyContentType = \CCrmContentType::IsDefined($bodyContentType) ? $bodyContentType : \CCrmContentType::Html;

	if (!empty($body))
	{
		\CCrmActivity::AddEmailSignature($body, $bodyContentType);
	}

	if ($bodyContentType === \CCrmContentType::Html)
	{
		$activityDescription = preg_replace('/]*>.*?<\/script>/is', '', $body);
		$activityDescription = preg_replace('/]*>.*?<\/title>/is', '', $activityDescription);

		$sanitizer = new \CBXSanitizer();
		$sanitizer->setLevel(\CBXSanitizer::SECURE_LEVEL_LOW);
		$sanitizer->applyDoubleEncode(false);
		$sanitizer->addTags(['style' => []]);
		$activityDescription = $sanitizer->SanitizeHtml($activityDescription);
	}
	else
	{
		$activityDescription = $body;
	}

	$addressSource = $commonOptions['ADDITIONAL_FIELDS']['ADDRESS_SOURCE'] ?? null;
	if (!is_array($addressSource))
	{
		$addressSource = [];
	}

	$bindings = $commonOptions['ADDITIONAL_FIELDS']['BINDINGS'] ?? null;
	if (!is_array($bindings))
	{
		$bindings = [];
	}

	$toEmail = (string)($commonOptions['EMAIL'] ?? '');
	if (!check_email($toEmail))
	{
		return (new Result())->addError(
			new Error(Loc::getMessage('CRM_INTEGRATION_MAIL_MANAGER_ERROR_INVALID_TO_EMAIL', ['#EMAIL#' => $toEmail])),
		);
	}

	if (self::isReceiverBlacklisted($toEmail))
	{
		return (new Result())->addError(
			new Error(Loc::getMessage('CRM_INTEGRATION_MAIL_MANAGER_ERROR_TO_BLACKLISTED', ['#EMAIL#' => $toEmail])),
		);
	}

	$mailboxHelper = \Bitrix\Mail\Helper\Mailbox::createInstance($fromMailboxId, false) ?: null;
	$activityFields = [
		'AUTHOR_ID' => $mailboxHelper?->getMailboxOwnerId() ?: $userId,
		'OWNER_TYPE_ID' => $entityTypeId,
		'OWNER_ID' => $entityId,
		'TYPE_ID' => \CCrmActivityType::Email,
		'SUBJECT' => $subject,
		'START_TIME' => (string)$now,
		'END_TIME' => (string)$now,
		'COMPLETED' => 'Y',
		'RESPONSIBLE_ID' => $userId,
		'PRIORITY' => \CCrmActivityPriority::Medium,
		'DESCRIPTION' => $activityDescription,
		'DESCRIPTION_TYPE' => $bodyContentType,
		'DIRECTION' => \CCrmActivityDirection::Outgoing,
		'BINDINGS' => $bindings,
		'COMMUNICATIONS' => [
			[
				'TYPE' => Multifield\Type\Email::ID,
				'VALUE' => $toEmail,
			] + $addressSource
		],
	];

	$attachments = [];
	$attachmentsStorageTypeId = StorageType::Undefined;

	if (
		!empty($options['ATTACHMENTS_IDS'])
		&& is_array($options['ATTACHMENTS_IDS'])
		&& isset($options['ATTACHMENTS_STORAGE_TYPE_ID'])
		&& $options['ATTACHMENTS_STORAGE_TYPE_ID'] === StorageType::File
	)
	{
		$attachmentsStorageTypeId = $options['ATTACHMENTS_STORAGE_TYPE_ID'];

		foreach ($options['ATTACHMENTS_IDS'] as $bFileId)
		{
			$file = \CFile::MakeFileArray($bFileId);
			if (is_array($file))
			{
				// each db row should reference its own b_file row. create new rows with same files for the activity
				$newBFileId = (int)\CFile::SaveFile($file, 'crm');
				if ($newBFileId > 0)
				{
					$attachments[] = $newBFileId;
				}
			}
		}
	}

	if (!empty($attachments) && StorageType::isDefined($attachmentsStorageTypeId))
	{
		$sizeCheckResult = self::checkAttachmentsFileSize($attachmentsStorageTypeId, $attachments);
		if (!$sizeCheckResult->isSuccess())
		{
			return $sizeCheckResult;
		}

		$activityFields['STORAGE_TYPE_ID'] = $attachmentsStorageTypeId;
		$activityFields['STORAGE_ELEMENT_IDS'] = $attachments;
	}

	\Bitrix\Crm\Activity\Provider\Email::compressActivity($activityFields);

	$activityId = (int)\CCrmActivity::Add(
		$activityFields,
		false,
		false,
		['REGISTER_SONET_EVENT' => true],
	);
	if ($activityId <= 0)
	{
		self::deleteFilesFromActivity($activityFields);

		$result =
			(new Result())
				->addError(new Error('Could not create an activity'))
		;

		foreach (\CCrmActivity::GetErrorMessages() as $errorMessage)
		{
			$result->addError(new Error($errorMessage));
		}

		return $result;
	}

	$urn = \CCrmActivity::PrepareUrn($activityFields);
	$messageId = self::compileMessageId($urn);

	$fromAddress = new \Bitrix\Main\Mail\Address($options['MESSAGE_FROM'] ?? null);

	$replyTo = self::compileReplyTo($fromAddress->getEmail());

	\CCrmActivity::Update(
		$activityId,
		[
			'URN' => $urn,
			'SETTINGS' => [
				'IS_BATCH_EMAIL' => self::isTrackOutgoingEmailsReadEnabled() ? false : null,
				'MESSAGE_HEADERS' => [
					'Message-Id' => $messageId,
					'Reply-To' => $replyTo ?: $fromAddress->get(),
				],
				'EMAIL_META' => [
					'__email' => $fromAddress->getEmail(),
					'from' => $fromAddress->get(),
					'replyTo' => $replyTo,
					'to' => $toEmail,
				],
			],
		],
		false,
		false,
		['REGISTER_SONET_EVENT' => true]
	);

	$bodyHtml = '';
	if ($body && $bodyContentType === \CCrmContentType::BBCode)
	{
		$bodyHtml = TextHelper::convertBbCodeToHtml($body);
	}
	elseif ($body)
	{
		$bodyHtml = $body;
	}

	if (
		($bodyContentType === \CCrmContentType::BBCode || $bodyContentType === \CCrmContentType::Html)
		&& mb_strpos($bodyHtml, '') === false
	)
	{
		/** @noinspection HtmlRequiredLangAttribute */
		$bodyHtml = '' . $bodyHtml . '';
	}


	$outgoingSubject = $subject;

	$fromMailbox = current(array_filter(
		\Bitrix\Mail\MailboxTable::getUserMailboxes($userId),
		fn(array $mailbox) => $mailbox['EMAIL'] === $fromAddress->getEmail(),
	));

	$outgoingBody = $bodyHtml;

	$shouldInjectUrn = empty($fromMailbox);

	if ($shouldInjectUrn)
	{
		switch (\CCrmEMailCodeAllocation::getCurrent())
		{
			case \CCrmEMailCodeAllocation::Subject:
				$outgoingSubject = \CCrmActivity::injectUrnInSubject($urn, $outgoingSubject);
				break;
			case \CCrmEMailCodeAllocation::Body:
				$outgoingBody = \CCrmActivity::injectUrnInBody($urn, $outgoingBody);
				break;
		}
	}

	$emailAttachments = [];
	$attachmentsFileArrays = [];
	if (!empty($attachments) && StorageType::isDefined($attachmentsStorageTypeId))
	{
		$attachmentsFileArrays = StorageManager::makeFileArray($attachments, $attachmentsStorageTypeId);
		foreach ($attachmentsFileArrays as $fileArray)
		{
			$emailAttachments[] = [
				'ID' => $fileArray['external_id'],
				'NAME' => empty($fileArray['ORIGINAL_NAME']) ? $fileArray['name'] : $fileArray['ORIGINAL_NAME'],
				'PATH' => $fileArray['tmp_name'],
				'CONTENT_TYPE' => $fileArray['type'],
			];
		}
	}

	$fields = [
		'CHARSET' => SITE_CHARSET,
		'CONTENT_TYPE' => 'html',
		'ATTACHMENT' => $emailAttachments,
		'TO' => \Bitrix\Main\Mail\Mail::encodeHeaderFrom($toEmail, SITE_CHARSET),
		'SUBJECT' => $outgoingSubject,
		'BODY' => $outgoingBody ?: Loc::getMessage('CRM_INTEGRATION_MAIL_MANAGER_EMPTY_BODY_PLACEHOLDER'),
		'HEADER' => [
			'From' => $fromAddress->getEncoded() ?: $fromAddress->getEmail(),
			'Reply-To' => $replyTo,
			'Message-Id' => $messageId,
		],
		'TRACK_READ' => [
			'MODULE_ID' => 'crm',
			'FIELDS' => ['urn' => $urn],
			'URL_PAGE' => '/pub/mail/read.php',
		],
		'TRACK_CLICK' => [
			'MODULE_ID' => 'crm',
			'FIELDS' => ['urn' => $urn],
			'URL_PAGE' => '/pub/mail/click.php',
			'URL_PARAMS' => [],
		],
		'CONTEXT' =>
			(new \Bitrix\Main\Mail\Context())
				->setCategory(\Bitrix\Main\Mail\Context::CAT_EXTERNAL)
				->setPriority(\Bitrix\Main\Mail\Context::PRIORITY_LOW)
				->setCallback(
					(new \Bitrix\Main\Mail\Callback\Config())
						->setModuleId('crm')
						->setEntityType(self::CALLBACK_ENTITY_TYPE)
						->setEntityId($urn)
				)
		,
	];

	if (\Bitrix\Crm\WebForm\Manager::isEmbeddingAvailable())
	{
		$fields['TRACK_CLICK']['URL_PARAMS'][\Bitrix\Crm\WebForm\Embed\Sign::uriParameterName] =
			(new \Bitrix\Crm\WebForm\Embed\Sign())
				->addEntity($entityTypeId, $entityId)
				->pack()
		;
	}

	$isSuccess = \Bitrix\Main\Mail\Mail::send($fields);
	if (!$isSuccess)
	{
		\CCrmActivity::Delete($activityId);

		return self::tryGetResultWithSendFailReason();
	}

	addEventToStatFile(
		'crm',
		'send_email_message',
		'mail_manager',
		trim(trim($messageId), '<>')
	);

	if (is_array($fromMailbox))
	{
		\Bitrix\Mail\Helper::addImapMessage(
			$fromMailbox,
			(string)(new \Bitrix\Mail\DummyMail(array_merge(
				$fields,
				[
					'HEADER' => array_merge(
						$fields['HEADER'],
						[
							'To' => $fields['TO'],
							'Subject' => $fields['SUBJECT'],
						]
					),
				]
			))),
			$errorThatWeDontCareAbout,
		);
	}

	$eventBindings = array_map(
		fn(array $singleBinding) => [
			'ENTITY_TYPE' => \CCrmOwnerType::ResolveName($singleBinding['OWNER_TYPE_ID']),
			'ENTITY_ID' => $singleBinding['OWNER_ID'],
		],
		$bindings,
	);

	(new \CCrmEvent())->Add([
		'ENTITY' => array_unique($eventBindings, SORT_REGULAR),
		'EVENT_ID' => 'MESSAGE',
		'EVENT_TEXT_1' => str_replace(
			'
', "\r\n", Loc::getMessage( 'CRM_INTEGRATION_MAIL_MANAGER_HISTORY_EVENT_TEXT', [ '#SUBJECT#' => $subject, '#FROM#' => $fromAddress->getEmail(), '#TO#' => $toEmail, '#MESSAGE_BODY#' => $bodyHtml, ] ) ), 'FILES' => $attachmentsFileArrays, ]); return new Result(); }