Application->recallObject('EmailSender'); if ($this->_mailingId != $mailing_id) { if (is_numeric($this->_mailingId)) { // clear fields after previous mailing processing $esender->Clear(); } // 1. set headers same for all emails list ($mailing_data['FromName'], $mailing_data['FromEmail']) = $this->_getSenderData($mailing_data); $esender->SetFrom($mailing_data['FromEmail'], $mailing_data['FromName']); $esender->SetSubject($mailing_data['Subject']); if ( !$mailing_data['MessageText'] ) { $mailing_data['MessageText'] = $esender->ConvertToText($mailing_data['MessageHtml']); } $esender->SetBody($mailing_data['MessageHtml'], $mailing_data['MessageText']); // 2. add attachment if any $attachments = $mailing_data['Attachments'] ? explode('|', $mailing_data['Attachments']) : Array (); foreach ($attachments as $attachment) { $esender->AddAttachment(FULL_PATH . ITEM_FILES_PATH . $attachment); } $this->_mailingId = $mailing_id; } // 3. set recipient specific fields $esender->SetTo($email, $email); if ( $this->Application->ConfigValue('EnableEmailLog') ) { // 4. write to log $log_fields_hash = Array ( 'From' => $mailing_data['FromName'] . '(' . $mailing_data['FromEmail'] . ')', 'To' => $email, 'Subject' => $mailing_data['Subject'], 'HtmlBody' => $mailing_data['MessageHtml'], 'TextBody' => $mailing_data['MessageText'], 'SentOn' => TIMENOW, 'EventParams' => serialize( Array ('MailingId' => $mailing_id) ), ); $esender->setLogData($log_fields_hash); } $esender->Deliver(null, $mailing_id, false); } /** * Returns mass mail sender name & email * * @param Array $mailing_data * @return Array * @access protected */ protected function _getSenderData(&$mailing_data) { $is_root = true; $email_address = $name = ''; if ( $mailing_data['PortalUserId'] > 0 ) { /** @var UsersItem $sender */ $sender = $this->Application->recallObject('u.-item', null, Array ('skip_autoload' => true)); $sender->Load($mailing_data['PortalUserId']); $email_address = $sender->GetDBField('Email'); $name = trim($sender->GetDBField('FirstName') . ' ' . $sender->GetDBField('LastName')); $is_root = false; } if ( $is_root || !$email_address ) { $email_address = $this->Application->ConfigValue('DefaultEmailSender'); } if ( $is_root || !$name ) { $name = strip_tags($this->Application->ConfigValue('Site_Name')); } return Array ($name, $email_address); } /** * Generates recipients emails based on "To" field value. * * @param int $id Id. * @param Array $fields_hash Fields hash. * * @return array */ function generateRecipients($id, $fields_hash) { // for each group convert ids to names $recipient_emails = Array (); $recipients_grouped = $this->groupRecipientsByType(explode(';', $fields_hash['To'])); foreach ($recipients_grouped as $recipient_type => $group_recipients) { $recipient_emails = array_merge($recipient_emails, $this->_getRecipientEmails($recipient_type, $group_recipients)); } $recipient_emails = array_unique($recipient_emails); return Array ( 'ToParsed' => serialize($recipient_emails), 'EmailsTotal' => count($recipient_emails), ); } /** * Groups recipients by type * * @param Array $recipients * @return Array * @access public */ public function groupRecipientsByType($recipients) { $recipients_grouped = Array (); foreach ($recipients as $recipient) { if ( strpos($recipient, '_') !== false ) { list ($recipient_type, $recipient_id) = explode('_', $recipient); } else { $recipient_type = 'direct'; $recipient_id = $recipient; } if ( !array_key_exists($recipient_type, $recipients_grouped) ) { $recipients_grouped[$recipient_type] = Array (); } $recipients_grouped[$recipient_type][] = $recipient_id; } return $recipients_grouped; } function _getRecipientEmails($recipient_type, $recipient_ids) { if (strpos($recipient_type, '.') !== false) { // remove special list ($recipient_type, ) = explode('.', $recipient_type); } if ($recipient_type != 'u' && $recipient_type != 'g') { // these are already emails return $recipient_ids; } switch ($recipient_type) { case 'u': $sql = 'SELECT Email FROM ' . TABLE_PREFIX . 'Users WHERE (PortalUserId IN (' . implode(',', $recipient_ids) . ')) AND (Email <> "")'; break; case 'g': $sql = 'SELECT u.Email FROM ' . TABLE_PREFIX . 'UserGroupRelations ug LEFT JOIN ' . TABLE_PREFIX . 'Users u ON u.PortalUserId = ug.PortalUserId WHERE (ug.GroupId IN (' . implode(',', $recipient_ids) . ')) AND (u.Email <> "")'; break; default: $sql = ''; break; } return $this->Conn->GetCol($sql); } function getRecipientNames($recipient_type, $recipient_ids) { if (strpos($recipient_type, '.') !== false) { // remove special list ($recipient_type, ) = explode('.', $recipient_type); } switch ($recipient_type) { case 'u': $title_field = 'Email'; break; case 'g': $title_field = 'Name'; break; default: $title_field = false; break; } if ($title_field === false || !$recipient_ids) { return $recipient_ids; } $config = $this->Application->getUnitConfig($recipient_type); $id_field = $config->getIDField(); $table_name = $config->getTableName(); $sql = 'SELECT ' . $title_field . ' FROM ' . $table_name . ' WHERE ' . $id_field . ' IN (' . implode(',', $recipient_ids) . ')'; return $this->Conn->GetCol($sql); } /** * Updates information about sent email count based on given totals by mailings * * @param Array $mailing_totals */ function _updateSentTotals($mailing_totals) { if ( array_key_exists(0, $mailing_totals) ) { // don't update sent email count for mails queued directly (not via mailing lists) unset($mailing_totals[0]); } $config = $this->Application->getUnitConfig('mailing-list'); $table_name = $config->getTableName(); // update sent email count for each processed mailing foreach ( $mailing_totals as $mailing_id => $mailing_total ) { $sql = 'UPDATE ' . $table_name . ' SET EmailsSent = EmailsSent + ' . $mailing_total . ' WHERE ' . $config->getIDField() . ' = ' . $mailing_id; $this->Conn->Query($sql); } // mark mailings, that were processed completely $sql = 'UPDATE ' . $table_name . ' SET Status = ' . MailingList::PROCESSED . ' WHERE (Status = ' . MailingList::PARTIALLY_PROCESSED . ') AND (EmailsSent = EmailsTotal)'; $this->Conn->Query($sql); } /** * Sent given messages from email queue. * * @param array|null $messages Messages. * * @return integer */ function processQueue(&$messages = null) { /** @var kEmailSendingHelper $esender */ $esender = $this->Application->recallObject('EmailSender'); if ( !isset($messages) ) { $messages = $this->getMessages(); } else { kUtil::deprecatedArgument(__METHOD__, '5.3.0-B1', 'The "$messages" parameter is deprecated.'); } $message_count = count($messages); if ( !$message_count ) { return 0; } $i = 0; $message = Array(); $mailing_totals = Array(); $queue_table = $this->Application->getUnitConfig('email-queue')->getTableName(); while ( $i < $message_count ) { $message[0] = unserialize($messages[$i]['MessageHeaders']); $message[1] =& $messages[$i]['MessageBody']; $esender->setLogData(unserialize($messages[$i]['LogData'])); $delivered = $esender->Deliver($message, true); // immediate send! if ( $delivered ) { // send succeeded, delete from queue $sql = 'DELETE FROM ' . $queue_table . ' WHERE EmailQueueId = ' . $messages[$i]['EmailQueueId']; $this->Conn->Query($sql); $mailing_id = $messages[$i]['MailingId']; if ( !array_key_exists($mailing_id, $mailing_totals) ) { $mailing_totals[$mailing_id] = 0; } $mailing_totals[$mailing_id]++; } else { // send failed, increment retries counter $sql = 'UPDATE ' . $queue_table . ' SET SendRetries = SendRetries + 1, LastSendRetry = ' . time() . ' WHERE EmailQueueId = ' . $messages[$i]['EmailQueueId']; $this->Conn->Query($sql); } $i++; } $this->_updateSentTotals($mailing_totals); return $message_count; } /** * Returns queued messages (or their count), that can be sent * * @param bool $count_only * * @return Array|int * @access public */ public function getMessages($count_only = false) { $deliver_count = $this->getSetting('MailingListSendPerStep'); if ( !is_numeric($deliver_count) ) { return $count_only ? 0 : Array(); } $queue_table = $this->Application->getUnitConfig('email-queue')->getTableName(); if ( $count_only ) { $sql = 'SELECT COUNT(*) FROM ' . $queue_table . ' WHERE (SendRetries < 5) AND (LastSendRetry < ' . strtotime('-2 hours') . ')'; return $this->Conn->GetOne($sql); } // regular e-mails are pressed before mailing generated ones ! $sql = 'SELECT * FROM ' . $queue_table . ' WHERE (SendRetries < 5) AND (LastSendRetry < ' . strtotime('-2 hours') . ') ORDER BY MailingId ASC LIMIT 0,' . $deliver_count; return $this->Conn->Query($sql); } /** * Allows to safely get mailing configuration variable * * @param string $variable_name * * @return int * @access public */ public function getSetting($variable_name) { $value = $this->Application->ConfigValue($variable_name); if ( $value === false ) { // ensure default value, when configuration variable is missing return 10; } if ( !$value ) { // configuration variable found, but it's value is empty or zero return false; } return $value; } }