Index: branches/5.2.x/core/kernel/utility/email.php
===================================================================
--- branches/5.2.x/core/kernel/utility/email.php	(revision 16030)
+++ branches/5.2.x/core/kernel/utility/email.php	(revision 16031)
@@ -1,861 +1,862 @@
 <?php
 /**
  * @version	$Id$
  * @package	In-Portal
  * @copyright	Copyright (C) 1997 - 2012 Intechnic. All rights reserved.
  * @license	  GNU/GPL
  * In-Portal is Open Source software.
  * This means that this software may have been modified pursuant
  * the GNU General Public License, and as distributed it includes
  * or is derivative of works licensed under the GNU General Public License
  * or other free or open source software licenses.
  * See http://www.in-portal.org/license for copyright notices and details.
  */
 
 defined('FULL_PATH') or die('restricted access!');
 
 class kEmail extends kBase {
 
 	/**
 	 * Reference to class, that could send out e-mail
 	 *
 	 * @var kEmailSendingHelper
 	 * @access protected
 	 */
 	protected $sender = null;
 
 	/**
 	 * Parameters of e-mail
 	 *
 	 * @var Array
 	 * @access protected
 	 * @see kEmail::_getCustomParams() List of possible system parameters supported
 	 */
 	protected $params = Array ();
 
 	/**
 	 * Reference to e-mail template object, that would be used as data source
 	 *
 	 * @var kDBItem
 	 */
 	protected $emailTemplate = null;
 
 	/**
 	 * Sender name
 	 *
 	 * @var string
 	 * @access protected
 	 */
 	protected $fromName = '';
 
 	/**
 	 * Sender e-mail
 	 *
 	 * @var string
 	 * @access protected
 	 */
 	protected $fromEmail = '';
 
 	/**
 	 * Recipient name
 	 *
 	 * @var string
 	 * @access protected
 	 */
 	protected $toName = '';
 
 	/**
 	 * Recipient e-mail
 	 *
 	 * @var string
 	 * @access protected
 	 */
 	protected $toEmail = '';
 
 	/**
 	 * ID of recipient user
 	 *
 	 * @var int
 	 */
 	protected $recipientUserId = null;
 
 	/**
 	 * List of e-mail recipients
 	 *
 	 * @var Array
 	 * @access protected
 	 */
 	protected $recipients = Array (
 		EmailTemplate::RECIPIENT_TYPE_TO => Array (),
 		EmailTemplate::RECIPIENT_TYPE_CC => Array (),
 		EmailTemplate::RECIPIENT_TYPE_BCC => Array (),
 	);
 
 	/**
 	 * Creates e-mail instance
 	 */
 	public function __construct()
 	{
 		parent::__construct();
 
 		$this->sender = $this->Application->recallObject('EmailSender');
 	}
 
 	/**
 	 * Resets state of e-mail
 	 *
 	 * @return void
 	 * @access protected
 	 */
 	protected function _resetState()
 	{
 		$this->fromEmail = $this->fromName = '';
 		$this->Application->removeObject('u.email-from');
 
 		$this->recipients = Array (
 			EmailTemplate::RECIPIENT_TYPE_TO => Array (),
 			EmailTemplate::RECIPIENT_TYPE_CC => Array (),
 			EmailTemplate::RECIPIENT_TYPE_BCC => Array (),
 		);
 
 		$this->toEmail = $this->toEmail = '';
 		$this->Application->removeObject('u.email-to');
 	}
 
 	/**
 	 * Finds e-mail template matching user data
 	 *
 	 * @param string $name
 	 * @param int $type
 	 * @return bool
 	 * @throws InvalidArgumentException
 	 * @access public
 	 */
 	public function findTemplate($name, $type)
 	{
 		if ( !$name || !preg_match('/^[A-Z\.]+$/', $name) ) {
 			throw new InvalidArgumentException('Invalid e-mail template name "<strong>' . $name . '</strong>". Only <strong>UPPERCASE characters</strong> and <strong>dots</strong> are allowed.');
 		}
 
 		if ( $type != EmailTemplate::TEMPLATE_TYPE_ADMIN && $type != EmailTemplate::TEMPLATE_TYPE_FRONTEND ) {
 			throw new InvalidArgumentException('Invalid e-mail template type');
 		}
 
 		// use "-item" special prevent error, when e-mail sent out from e-mail templates list
 		$this->emailTemplate = $this->Application->recallObject('email-template.-item', null, Array ('skip_autoload' => true));
 
 		if ( !$this->emailTemplate->isLoaded() || !$this->_sameTemplate($name, $type) ) {
 			// get template parameters by name & type
 			$this->emailTemplate->Load(Array ('TemplateName' => $name, 'Type' => $type));
 		}
 
 		return $this->_templateUsable();
 	}
 
 	/**
 	 * Detects, that given e-mail template data matches currently used e-mail template
 	 *
 	 * @param string $name
 	 * @param int $type
 	 * @return bool
 	 * @access protected
 	 */
 	protected function _sameTemplate($name, $type)
 	{
 		return $this->emailTemplate->GetDBField('TemplateName') == $name && $this->emailTemplate->GetDBField('Type') == $type;
 	}
 
 	/**
 	 * Determines if we can use e-mail template we've found based on user data
 	 *
 	 * @return bool
 	 * @access protected
 	 */
 	protected function _templateUsable()
 	{
 		if ( !$this->emailTemplate->isLoaded() || $this->emailTemplate->GetDBField('Enabled') == STATUS_DISABLED ) {
 			return false;
 		}
 
 		if ( $this->emailTemplate->GetDBField('FrontEndOnly') && $this->Application->isAdmin ) {
 			return false;
 		}
 
 		return true;
 	}
 
 	/**
 	 * Sets e-mail template params
 	 *
 	 * @param Array $params
 	 * @access public
 	 */
 	public function setParams($params)
 	{
 		$this->params = $params;
 	}
 
 	/**
 	 * Returns any custom parameters, that are passed when invoked e-mail template sending
 	 *
 	 * @return Array
 	 * @access protected
 	 */
 	protected function _getCustomParams()
 	{
 		$ret = $this->params;
 		$send_keys = Array ('from_email', 'from_name', 'to_email', 'to_name', 'overwrite_to_email', 'language_id', 'use_custom_design');
 
 		foreach ($send_keys as $send_key) {
 			unset($ret[$send_key]);
 		}
 
 		return $ret;
 	}
 
 	/**
 	 * Sends e-mail now or puts it in queue
 	 *
 	 * @param int $recipient_user_id
 	 * @param bool $immediate_send
 	 * @return bool
 	 * @access public
 	 */
 	public function send($recipient_user_id = null, $immediate_send = true)
 	{
 		$this->recipientUserId = $recipient_user_id;
 
 		$this->_resetState();
 		$this->_processSender();
 		$this->_processRecipients();
 		$this->_changeLanguage(false);
 
 		// 1. set headers
 		$message_headers = $this->_getHeaders();
 		$message_subject = isset($message_headers['Subject']) ? $message_headers['Subject'] : 'Mail message';
 		$this->sender->SetSubject($message_subject);
 
 		foreach ($message_headers as $header_name => $header_value) {
 			$this->sender->SetEncodedHeader($header_name, $header_value);
 		}
 
 		if ( $this->_storeEmailLog() ) {
 			// 2. prepare log
 			$log_fields_hash = Array (
 				'From' => $this->fromName . ' (' . $this->fromEmail . ')',
 				'To' => $this->toName . ' (' . $this->toEmail . ')',
 				'OtherRecipients' => serialize($this->recipients),
 				'Subject' => $message_subject,
 				'SentOn' => TIMENOW,
 				'TemplateName' => $this->emailTemplate->GetDBField('TemplateName'),
 				'EventType' => $this->emailTemplate->GetDBField('Type'),
 				'EventParams' => serialize($this->_getCustomParams()),
 			);
 
 			$this->params['email_access_key'] = $this->_generateAccessKey($log_fields_hash);
 		}
 
 		// 3. set body
 		$html_message_body = $this->_getMessageBody(true);
 		$plain_message_body = $this->_getMessageBody(false);
 
 		if ( $html_message_body === false && $plain_message_body === false ) {
 			trigger_error('Message template is empty (maybe after parsing).', E_USER_WARNING);
 
 			return false;
 		}
 
 		if ( $html_message_body !== false ) {
 			$this->sender->CreateTextHtmlPart($html_message_body, true);
 		}
 
 		if ( $plain_message_body !== false ) {
 			$this->sender->CreateTextHtmlPart($plain_message_body, false);
 		}
 
 		$this->_changeLanguage(true);
 
 		if ( $this->_storeEmailLog() ) {
 			// 4. set log
 			$log_fields_hash['HtmlBody'] = $html_message_body;
 			$log_fields_hash['TextBody'] = $plain_message_body;
 			$log_fields_hash['AccessKey'] = $this->params['email_access_key'];
 			$this->sender->setLogData($log_fields_hash);
 		}
 
 		return $this->sender->Deliver(null, $immediate_send);
 	}
 
 	/**
 	 * Determines whatever we should keep e-mail log or not
 	 *
 	 * @return bool
 	 * @access protected
 	 */
 	protected function _storeEmailLog()
 	{
 		return $this->Application->ConfigValue('EnableEmailLog');
 	}
 
 	/**
 	 * Generates access key for accessing e-mail later
 	 *
 	 * @param Array $log_fields_hash
 	 * @return string
 	 * @access protected
 	 */
 	protected function _generateAccessKey($log_fields_hash)
 	{
 		$ret = '';
 		$use_fields = Array ('From', 'To', 'Subject');
 
 		foreach ($use_fields as $use_field) {
 			$ret .= $log_fields_hash[$use_field] . ':';
 		}
 
 		return md5($ret . microtime(true));
 	}
 
 	/**
 	 * Processes email sender
 	 *
 	 * @return void
 	 * @access protected
 	 */
 	protected function _processSender()
 	{
 		if ( $this->emailTemplate->GetDBField('CustomSender') ) {
 			$this->_processCustomSender();
 		}
 
 		// update with custom data given during event execution
 		if ( isset($this->params['from_email']) ) {
 			$this->fromEmail = $this->params['from_email'];
 		}
 
 		if ( isset($this->params['from_name']) ) {
 			$this->fromName = $this->params['from_name'];
 		}
 
 		// still nothing, set defaults
 		$this->_ensureDefaultSender();
 		$this->sender->SetFrom($this->fromEmail, $this->fromName);
 	}
 
 	/**
 	 * Processes custom e-mail sender
 	 *
 	 * @return void
 	 * @access protected
 	 */
 	protected function _processCustomSender()
 	{
 		$address = $this->emailTemplate->GetDBField('SenderAddress');
 		$address_type = $this->emailTemplate->GetDBField('SenderAddressType');
 
 		switch ($address_type) {
 			case EmailTemplate::ADDRESS_TYPE_EMAIL:
 				$this->fromEmail = $address;
 				break;
 
 			case EmailTemplate::ADDRESS_TYPE_USER:
 				$sql = 'SELECT FirstName, LastName, Email, PortalUserId
 						FROM ' . TABLE_PREFIX . 'Users
 						WHERE Username = ' . $this->Conn->qstr($address);
 				$user_info = $this->Conn->GetRow($sql);
 
 				if ( $user_info ) {
 					// user still exists
 					$this->fromEmail = $user_info['Email'];
 					$this->fromName = trim($user_info['FirstName'] . ' ' . $user_info['LastName']);
 
 					$user = $this->Application->recallObject('u.email-from', null, Array ('skip_autoload' => true));
 					/* @var $user UsersItem */
 
 					$user->Load($user_info['PortalUserId']);
 				}
 				break;
 		}
 
 		if ( $this->emailTemplate->GetDBField('SenderName') ) {
 			$this->fromName = $this->emailTemplate->GetDBField('SenderName');
 		}
 	}
 
 	/**
 	 * Ensures, that sender name & e-mail are not empty
 	 *
 	 * @return void
 	 * @access protected
 	 */
 	protected function _ensureDefaultSender()
 	{
 		if ( !$this->fromEmail ) {
 			$this->fromEmail = $this->Application->ConfigValue('DefaultEmailSender');
 		}
 
 		if ( !$this->fromName ) {
 			$this->fromName = strip_tags($this->Application->ConfigValue('Site_Name'));
 		}
 	}
 
 	/**
 	 * Processes email recipients
 	 *
 	 * @return void
 	 * @access protected
 	 */
 	protected function _processRecipients()
 	{
 		$this->_collectRecipients();
 
 		$header_mapping = Array (
 			EmailTemplate::RECIPIENT_TYPE_TO => 'To',
 			EmailTemplate::RECIPIENT_TYPE_CC => 'Cc',
 			EmailTemplate::RECIPIENT_TYPE_BCC => 'Bcc',
 		);
 
 		$default_email = $this->Application->ConfigValue('DefaultEmailSender');
 		$this->recipients = array_map(Array ($this, '_transformRecipientsIntoPairs'), $this->recipients);
 
 		foreach ($this->recipients as $recipient_type => $recipients) {
 			// add recipients to email
 			if ( !$recipients ) {
 				continue;
 			}
 
 			if ( $recipient_type == EmailTemplate::RECIPIENT_TYPE_TO ) {
 				$this->toEmail = $recipients[0]['email'] ? $recipients[0]['email'] : $default_email;
 				$this->toName = $recipients[0]['name'] ? $recipients[0]['name'] : $this->toEmail;
 			}
 
 			$header_name = $header_mapping[$recipient_type];
 
 			foreach ($recipients as $recipient) {
 				$email = $recipient['email'] ? $recipient['email'] : $default_email;
 				$name = $recipient['name'] ? $recipient['name'] : $email;
 
 				$this->sender->AddRecipient($header_name, $email, $name);
 			}
 		}
 	}
 
 	/**
 	 * Collects e-mail recipients from various sources
 	 *
 	 * @return void
 	 * @access protected
 	 */
 	protected function _collectRecipients()
 	{
 		$this->_addRecipientsFromXml($this->emailTemplate->GetDBField('Recipients'));
 		$this->_overwriteToRecipient();
 		$this->_addRecipientByUserId();
 		$this->_addRecipientFromParams();
 
 		if ( ($this->emailTemplate->GetDBField('Type') == EmailTemplate::TEMPLATE_TYPE_ADMIN) && !$this->recipients[EmailTemplate::RECIPIENT_TYPE_TO] ) {
 			// admin email template without direct recipient -> send to admin
 			$this->_addDefaultRecipient();
 		}
 	}
 
 	/**
 	 * Adds multiple recipients from an XML
 	 *
 	 * @param string $xml
 	 * @return bool
 	 * @access protected
 	 */
 	protected function _addRecipientsFromXml($xml)
 	{
 		if ( !$xml ) {
 			return false;
 		}
 
 		$minput_helper = $this->Application->recallObject('MInputHelper');
 		/* @var $minput_helper MInputHelper */
 
 		// group recipients by type
 		$records = $minput_helper->parseMInputXML($xml);
 
 		foreach ($records as $record) {
 			$this->recipients[$record['RecipientType']][] = $record;
 		}
 
 		return true;
 	}
 
 	/**
 	 * Remove all "To" recipients, when not allowed
 	 *
 	 * @return void
 	 * @access protected
 	 */
 	protected function _overwriteToRecipient()
 	{
 		$overwrite_to_email = isset($this->params['overwrite_to_email']) ? $this->params['overwrite_to_email'] : false;
 
 		if ( !$this->emailTemplate->GetDBField('CustomRecipient') || $overwrite_to_email ) {
 			$this->recipients[EmailTemplate::RECIPIENT_TYPE_TO] = Array ();
 		}
 	}
 
 	/**
 	 * Update with custom data given during event execution (user_id)
 	 *
 	 * @return void
 	 * @access protected
 	 */
 	protected function _addRecipientByUserId()
 	{
 		if ( !is_numeric($this->recipientUserId) ) {
 			return;
 		}
 
 		if ( $this->recipientUserId <= 0 ) {
 			// recipient is system user with negative ID (root, guest, etc.) -> send to admin
 			$this->_addDefaultRecipient();
 
 			return;
 		}
 
 		$language_field = $this->emailTemplate->GetDBField('Type') == EmailTemplate::TEMPLATE_TYPE_FRONTEND ? 'FrontLanguage' : 'AdminLanguage';
 
 		$sql = 'SELECT FirstName, LastName, Email, ' . $language_field . ' AS Language
 				FROM ' . TABLE_PREFIX . 'Users
 				WHERE PortalUserId = ' . $this->recipientUserId;
 		$user_info = $this->Conn->GetRow($sql);
 
 		if ( !$user_info ) {
 			return;
 		}
 
 		$add_recipient = Array (
 			'RecipientAddressType' => EmailTemplate::ADDRESS_TYPE_EMAIL,
 			'RecipientAddress' => $user_info['Email'],
 			'RecipientName' => trim($user_info['FirstName'] . ' ' . $user_info['LastName']),
 		);
 
 		if ( $user_info['Language'] && !isset($this->params['language_id']) ) {
 			$this->params['language_id'] = $user_info['Language'];
 		}
 
 		array_unshift($this->recipients[EmailTemplate::RECIPIENT_TYPE_TO], $add_recipient);
 
 		$user = $this->Application->recallObject('u.email-to', null, Array('skip_autoload' => true));
 		/* @var $user UsersItem */
 
 		$user->Load($this->recipientUserId);
 	}
 
 	/**
 	 * Update with custom data given during event execution (email + name)
 	 *
 	 * @return void
 	 * @access protected
 	 */
 	protected function _addRecipientFromParams()
 	{
 		$add_recipient = Array ();
 
 		if ( isset($this->params['to_email']) && $this->params['to_email'] ) {
 			$add_recipient['RecipientName'] = '';
 			$add_recipient['RecipientAddressType'] = EmailTemplate::ADDRESS_TYPE_EMAIL;
 			$add_recipient['RecipientAddress'] = $this->params['to_email'];
 		}
 
 		if ( isset($this->params['to_name']) && $this->params['to_name'] ) {
 			$add_recipient['RecipientName'] = $this->params['to_name'];
 		}
 
 		if ( $add_recipient ) {
 			array_unshift($this->recipients[EmailTemplate::RECIPIENT_TYPE_TO], $add_recipient);
 		}
 	}
 
 	/**
 	 * This is default recipient, when we can't determine actual one
 	 *
 	 * @return void
 	 * @access protected
 	 */
 	protected function _addDefaultRecipient()
 	{
 		$xml = $this->Application->ConfigValue('DefaultEmailRecipients');
 
 		if ( !$this->_addRecipientsFromXml($xml) ) {
 			$recipient = Array (
 				'RecipientName' => $this->Application->ConfigValue('DefaultEmailSender'),
 				'RecipientAddressType' => EmailTemplate::ADDRESS_TYPE_EMAIL,
 				'RecipientAddress' => $this->Application->ConfigValue('DefaultEmailSender'),
 			);
 
 			array_unshift($this->recipients[EmailTemplate::RECIPIENT_TYPE_TO], $recipient);
 		}
 	}
 
 	/**
 	 * Transforms recipients into name/e-mail pairs
 	 *
 	 * @param Array $recipients
 	 * @return Array
 	 * @access protected
 	 */
 	protected function _transformRecipientsIntoPairs($recipients)
 	{
 		if ( !$recipients ) {
 			return Array ();
 		}
 
 		$pairs = Array ();
 
 		foreach ($recipients as $recipient) {
 			$address = $recipient['RecipientAddress'];
 			$address_type = $recipient['RecipientAddressType'];
 			$recipient_name = $recipient['RecipientName'];
 
 			switch ($address_type) {
 				case EmailTemplate::ADDRESS_TYPE_EMAIL:
 					$pairs[] = Array ('email' => $address, 'name' => $recipient_name);
 					break;
 
 				case EmailTemplate::ADDRESS_TYPE_USER:
 					$sql = 'SELECT FirstName, LastName, Email
 							FROM ' . TABLE_PREFIX . 'Users
 							WHERE Username = ' . $this->Conn->qstr($address);
 					$user_info = $this->Conn->GetRow($sql);
 
 					if ( $user_info ) {
 						// user still exists
 						$name = trim($user_info['FirstName'] . ' ' . $user_info['LastName']);
 
 						$pairs[] = Array (
 							'email' => $user_info['Email'],
 							'name' => $name ? $name : $recipient_name,
 						);
 					}
 					break;
 
 				case EmailTemplate::ADDRESS_TYPE_GROUP:
 					$sql = 'SELECT u.FirstName, u.LastName, u.Email
 							FROM ' . TABLE_PREFIX . 'UserGroups g
 							JOIN ' . TABLE_PREFIX . 'UserGroupRelations ug ON ug.GroupId = g.GroupId
 							JOIN ' . TABLE_PREFIX . 'Users u ON u.PortalUserId = ug.PortalUserId
 							WHERE g.Name = ' . $this->Conn->qstr($address);
 					$users = $this->Conn->Query($sql);
 
 					foreach ($users as $user_info) {
 						$name = trim($user_info['FirstName'] . ' ' . $user_info['LastName']);
 
 						$pairs[] = Array (
 							'email' => $user_info['Email'],
 							'name' => $name ? $name : $recipient_name,
 						);
 					}
 					break;
 			}
 		}
 
 		return $pairs;
 	}
 	/**
 	 * Change system language temporarily to send e-mail on user language
 	 *
 	 * @param bool $restore
 	 * @return void
 	 * @access protected
 	 */
 	protected function _changeLanguage($restore = false)
 	{
 		static $prev_language_id = null;
 
 		if ( !isset($prev_language_id) ) {
 			$prev_language_id = $this->Application->GetVar('m_lang');
 		}
 
 		// ensure that language is set
 		if ( !isset($this->params['language_id']) ) {
 			$this->params['language_id'] = $this->Application->GetVar('m_lang');
 		}
 
 		$language_id = $restore ? $prev_language_id : $this->params['language_id'];
 		$this->Application->SetVar('m_lang', $language_id);
 
 		$language = $this->Application->recallObject('lang.current');
 		/* @var $language LanguagesItem */
 
 		$language->Load($language_id);
 
 		$this->Application->Phrases->LanguageId = $language_id;
 		$this->Application->Phrases->Phrases = Array ();
 	}
 
 	/**
 	 * Parses message headers into array
 	 *
 	 * @return Array
 	 * @access protected
 	 */
 	protected function _getHeaders()
 	{
 		$headers = $this->emailTemplate->GetDBField('Headers');
 		$headers = 'Subject: ' . $this->emailTemplate->GetField('Subject') . ($headers ? "\n" . $headers : '');
 		$headers = explode("\n", $this->_parseText($headers));
 
 		$ret = Array ();
 
 		foreach ($headers as $header) {
 			$header = explode(':', $header, 2);
 			$ret[ trim($header[0]) ] = trim($header[1]);
 		}
 
 		if ( $this->Application->isDebugMode() ) {
 			// set special header with template name, so it will be easier to determine what's actually was received
 			$template_type = $this->emailTemplate->GetDBField('Type') == EmailTemplate::TEMPLATE_TYPE_ADMIN ? 'ADMIN' : 'USER';
 			$ret['X-Template-Name'] = $this->emailTemplate->GetDBField('TemplateName') . ' - ' . $template_type;
 		}
 
 		return $ret;
 	}
 
 	/**
 	 * Applies design to given e-mail text
 	 *
 	 * @param string $text
 	 * @param bool $is_html
 	 * @return string
 	 * @access protected
 	 */
 	protected function _applyMessageDesign($text, $is_html = true)
 	{
 		static $design_templates = Array();
 
 		$design_key = 'L' . $this->params['language_id'] . ':' . ($is_html ? 'html' : 'text');
 
 		if ( !isset($design_templates[$design_key]) ) {
 			$language = $this->Application->recallObject('lang.current');
 			/* @var $language LanguagesItem */
 
 			$design_template = $language->GetDBField($is_html ? 'HtmlEmailTemplate' : 'TextEmailTemplate');
 
 			if ( !$is_html && !$design_template ) {
 				$design_template = $this->sender->ConvertToText($language->GetDBField('HtmlEmailTemplate'), true);
 			}
 
 			$design_templates[$design_key] = $design_template;
 		}
 
 		return $this->_parseText(str_replace('$body', $text, $design_templates[$design_key]), $is_html);
 	}
 
 	/**
 	 * Returns message body
 	 *
 	 * @param bool $is_html
 	 * @return bool|string
 	 * @access protected
 	 */
 	protected function _getMessageBody($is_html = false)
 	{
 		$message_body = $this->emailTemplate->GetField($is_html ? 'HtmlBody' : 'PlainTextBody');
 
 		if ( !trim($message_body) && !$is_html ) {
 			// no plain text part available -> make it from html part then
 			$message_body = $this->sender->ConvertToText($this->emailTemplate->GetField('HtmlBody'), true);
 		}
 
 		if ( !trim($message_body) ) {
 			return false;
 		}
 
 		if ( isset($this->params['use_custom_design']) && $this->params['use_custom_design'] ) {
 			$message_body = $this->_parseText($message_body, $is_html);
 		}
 		else {
 			$message_body = $this->_applyMessageDesign($message_body, $is_html);
 		}
 
 		return trim($message_body) ? $message_body : false;
 	}
 
 	/**
 	 * Parse message template and return headers (as array) and message body part
 	 *
 	 * @param string $text
 	 * @param bool $is_html
 	 * @return string
 	 * @access protected
 	 */
 	protected function _parseText($text, $is_html = true)
 	{
 		$text = $this->_substituteReplacementTags($text);
 
 		if ( !$text ) {
 			return '';
 		}
 
 		// init for cases, when e-mail is sent from event before page template rendering
 		$this->Application->InitParser();
 
 		$parser_params = $this->Application->Parser->Params; // backup parser params
 		$this->Application->Parser->SetParams($this->params);
 
-		$text = $this->Application->Parser->Parse($this->_normalizeLineEndings($text), 'email_template');
+		$template_name = 'et_' . $this->emailTemplate->GetID() . '_' . crc32($text);
+		$text = $this->Application->Parser->Parse($this->_normalizeLineEndings($text), $template_name);
 		$this->Application->Parser->SetParams($parser_params); // restore parser params
 
 		$category_helper = $this->Application->recallObject('CategoryHelper');
 		/* @var $category_helper CategoryHelper */
 
 		return $category_helper->replacePageIds($is_html ? $this->_removeTrailingLineEndings($text) : $text);
 	}
 
 	/**
 	 * Substitutes replacement tags in given text
 	 *
 	 * @param string $text
 	 * @return string
 	 * @access protected
 	 */
 	protected function _substituteReplacementTags($text)
 	{
 		$default_replacement_tags = Array (
 			'<inp:touser _Field="password"' => '<inp2:u_Field name="Password_plain"',
 			'<inp:touser _Field="UserName"' => '<inp2:u_Field name="Username"',
 			'<inp:touser _Field' => '<inp2:u_Field name',
 		);
 
 		$replacement_tags = $this->emailTemplate->GetDBField('ReplacementTags');
 		$replacement_tags = $replacement_tags ? unserialize($replacement_tags) : Array ();
 		$replacement_tags = array_merge($default_replacement_tags, $replacement_tags);
 
 		foreach ($replacement_tags as $replace_from => $replace_to) {
 			$text = str_replace($replace_from, $replace_to, $text);
 		}
 
 		return $text;
 	}
 
 	/**
 	 * Convert Unix/Windows/Mac line ending into Unix line endings
 	 *
 	 * @param string $text
 	 * @return string
 	 * @access protected
 	 */
 	protected function _normalizeLineEndings($text)
 	{
 		return str_replace(Array ("\r\n", "\r"), "\n", $text);
 	}
 
 	/**
 	 * Remove trailing line endings
 	 *
 	 * @param $text
 	 * @return string
 	 * @access protected
 	 */
 	protected function _removeTrailingLineEndings($text)
 	{
 		return preg_replace('/(\n|\r)+/', "\\1", $text);
 	}
-}
\ No newline at end of file
+}