Пример #1
0
 /**
  * @param Entity\Event $event
  * @return Entity\EventResult
  */
 public static function onAfterDelete(Entity\Event $event)
 {
     $result = new Entity\EventResult();
     $data = $event->getParameters();
     $primary = array('MAILING_ID' => $data['primary']['ID']);
     MailingGroupTable::delete($primary);
     MailingChainTable::delete($primary);
     PostingTable::delete($primary);
     return $result;
 }
Пример #2
0
 /**
  * Handler of before delete event
  * @param Entity\Event $event
  * @return Entity\EventResult
  */
 public static function onBeforeDelete(Entity\Event $event)
 {
     $result = new Entity\EventResult();
     $data = $event->getParameters();
     $chainListDb = MailingChainTable::getList(array('select' => array('ID', 'SUBJECT', 'MAILING_ID', 'MAILING_NAME' => 'MAILING.NAME'), 'filter' => array('TEMPLATE_TYPE' => 'USER', 'TEMPLATE_ID' => $data['primary']['ID']), 'order' => array('MAILING_NAME' => 'ASC', 'ID')));
     if ($chainListDb->getSelectedRowsCount() > 0) {
         $template = static::getRowById($data['primary']['ID']);
         $messageList = array();
         while ($chain = $chainListDb->fetch()) {
             $messageList[$chain['MAILING_NAME']] = '[' . $chain['ID'] . '] ' . htmlspecialcharsbx($chain['SUBJECT']) . "\n";
         }
         $message = Loc::getMessage('SENDER_ENTITY_TEMPLATE_DELETE_ERROR_TEMPLATE', array('#NAME#' => $template['NAME'])) . "\n";
         foreach ($messageList as $mailingName => $messageItem) {
             $message .= Loc::getMessage('SENDER_ENTITY_TEMPLATE_DELETE_ERROR_MAILING', array('#NAME#' => $mailingName)) . "\n" . $messageItem . "\n";
         }
         $result->addError(new Entity\EntityError($message));
     }
     return $result;
 }
Пример #3
0
?>
		</td>
	</tr>

	<?php 
if ($MAILING_ID > 0) {
    ?>
	<tr>
		<td><?php 
    echo GetMessage("sender_stat_flt_mailing_chain");
    ?>
:</td>
		<td valign="middle">
			<?php 
    $arr = array();
    $mailingChainDb = \Bitrix\Sender\MailingChainTable::getList(array('select' => array('REFERENCE' => 'SUBJECT', 'REFERENCE_ID' => 'ID'), 'filter' => array('MAILING_ID' => $MAILING_ID)));
    while ($arMailingChain = $mailingChainDb->fetch()) {
        $arr['reference'][] = $arMailingChain['REFERENCE'];
        $arr['reference_id'][] = $arMailingChain['REFERENCE_ID'];
    }
    echo SelectBoxFromArray("find_mailing_chain_id", $arr, $ID, false, "");
    ?>
		</td>
	</tr>
	<?php 
}
$oFilter->Buttons(array("table_id" => $sTableID, "url" => $APPLICATION->GetCurPage(), "form" => "find_form"));
$oFilter->End();
?>
</form>
Пример #4
0
	</td>
</tr>
<?php 
$oFilter->Buttons(array("table_id" => $sTableID, "url" => $APPLICATION->GetCurPage() . "?MAILING_ID=" . $MAILING_ID, "form" => "find_form"));
$oFilter->End();
?>
</form>

<?php 
//******************************
// Send mailing and show progress
//******************************
if ($_REQUEST['action'] == "send") {
    $canSend = \Bitrix\Sender\MailingChainTable::isReadyToSend($ID);
    if (!$canSend) {
        $canSend = \Bitrix\Sender\MailingChainTable::isManualSentPartly($ID);
    }
    if ($canSend) {
        ?>
		<div id="progress_message"></div>
		<script>
			var stop = false;
			function Stop()
			{
				stop=true;
				document.getElementById('btn_stop').disabled = true;
				document.getElementById('btn_cont').disabled = false;
			}
			function Cont()
			{
				stop=false;
Пример #5
0
				<td>
					<input type="text" id="EMAIL_FROM" name="EMAIL_FROM" value="<?php 
    echo $str_EMAIL_FROM;
    ?>
">
				</td>
			</tr>

			<tr class="hidden-when-show-template-list" <?php 
    echo empty($str_MESSAGE) ? 'style="display: none;"' : '';
    ?>
>
				<td>&nbsp;</td>
				<td>
					<?php 
    $arEmailFromList = \Bitrix\Sender\MailingChainTable::getEmailFromList();
    ?>
					<?php 
    echo GetMessage("sender_chain_edit_field_email_from_last");
    ?>
					<?php 
    foreach ($arEmailFromList as $email) {
        ?>
					<a class="sender-link-email" onclick="SetAddressToControl('EMAIL_FROM', '<?php 
        echo CUtil::AddSlashes(htmlspecialcharsbx($email));
        ?>
')">
						<?php 
        echo htmlspecialcharsbx($email);
        ?>
						</a><?php 
Пример #6
0
 /**
  * @param $mailingChainId
  * @param $address
  * @return bool
  * @throws \Bitrix\Main\DB\Exception
  */
 public static function sendToAddress($mailingChainId, $address)
 {
     $recipientEmail = $address;
     $emailParts = explode('@', $recipientEmail);
     $recipientName = $emailParts[0];
     global $USER;
     $mailingChain = MailingChainTable::getRowById(array('ID' => $mailingChainId));
     $sendParams = array('FIELDS' => array('NAME' => $recipientName, 'EMAIL_TO' => $address, 'USER_ID' => $USER->GetID(), 'SENDER_CHAIN_CODE' => 'sender_chain_item_' . $mailingChain["ID"], 'UNSUBSCRIBE_LINK' => Subscription::getLinkUnsub(array('MAILING_ID' => !empty($mailingChain) ? $mailingChain['MAILING_ID'] : 0, 'EMAIL' => $address, 'TEST' => 'Y'))), 'TRACK_READ' => array('MODULE_ID' => "sender", 'FIELDS' => array('RECIPIENT_ID' => 0)), 'TRACK_CLICK' => array('MODULE_ID' => "sender", 'FIELDS' => array('RECIPIENT_ID' => 0), 'URL_PARAMS' => array('bx_sender_conversion_id' => 0)));
     $mailSendResult = static::sendInternal($mailingChainId, $sendParams);
     switch ($mailSendResult) {
         case PostingRecipientTable::SEND_RESULT_SUCCESS:
             $mailResult = static::SEND_RESULT_SENT;
             break;
         case PostingRecipientTable::SEND_RESULT_ERROR:
         default:
             $mailResult = static::SEND_RESULT_ERROR;
     }
     return $mailResult;
 }
Пример #7
0
 public static function actualizeHandlers($chainId, array $fieldsNew = null, array $fieldsOld = null)
 {
     $settingsNew = null;
     $settingsOld = null;
     if ($fieldsNew) {
         $settingsNew = new TriggerSettings($fieldsNew);
     }
     if ($fieldsOld) {
         $settingsOld = new TriggerSettings($fieldsOld);
     }
     // if old item was closed trigger
     if ($settingsOld && $settingsOld->isClosedTrigger()) {
         // delete agent
         $agentName = TriggerManager::getClosedEventAgentName($settingsOld->getEventModuleId(), $settingsOld->getEventType(), $chainId);
         $agent = new \CAgent();
         $agentListDb = $agent->GetList(array(), array('MODULE_ID' => 'sender', 'NAME' => $agentName));
         while ($agentItem = $agentListDb->Fetch()) {
             $agent->Delete($agentItem['ID']);
         }
     }
     // if new item is closed trigger
     if ($settingsNew && $settingsNew->isClosedTrigger()) {
         // check active state of mailing
         $chainDb = MailingChainTable::getList(array('select' => array('ID'), 'filter' => array('=ID' => $chainId, '=MAILING.ACTIVE' => 'Y')));
         if (!$chainDb->fetch()) {
             return;
         }
         // add new agent
         $agentName = TriggerManager::getClosedEventAgentName($settingsNew->getEventModuleId(), $settingsNew->getEventType(), $chainId);
         // set date of next exec
         $agentTime = $settingsNew->getClosedTriggerTime();
         $agentInterval = $settingsNew->getClosedTriggerInterval();
         if ($agentInterval <= 0) {
             $agentInterval = 1440;
         }
         $agentTimeArray = explode(":", $agentTime);
         $agentDate = new \Bitrix\Main\Type\DateTime();
         $agentDate->setTime((int) $agentTimeArray[0], (int) $agentTimeArray[1]);
         // set next exec on next day if exec was today
         if ($agentDate->getTimestamp() < time()) {
             $agentDate->add("1 days");
         }
         // add agent
         $agent = new \CAgent();
         $agent->AddAgent($agentName, 'sender', 'N', $agentInterval * 60, '', 'Y', $agentDate->toString());
         return;
     }
     // actualize deleted/changed event
     if ($settingsOld && !$settingsOld->isClosedTrigger() && $settingsOld->getFullEventType()) {
         // if delete operation(no the NEW)
         // or change operation(the NEW is not equal to the OLD)
         if (!$settingsNew || $settingsOld->getFullEventType() != $settingsNew->getFullEventType()) {
             TriggerManager::actualizeHandler(array('MODULE_ID' => $settingsOld->getEventModuleId(), 'EVENT_TYPE' => $settingsOld->getEventType(), 'CALLED_BEFORE_CHANGE' => true));
         }
     }
     // actualize new event
     if ($settingsNew && $settingsNew->getFullEventType()) {
         $calledBeforeChange = $fieldsOld ? false : true;
         TriggerManager::actualizeHandler(array('MODULE_ID' => $settingsNew->getEventModuleId(), 'EVENT_TYPE' => $settingsNew->getEventType(), 'CALLED_BEFORE_CHANGE' => $calledBeforeChange));
     }
 }
Пример #8
0
 /**
  * @return string
  * @throws \Bitrix\Main\ArgumentException
  */
 public static function checkPeriod($isAgentExec = true)
 {
     $isAgentExecInSetting = \COption::GetOptionString("sender", "reiterate_method") !== 'cron';
     if ($isAgentExec && !$isAgentExecInSetting || !$isAgentExec && $isAgentExecInSetting) {
         return "";
     }
     $dateTodayPhp = new \DateTime();
     $datetimeToday = Type\DateTime::createFromPhp(clone $dateTodayPhp);
     $dateToday = clone $dateTodayPhp;
     $dateToday = Type\Date::createFromPhp($dateToday->setTime(0, 0, 0));
     $dateTomorrow = clone $dateTodayPhp;
     $dateTomorrow = Type\Date::createFromPhp($dateTomorrow->setTime(0, 0, 0))->add('1 DAY');
     $arDateFilter = array($dateToday, $dateTomorrow);
     $chainDb = MailingChainTable::getList(array('select' => array('ID', 'LAST_EXECUTED', 'POSTING_ID', 'DAYS_OF_MONTH', 'DAYS_OF_WEEK', 'TIMES_OF_DAY'), 'filter' => array('=REITERATE' => 'Y', '=MAILING.ACTIVE' => 'Y', 'STATUS' => MailingChainTable::STATUS_WAIT)));
     while ($arMailingChain = $chainDb->fetch()) {
         $lastExecuted = $arMailingChain['LAST_EXECUTED'];
         /* @var \Bitrix\Main\Type\DateTime $lastExecuted*/
         if ($lastExecuted && $lastExecuted->getTimestamp() >= $dateToday->getTimestamp()) {
             continue;
         }
         $timeOfExecute = static::getDateExecute($dateTodayPhp, $arMailingChain["DAYS_OF_MONTH"], $arMailingChain["DAYS_OF_WEEK"], $arMailingChain["TIMES_OF_DAY"]);
         if ($timeOfExecute) {
             $arUpdateMailChain = array('LAST_EXECUTED' => $datetimeToday);
             $postingDb = PostingTable::getList(array('select' => array('ID'), 'filter' => array('=MAILING_CHAIN_ID' => $arMailingChain['ID'], '><DATE_CREATE' => $arDateFilter)));
             $arPosting = $postingDb->fetch();
             if (!$arPosting) {
                 $postingId = MailingChainTable::initPosting($arMailingChain['ID']);
             } else {
                 $postingId = $arPosting['ID'];
                 $arUpdateMailChain['POSTING_ID'] = $postingId;
                 PostingTable::initGroupRecipients($postingId);
             }
             if ($postingId) {
                 $arUpdateMailChain['STATUS'] = MailingChainTable::STATUS_SEND;
                 $arUpdateMailChain['AUTO_SEND_TIME'] = Type\DateTime::createFromPhp($timeOfExecute);
             }
             MailingChainTable::update(array('ID' => $arMailingChain['ID']), $arUpdateMailChain);
         }
     }
     return static::getAgentNamePeriod();
 }
Пример #9
0
 public static function updateChainTrigger($id)
 {
     // get first item of chain
     $chainDb = MailingChainTable::getList(array('select' => array('ID', 'TRIGGER_FIELDS' => 'MAILING.TRIGGER_FIELDS'), 'filter' => array('=MAILING_ID' => $id, '=IS_TRIGGER' => 'Y', '=PARENT_ID' => null)));
     $chain = $chainDb->fetch();
     if (!$chain) {
         return;
     }
     $chainId = $chain['ID'];
     // get trigger settings from mailing
     $triggerFields = $chain['TRIGGER_FIELDS'];
     if (!is_array($triggerFields)) {
         $triggerFields = array();
     }
     // init TriggerSettings objects
     $settingsList = array();
     foreach ($triggerFields as $key => $point) {
         if (empty($point['CODE'])) {
             continue;
         }
         $point['IS_EVENT_OCCUR'] = true;
         $point['IS_PREVENT_EMAIL'] = false;
         $point['SEND_INTERVAL_UNIT'] = 'M';
         $point['IS_CLOSED_TRIGGER'] = $point['IS_CLOSED_TRIGGER'] == 'Y' ? true : false;
         switch ($key) {
             case 'END':
                 $point['IS_TYPE_START'] = false;
                 break;
             case 'START':
             default:
                 $point['IS_TYPE_START'] = true;
         }
         $settingsList[] = new \Bitrix\Sender\TriggerSettings($point);
     }
     // prepare fields for save
     $mailingTriggerList = array();
     foreach ($settingsList as $settings) {
         /* @var \Bitrix\Sender\TriggerSettings $settings */
         $trigger = \Bitrix\Sender\TriggerManager::getOnce($settings->getEndpoint());
         if ($trigger) {
             $triggerFindId = $trigger->getFullEventType() . "/" . (int) $settings->isTypeStart();
             $mailingTriggerList[$triggerFindId] = array('IS_TYPE_START' => $settings->isTypeStart(), 'NAME' => $trigger->getName(), 'EVENT' => $trigger->getFullEventType(), 'ENDPOINT' => $settings->getArray());
         }
     }
     // add new, update exists, delete old rows
     $triggerDb = MailingTriggerTable::getList(array('select' => array('EVENT', 'MAILING_CHAIN_ID', 'IS_TYPE_START'), 'filter' => array('=MAILING_CHAIN_ID' => $chainId)));
     while ($trigger = $triggerDb->fetch()) {
         $triggerFindId = $trigger['EVENT'] . "/" . (int) $trigger['IS_TYPE_START'];
         if (!isset($mailingTriggerList[$triggerFindId])) {
             MailingTriggerTable::delete($trigger);
         } else {
             MailingTriggerTable::update($trigger, $mailingTriggerList[$triggerFindId]);
             unset($mailingTriggerList[$triggerFindId]);
         }
     }
     foreach ($mailingTriggerList as $triggerFindId => $settings) {
         $settings['MAILING_CHAIN_ID'] = $chainId;
         MailingTriggerTable::add($settings);
     }
     TriggerManager::actualizeHandlerForChild();
 }
Пример #10
0
 public static function updateChain($id, array $fields)
 {
     $result = new \Bitrix\Main\Entity\Result();
     static::checkFieldsChain($result, $id, $fields);
     if (!$result->isSuccess(true)) {
         return $result;
     }
     $parentChainId = null;
     $existChildIdList = array();
     foreach ($fields as $chainFields) {
         $chainId = $chainFields['ID'];
         unset($chainFields['ID']);
         $chainFields['MAILING_ID'] = $id;
         $chainFields['IS_TRIGGER'] = 'Y';
         $chainFields['REITERATE'] = 'Y';
         $chainFields['PARENT_ID'] = $parentChainId;
         // default status
         if ($chainId > 0) {
             $chain = \Bitrix\Sender\MailingChainTable::getRowById(array('ID' => $chainId));
             if ($chain && $chain['STATUS'] != \Bitrix\Sender\MailingChainTable::STATUS_WAIT) {
                 $chainFields['STATUS'] = $chain['STATUS'];
                 unset($chainFields['CREATED_BY']);
             }
         }
         if (empty($chainFields['STATUS'])) {
             $chainFields['STATUS'] = \Bitrix\Sender\MailingChainTable::STATUS_WAIT;
         }
         // add or update
         if ($chainId > 0) {
             $existChildIdList[] = $chainId;
             $chainUpdateDb = MailingChainTable::update(array('ID' => $chainId), $chainFields);
             if ($chainUpdateDb->isSuccess()) {
             } else {
                 $result->addErrors($chainUpdateDb->getErrors());
             }
         } else {
             $chainAddDb = MailingChainTable::add($chainFields);
             if ($chainAddDb->isSuccess()) {
                 $chainId = $chainAddDb->getId();
                 $existChildIdList[] = $chainId;
             } else {
                 $result->addErrors($chainAddDb->getErrors());
             }
         }
         if (!empty($errorList)) {
             break;
         }
         $parentChainId = null;
         if ($chainId !== null) {
             $parentChainId = $chainId;
         }
     }
     $deleteChainDb = MailingChainTable::getList(array('select' => array('ID'), 'filter' => array('MAILING_ID' => $id, '!ID' => $existChildIdList)));
     while ($deleteChain = $deleteChainDb->fetch()) {
         MailingChainTable::delete(array('ID' => $deleteChain['ID']));
     }
     static::updateChainTrigger($id);
     return $result;
 }
Пример #11
0
 /**
  * @param $mailingChainId
  * @param $address
  * @return bool
  * @throws \Bitrix\Main\DB\Exception
  */
 public static function sendToAddress($mailingChainId, $address)
 {
     $recipientEmail = $address;
     $arEmailParts = explode('@', $recipientEmail);
     $recipientName = $arEmailParts[0];
     $mailingChain = MailingChainTable::getRowById(array('ID' => $mailingChainId));
     $arParams = array('FIELDS' => array('NAME' => $recipientName, 'EMAIL_TO' => $address, 'USER_ID' => '', 'UNSUBSCRIBE_LINK' => Subscription::getLinkUnsub(array('MAILING_ID' => !empty($mailingChain) ? $mailingChain['MAILING_ID'] : 0, 'EMAIL' => $address, 'TEST' => 'Y'))));
     $mailSendResult = static::sendInternal($mailingChainId, $arParams);
     switch ($mailSendResult) {
         case PostingRecipientTable::SEND_RESULT_SUCCESS:
             $mailResult = static::SEND_RESULT_SENT;
             break;
         case PostingRecipientTable::SEND_RESULT_ERROR:
         default:
             $mailResult = static::SEND_RESULT_ERROR;
     }
     return $mailResult;
 }
Пример #12
0
 /**
  * @param \Bitrix\Main\Event $event
  * @return void
  */
 public static function onAfterPostingSendRecipient(\Bitrix\Main\Event $event)
 {
     $data = $event->getParameter(0);
     if (!$data || !$data['SEND_RESULT'] || empty($data['POSTING']['MAILING_CHAIN_ID'])) {
         return;
     }
     $chainId = $data['POSTING']['MAILING_CHAIN_ID'];
     $dataRecipient = $data['RECIPIENT'];
     static $mailingParams = array();
     if (!isset($mailingParams[$chainId])) {
         $mailingParams[$chainId] = array();
         $childChainDb = MailingChainTable::getList(array('select' => array('ID', 'MAILING_ID', 'PARENT_ID', 'POSTING_ID'), 'filter' => array('=MAILING.ACTIVE' => 'Y', '=IS_TRIGGER' => 'Y', '=STATUS' => array(MailingChainTable::STATUS_WAIT, MailingChainTable::STATUS_SEND), '=PARENT_ID' => $chainId)));
         while ($childChain = $childChainDb->fetch()) {
             // add posting
             $postingAddDb = PostingTable::add(array('MAILING_ID' => $childChain['MAILING_ID'], 'MAILING_CHAIN_ID' => $childChain['ID']));
             if (!$postingAddDb->isSuccess()) {
                 continue;
             }
             $mailingParams[$chainId][] = array('POSTING_ID' => $postingAddDb->getId(), 'CHAIN' => $childChain);
         }
     }
     if (empty($mailingParams[$chainId])) {
         return;
     }
     foreach ($mailingParams[$chainId] as $mailingParamsItem) {
         $postingId = $mailingParamsItem['POSTING_ID'];
         $childChain = $mailingParamsItem['CHAIN'];
         // check email as unsubscribed
         if (Subscription::isUnsubscibed($childChain['MAILING_ID'], $data['RECIPIENT']['EMAIL'])) {
             continue;
         }
         $recipient = array('POSTING_ID' => $postingId);
         $recipient['STATUS'] = PostingRecipientTable::SEND_RESULT_NONE;
         $recipient['EMAIL'] = $dataRecipient['EMAIL'];
         if (!empty($dataRecipient['FIELDS'])) {
             $recipient['FIELDS'] = $dataRecipient['FIELDS'];
         }
         if (!empty($dataRecipient['ROOT_ID'])) {
             $recipient['ROOT_ID'] = $dataRecipient['ROOT_ID'];
         } else {
             $recipient['ROOT_ID'] = $dataRecipient['ID'];
         }
         if (!empty($dataRecipient['NAME'])) {
             $recipient['NAME'] = $dataRecipient['NAME'];
         }
         if (!empty($dataRecipient['USER_ID'])) {
             $recipient['USER_ID'] = $dataRecipient['USER_ID'];
         }
         // add recipient
         PostingTable::addRecipient($recipient, true);
         if (empty($mailingParams[$chainId]['CHAIN']['POSTING_ID'])) {
             $chainUpdateDb = MailingChainTable::update(array('ID' => $childChain['ID']), array('POSTING_ID' => $postingId));
             if ($chainUpdateDb->isSuccess()) {
                 $mailingParams[$chainId]['CHAIN']['POSTING_ID'] = $postingId;
             }
         }
     }
 }
Пример #13
0
 /**
  * Send posting.
  *
  * @param $id
  * @param int $timeout
  * @param int $maxMailCount
  * @return bool|string
  * @throws \Bitrix\Main\ArgumentException
  * @throws \Bitrix\Main\DB\Exception
  * @throws \Bitrix\Main\Db\SqlQueryException
  * @throws \Exception
  */
 public static function send($id, $timeout = 0, $maxMailCount = 0)
 {
     $start_time = getmicrotime();
     @set_time_limit(0);
     static::$emailSentPerIteration = 0;
     $postingDb = PostingTable::getList(array('select' => array('ID', 'STATUS', 'MAILING_ID', 'MAILING_CHAIN_ID', 'MAILING_CHAIN_REITERATE' => 'MAILING_CHAIN.REITERATE', 'MAILING_CHAIN_IS_TRIGGER' => 'MAILING_CHAIN.IS_TRIGGER'), 'filter' => array('=ID' => $id, '=MAILING.ACTIVE' => 'Y', '=MAILING_CHAIN.STATUS' => MailingChainTable::STATUS_SEND)));
     $postingData = $postingDb->fetch();
     // posting not found
     if (!$postingData) {
         return static::SEND_RESULT_ERROR;
     }
     // if posting in new status, then import recipients from groups and set right status for sending
     $isInitGroupRecipients = false;
     $isChangeStatusToPart = false;
     if ($postingData["STATUS"] == PostingTable::STATUS_NEW) {
         $isInitGroupRecipients = true;
         $isChangeStatusToPart = true;
     }
     if ($postingData["STATUS"] != PostingTable::STATUS_PART && $postingData["MAILING_CHAIN_IS_TRIGGER"] == 'Y') {
         $isInitGroupRecipients = false;
         $isChangeStatusToPart = true;
     }
     if ($isInitGroupRecipients) {
         PostingTable::initGroupRecipients($postingData['ID']);
     }
     if ($isChangeStatusToPart) {
         PostingTable::update(array('ID' => $postingData['ID']), array('STATUS' => PostingTable::STATUS_PART));
         $postingData["STATUS"] = PostingTable::STATUS_PART;
     }
     // posting not in right status
     if ($postingData["STATUS"] != PostingTable::STATUS_PART) {
         return static::SEND_RESULT_ERROR;
     }
     // lock posting for exclude double parallel sending
     if (static::lockPosting($id) === false) {
         throw new \Bitrix\Main\DB\Exception(Loc::getMessage('SENDER_POSTING_MANAGER_ERR_LOCK'));
     }
     $isStopped = false;
     $checkStatusCounter = 0;
     static::$checkStatusStep = intval(Option::get('sender', 'send_check_status_step', static::$checkStatusStep));
     // select all recipients of posting, only not processed
     $recipientDataDb = PostingRecipientTable::getList(array('filter' => array('=POSTING_ID' => $postingData['ID'], '=STATUS' => PostingRecipientTable::SEND_RESULT_NONE), 'limit' => $maxMailCount));
     while ($recipientData = $recipientDataDb->fetch()) {
         // check pause or stop status
         if (++$checkStatusCounter >= static::$checkStatusStep) {
             $checkStatusDb = MailingChainTable::getList(array('select' => array('ID'), 'filter' => array('=ID' => $postingData["MAILING_CHAIN_ID"], '=STATUS' => MailingChainTable::STATUS_SEND)));
             if (!$checkStatusDb->fetch()) {
                 break;
             }
             $checkStatusCounter = 0;
         }
         // create name from email
         $recipientEmail = $recipientData["EMAIL"];
         if (empty($recipientData["NAME"])) {
             $recipientEmailParts = explode('@', $recipientEmail);
             $recipientName = $recipientEmailParts[0];
         } else {
             $recipientName = $recipientData["NAME"];
         }
         // prepare params for send
         $sendParams = array('FIELDS' => array('EMAIL_TO' => $recipientEmail, 'NAME' => $recipientName, 'USER_ID' => $recipientData["USER_ID"], 'SENDER_CHAIN_ID' => $postingData["MAILING_CHAIN_ID"], 'SENDER_CHAIN_CODE' => 'sender_chain_item_' . $postingData["MAILING_CHAIN_ID"], 'UNSUBSCRIBE_LINK' => Subscription::getLinkUnsub(array('MAILING_ID' => $postingData['MAILING_ID'], 'EMAIL' => $recipientEmail, 'RECIPIENT_ID' => $recipientData["ID"]))), 'TRACK_READ' => array('MODULE_ID' => "sender", 'FIELDS' => array('RECIPIENT_ID' => $recipientData["ID"])), 'TRACK_CLICK' => array('MODULE_ID' => "sender", 'FIELDS' => array('RECIPIENT_ID' => $recipientData["ID"]), 'URL_PARAMS' => array('bx_sender_conversion_id' => $recipientData["ID"])));
         if (is_array($recipientData['FIELDS']) && count($recipientData) > 0) {
             $sendParams['FIELDS'] = $sendParams['FIELDS'] + $recipientData['FIELDS'];
         }
         // set sending result to recipient
         try {
             $mailSendResult = static::sendInternal($postingData['MAILING_CHAIN_ID'], $sendParams);
         } catch (\Bitrix\Main\Mail\StopException $e) {
             $isStopped = true;
             break;
         }
         PostingRecipientTable::update(array('ID' => $recipientData["ID"]), array('STATUS' => $mailSendResult, 'DATE_SENT' => new Type\DateTime()));
         // send event
         $eventData = array('SEND_RESULT' => $mailSendResult == PostingRecipientTable::SEND_RESULT_SUCCESS, 'RECIPIENT' => $recipientData, 'POSTING' => $postingData);
         $event = new Event('sender', 'OnAfterPostingSendRecipient', array($eventData));
         $event->send();
         // limit executing script by time
         if ($timeout > 0 && getmicrotime() - $start_time >= $timeout) {
             break;
         }
         // increment sending statistic
         static::$emailSentPerIteration++;
     }
     //set status and delivered and error emails
     $statusList = PostingTable::getRecipientCountByStatus($id);
     if ($isStopped) {
         $STATUS = PostingTable::STATUS_ABORT;
         $DATE = new Type\DateTime();
     } elseif (!array_key_exists(PostingRecipientTable::SEND_RESULT_NONE, $statusList)) {
         if (array_key_exists(PostingRecipientTable::SEND_RESULT_ERROR, $statusList)) {
             $STATUS = PostingTable::STATUS_SENT_WITH_ERRORS;
         } else {
             $STATUS = PostingTable::STATUS_SENT;
         }
         $DATE = new Type\DateTime();
     } else {
         $STATUS = PostingTable::STATUS_PART;
         $DATE = null;
     }
     // unlock posting for exclude double parallel sending
     static::unlockPosting($id);
     // update status of posting
     $postingUpdateFields = array('STATUS' => $STATUS, 'DATE_SENT' => $DATE, 'COUNT_SEND_ALL' => 0);
     $recipientStatusToPostingFieldMap = PostingTable::getRecipientStatusToPostingFieldMap();
     foreach ($recipientStatusToPostingFieldMap as $recipientStatus => $postingFieldName) {
         if (!array_key_exists($recipientStatus, $statusList)) {
             $postingCountFieldValue = 0;
         } else {
             $postingCountFieldValue = $statusList[$recipientStatus];
         }
         $postingUpdateFields['COUNT_SEND_ALL'] += $postingCountFieldValue;
         $postingUpdateFields[$postingFieldName] = $postingCountFieldValue;
     }
     PostingTable::update(array('ID' => $id), $postingUpdateFields);
     // return status to continue or end of sending
     if ($STATUS == PostingTable::STATUS_PART) {
         return static::SEND_RESULT_CONTINUE;
     } else {
         return static::SEND_RESULT_SENT;
     }
 }