newsletter-bundle/src/Resources/contao/classes/Newsletter.php
public function send(DataContainer $dc)
	{
		$objNewsletter = $this->Database->prepare("SELECT n.*, c.template AS channelTemplate, c.sender AS channelSender, c.senderName as channelSenderName FROM tl_newsletter n LEFT JOIN tl_newsletter_channel c ON n.pid=c.id WHERE n.id=?")
										->limit(1)
										->execute($dc->id);

		// Return if there is no newsletter
		if ($objNewsletter->numRows < 1)
		{
			return '';
		}

		// Set the template
		if ($objNewsletter->template == '')
		{
			$objNewsletter->template = $objNewsletter->channelTemplate;
		}

		// Set the sender address
		if ($objNewsletter->sender == '')
		{
			$objNewsletter->sender = $objNewsletter->channelSender;
		}

		// Set the sender name
		if ($objNewsletter->senderName == '')
		{
			$objNewsletter->senderName = $objNewsletter->channelSenderName;
		}

		// No sender address given
		if ($objNewsletter->sender == '')
		{
			throw new InternalServerErrorException('No sender address given. Please check the newsletter channel settings.');
		}

		$arrAttachments = array();

		// Add attachments
		if ($objNewsletter->addFile)
		{
			$files = StringUtil::deserialize($objNewsletter->files);

			if (!empty($files) && \is_array($files))
			{
				$objFiles = FilesModel::findMultipleByUuids($files);

				if ($objFiles !== null)
				{
					$rootDir = System::getContainer()->getParameter('kernel.project_dir');

					while ($objFiles->next())
					{
						if (is_file($rootDir . '/' . $objFiles->path))
						{
							$arrAttachments[] = $objFiles->path;
						}
					}
				}
			}
		}

		// Replace insert tags
		$html = $this->replaceInsertTags($objNewsletter->content, false);
		$text = $this->replaceInsertTags($objNewsletter->text, false);

		// Convert relative URLs
		if ($objNewsletter->externalImages)
		{
			$html = $this->convertRelativeUrls($html);
		}

		/** @var Session $objSession */
		$objSession = System::getContainer()->get('session');

		// Send newsletter
		if (Input::get('token') != '' && Input::get('token') == $objSession->get('tl_newsletter_send'))
		{
			$referer = preg_replace('/&(amp;)?(start|mpc|token|recipient|preview)=[^&]*/', '', Environment::get('request'));

			// Preview
			if (isset($_GET['preview']))
			{
				// Check the e-mail address
				if (!Validator::isEmail(Input::get('recipient', true)))
				{
					$_SESSION['TL_PREVIEW_MAIL_ERROR'] = true;
					$this->redirect($referer);
				}

				$arrRecipient['email'] = urldecode(Input::get('recipient', true));

				// Send
				$objEmail = $this->generateEmailObject($objNewsletter, $arrAttachments);
				$this->sendNewsletter($objEmail, $objNewsletter, $arrRecipient, $text, $html);

				// Redirect
				Message::addConfirmation(sprintf($GLOBALS['TL_LANG']['tl_newsletter']['confirm'], 1));
				$this->redirect($referer);
			}

			// Get the total number of recipients
			$objTotal = $this->Database->prepare("SELECT COUNT(DISTINCT email) AS count FROM tl_newsletter_recipients WHERE pid=? AND active=1")
									   ->execute($objNewsletter->pid);

			// Return if there are no recipients
			if ($objTotal->count < 1)
			{
				$objSession->set('tl_newsletter_send', null);
				Message::addError($GLOBALS['TL_LANG']['tl_newsletter']['error']);
				$this->redirect($referer);
			}

			$intTotal = $objTotal->count;

			// Get page and timeout
			$intTimeout = (Input::get('timeout') > 0) ? Input::get('timeout') : 1;
			$intStart = Input::get('start') ?: 0;
			$intPages = Input::get('mpc') ?: 10;

			// Get recipients
			$objRecipients = $this->Database->prepare("SELECT *, r.email FROM tl_newsletter_recipients r LEFT JOIN tl_member m ON(r.email=m.email) WHERE r.pid=? AND r.active=1 ORDER BY r.email")
											->limit($intPages, $intStart)
											->execute($objNewsletter->pid);

			echo '<div style="font-family:Verdana,sans-serif;font-size:11px;line-height:16px;margin-bottom:12px">';

			// Send newsletter
			if ($objRecipients->numRows > 0)
			{
				// Update status
				if ($intStart == 0)
				{
					$this->Database->prepare("UPDATE tl_newsletter SET sent='1', date=? WHERE id=?")
								   ->execute(time(), $objNewsletter->id);

					$_SESSION['REJECTED_RECIPIENTS'] = array();
				}

				while ($objRecipients->next())
				{
					// Skip the recipient if the member is not active (see #8812)
					if ($objRecipients->id !== null && ($objRecipients->disable || ($objRecipients->start != '' && $objRecipients->start > time()) || ($objRecipients->stop != '' && $objRecipients->stop < time())))
					{
						--$intTotal;
						echo 'Skipping <strong>' . Idna::decodeEmail($objRecipients->email) . '</strong> as the member is not active<br>';
						continue;
					}

					$objEmail = $this->generateEmailObject($objNewsletter, $arrAttachments);
					$this->sendNewsletter($objEmail, $objNewsletter, $objRecipients->row(), $text, $html);

					echo 'Sending newsletter to <strong>' . Idna::decodeEmail($objRecipients->email) . '</strong><br>';
				}
			}

			echo '<div style="margin-top:12px">';

			// Redirect back home
			if ($objRecipients->numRows < 1 || ($intStart + $intPages) >= $intTotal)
			{
				$objSession->set('tl_newsletter_send', null);

				// Deactivate rejected addresses
				if (!empty($_SESSION['REJECTED_RECIPIENTS']))
				{
					$intRejected = \count($_SESSION['REJECTED_RECIPIENTS']);
					Message::addInfo(sprintf($GLOBALS['TL_LANG']['tl_newsletter']['rejected'], $intRejected));
					$intTotal -= $intRejected;

					foreach ($_SESSION['REJECTED_RECIPIENTS'] as $strRecipient)
					{
						$this->Database->prepare("UPDATE tl_newsletter_recipients SET active='' WHERE email=?")
									   ->execute($strRecipient);

						$this->log('Recipient address "' . Idna::decodeEmail($strRecipient) . '" was rejected and has been deactivated', __METHOD__, TL_ERROR);
					}
				}

				Message::addConfirmation(sprintf($GLOBALS['TL_LANG']['tl_newsletter']['confirm'], $intTotal));

				echo '<script>setTimeout(\'window.location="' . Environment::get('base') . $referer . '"\',1000)</script>';
				echo '<a href="' . Environment::get('base') . $referer . '">Please click here to proceed if you are not using JavaScript</a>';
			}

			// Redirect to the next cycle
			else
			{
				$url = preg_replace('/&(amp;)?(start|mpc|recipient)=[^&]*/', '', Environment::get('request')) . '&start=' . ($intStart + $intPages) . '&mpc=' . $intPages;

				echo '<script>setTimeout(\'window.location="' . Environment::get('base') . $url . '"\',' . ($intTimeout * 1000) . ')</script>';
				echo '<a href="' . Environment::get('base') . $url . '">Please click here to proceed if you are not using JavaScript</a>';
			}

			echo '</div></div>';
			exit;
		}

		$strToken = md5(uniqid(mt_rand(), true));
		$objSession->set('tl_newsletter_send', $strToken);
		$sprintf = ($objNewsletter->senderName != '') ? $objNewsletter->senderName . ' &lt;%s&gt;' : '%s';
		$this->import(BackendUser::class, 'User');

		// Preview newsletter
		$return = Message::generate() . '
<div id="tl_buttons">
<a href="'.$this->getReferer(true).'" class="header_back" title="'.StringUtil::specialchars($GLOBALS['TL_LANG']['MSC']['backBTTitle']).'" accesskey="b">'.$GLOBALS['TL_LANG']['MSC']['backBT'].'</a>
</div>
<form action="'.TL_SCRIPT.'" id="tl_newsletter_send" class="tl_form tl_edit_form" method="get">
<div class="tl_formbody_edit tl_newsletter_send">
<input type="hidden" name="do" value="' . Input::get('do') . '">
<input type="hidden" name="table" value="' . Input::get('table') . '">
<input type="hidden" name="key" value="' . Input::get('key') . '">
<input type="hidden" name="id" value="' . Input::get('id') . '">
<input type="hidden" name="token" value="' . $strToken . '">
<table class="prev_header">
  <tr class="row_0">
    <td class="col_0">' . $GLOBALS['TL_LANG']['tl_newsletter']['from'] . '</td>
    <td class="col_1">' . sprintf($sprintf, Idna::decodeEmail($objNewsletter->sender)) . '</td>
  </tr>
  <tr class="row_1">
    <td class="col_0">' . $GLOBALS['TL_LANG']['tl_newsletter']['subject'][0] . '</td>
    <td class="col_1">' . $objNewsletter->subject . '</td>
  </tr>
  <tr class="row_2">
    <td class="col_0">' . $GLOBALS['TL_LANG']['tl_newsletter']['template'][0] . '</td>
    <td class="col_1">' . $objNewsletter->template . '</td>
  </tr>' . ((!empty($arrAttachments) && \is_array($arrAttachments)) ? '
  <tr class="row_3">
    <td class="col_0">' . $GLOBALS['TL_LANG']['tl_newsletter']['attachments'] . '</td>
    <td class="col_1">' . implode(', ', $arrAttachments) . '</td>
  </tr>' : '') . '
</table>' . (!$objNewsletter->sendText ? '
<div class="preview_html">
' . $html . '
</div>' : '') . '
<div class="preview_text">
<pre style="white-space:pre-wrap">' . $text . '</pre>
</div>

<fieldset class="tl_tbox nolegend">
<div class="w50 widget">
  <h3><label for="ctrl_mpc">' . $GLOBALS['TL_LANG']['tl_newsletter']['mailsPerCycle'][0] . '</label></h3>
  <input type="text" name="mpc" id="ctrl_mpc" value="10" class="tl_text" onfocus="Backend.getScrollOffset()">' . (($GLOBALS['TL_LANG']['tl_newsletter']['mailsPerCycle'][1] && Config::get('showHelp')) ? '
  <p class="tl_help tl_tip">' . $GLOBALS['TL_LANG']['tl_newsletter']['mailsPerCycle'][1] . '</p>' : '') . '
</div>
<div class="w50 widget">
  <h3><label for="ctrl_timeout">' . $GLOBALS['TL_LANG']['tl_newsletter']['timeout'][0] . '</label></h3>
  <input type="text" name="timeout" id="ctrl_timeout" value="1" class="tl_text" onfocus="Backend.getScrollOffset()">' . (($GLOBALS['TL_LANG']['tl_newsletter']['timeout'][1] && Config::get('showHelp')) ? '
  <p class="tl_help tl_tip">' . $GLOBALS['TL_LANG']['tl_newsletter']['timeout'][1] . '</p>' : '') . '
</div>
<div class="w50 widget">
  <h3><label for="ctrl_start">' . $GLOBALS['TL_LANG']['tl_newsletter']['start'][0] . '</label></h3>
  <input type="text" name="start" id="ctrl_start" value="0" class="tl_text" onfocus="Backend.getScrollOffset()">' . (($GLOBALS['TL_LANG']['tl_newsletter']['start'][1] && Config::get('showHelp')) ? '
  <p class="tl_help tl_tip">' . sprintf($GLOBALS['TL_LANG']['tl_newsletter']['start'][1], $objNewsletter->id) . '</p>' : '') . '
</div>
<div class="w50 widget">
  <h3><label for="ctrl_recipient">' . $GLOBALS['TL_LANG']['tl_newsletter']['sendPreviewTo'][0] . '</label></h3>
  <input type="text" name="recipient" id="ctrl_recipient" value="'.Idna::decodeEmail($this->User->email).'" class="tl_text" onfocus="Backend.getScrollOffset()">' . (isset($_SESSION['TL_PREVIEW_MAIL_ERROR']) ? '
  <div class="tl_error">' . $GLOBALS['TL_LANG']['ERR']['email'] . '</div>' : (($GLOBALS['TL_LANG']['tl_newsletter']['sendPreviewTo'][1] && Config::get('showHelp')) ? '
  <p class="tl_help tl_tip">' . $GLOBALS['TL_LANG']['tl_newsletter']['sendPreviewTo'][1] . '</p>' : '')) . '
</div>
</fieldset>
</div>';

		$return .= '

<div class="tl_formbody_submit">
<div class="tl_submit_container">
<button type="submit" name="preview" class="tl_submit" accesskey="p">'.$GLOBALS['TL_LANG']['tl_newsletter']['preview'].'</button>
<button type="submit" id="send" class="tl_submit" accesskey="s" onclick="return confirm(\''. str_replace("'", "\\'", $GLOBALS['TL_LANG']['tl_newsletter']['sendConfirm']) .'\')">'.$GLOBALS['TL_LANG']['tl_newsletter']['send'][0].'</button>
</div>
</div>

</form>';

		unset($_SESSION['TL_PREVIEW_MAIL_ERROR']);

		return $return;
	}
public function send(DataContainer $dc)
	{
		$objNewsletter = $this->Database->prepare("SELECT n.*, c.template AS channelTemplate, c.sender AS channelSender, c.senderName as channelSenderName FROM tl_newsletter n LEFT JOIN tl_newsletter_channel c ON n.pid=c.id WHERE n.id=?")
										->limit(1)
										->execute($dc->id);

		// Return if there is no newsletter
		if ($objNewsletter->numRows < 1)
		{
			return '';
		}

		// Set the template
		if ($objNewsletter->template == '')
		{
			$objNewsletter->template = $objNewsletter->channelTemplate;
		}

		// Set the sender address
		if ($objNewsletter->sender == '')
		{
			$objNewsletter->sender = $objNewsletter->channelSender;
		}

		// Set the sender name
		if ($objNewsletter->senderName == '')
		{
			$objNewsletter->senderName = $objNewsletter->channelSenderName;
		}

		// No sender address given
		if ($objNewsletter->sender == '')
		{
			throw new InternalServerErrorException('No sender address given. Please check the newsletter channel settings.');
		}

		$arrAttachments = array();

		// Add attachments
		if ($objNewsletter->addFile)
		{
			$files = StringUtil::deserialize($objNewsletter->files);

			if (!empty($files) && \is_array($files))
			{
				$objFiles = FilesModel::findMultipleByUuids($files);

				if ($objFiles !== null)
				{
					$rootDir = System::getContainer()->getParameter('kernel.project_dir');

					while ($objFiles->next())
					{
						if (is_file($rootDir . '/' . $objFiles->path))
						{
							$arrAttachments[] = $objFiles->path;
						}
					}
				}
			}
		}

		// Replace insert tags
		$html = $this->replaceInsertTags($objNewsletter->content, false);
		$text = $this->replaceInsertTags($objNewsletter->text, false);

		// Convert relative URLs
		if ($objNewsletter->externalImages)
		{
			$html = $this->convertRelativeUrls($html);
		}

		/** @var Session $objSession */
		$objSession = System::getContainer()->get('session');

		// Send newsletter
		if (Input::get('token') != '' && Input::get('token') == $objSession->get('tl_newsletter_send'))
		{
			$referer = preg_replace('/&(amp;)?(start|mpc|token|recipient|preview)=[^&]*/', '', Environment::get('request'));

			// Preview
			if (isset($_GET['preview']))
			{
				// Check the e-mail address
				if (!Validator::isEmail(Input::get('recipient', true)))
				{
					$_SESSION['TL_PREVIEW_MAIL_ERROR'] = true;
					$this->redirect($referer);
				}

				$arrRecipient['email'] = urldecode(Input::get('recipient', true));

				// Send
				$objEmail = $this->generateEmailObject($objNewsletter, $arrAttachments);
				$this->sendNewsletter($objEmail, $objNewsletter, $arrRecipient, $text, $html);

				// Redirect
				Message::addConfirmation(sprintf($GLOBALS['TL_LANG']['tl_newsletter']['confirm'], 1));
				$this->redirect($referer);
			}

			// Get the total number of recipients
			$objTotal = $this->Database->prepare("SELECT COUNT(DISTINCT email) AS count FROM tl_newsletter_recipients WHERE pid=? AND active=1")
									   ->execute($objNewsletter->pid);

			// Return if there are no recipients
			if ($objTotal->count < 1)
			{
				$objSession->set('tl_newsletter_send', null);
				Message::addError($GLOBALS['TL_LANG']['tl_newsletter']['error']);
				$this->redirect($referer);
			}

			$intTotal = $objTotal->count;

			// Get page and timeout
			$intTimeout = (Input::get('timeout') > 0) ? Input::get('timeout') : 1;
			$intStart = Input::get('start') ?: 0;
			$intPages = Input::get('mpc') ?: 10;

			// Get recipients
			$objRecipients = $this->Database->prepare("SELECT *, r.email FROM tl_newsletter_recipients r LEFT JOIN tl_member m ON(r.email=m.email) WHERE r.pid=? AND r.active=1 ORDER BY r.email")
											->limit($intPages, $intStart)
											->execute($objNewsletter->pid);

			echo '<div style="font-family:Verdana,sans-serif;font-size:11px;line-height:16px;margin-bottom:12px">';

			// Send newsletter
			if ($objRecipients->numRows > 0)
			{
				// Update status
				if ($intStart == 0)
				{
					$this->Database->prepare("UPDATE tl_newsletter SET sent='1', date=? WHERE id=?")
								   ->execute(time(), $objNewsletter->id);

					$_SESSION['REJECTED_RECIPIENTS'] = array();
				}

				while ($objRecipients->next())
				{
					// Skip the recipient if the member is not active (see #8812)
					if ($objRecipients->id !== null && ($objRecipients->disable || ($objRecipients->start != '' && $objRecipients->start > time()) || ($objRecipients->stop != '' && $objRecipients->stop < time())))
					{
						--$intTotal;
						echo 'Skipping <strong>' . Idna::decodeEmail($objRecipients->email) . '</strong> as the member is not active<br>';
						continue;
					}

					$objEmail = $this->generateEmailObject($objNewsletter, $arrAttachments);
					$this->sendNewsletter($objEmail, $objNewsletter, $objRecipients->row(), $text, $html);

					echo 'Sending newsletter to <strong>' . Idna::decodeEmail($objRecipients->email) . '</strong><br>';
				}
			}

			echo '<div style="margin-top:12px">';

			// Redirect back home
			if ($objRecipients->numRows < 1 || ($intStart + $intPages) >= $intTotal)
			{
				$objSession->set('tl_newsletter_send', null);

				// Deactivate rejected addresses
				if (!empty($_SESSION['REJECTED_RECIPIENTS']))
				{
					$intRejected = \count($_SESSION['REJECTED_RECIPIENTS']);
					Message::addInfo(sprintf($GLOBALS['TL_LANG']['tl_newsletter']['rejected'], $intRejected));
					$intTotal -= $intRejected;

					foreach ($_SESSION['REJECTED_RECIPIENTS'] as $strRecipient)
					{
						$this->Database->prepare("UPDATE tl_newsletter_recipients SET active='' WHERE email=?")
									   ->execute($strRecipient);

						$this->log('Recipient address "' . Idna::decodeEmail($strRecipient) . '" was rejected and has been deactivated', __METHOD__, TL_ERROR);
					}
				}

				Message::addConfirmation(sprintf($GLOBALS['TL_LANG']['tl_newsletter']['confirm'], $intTotal));

				echo '<script>setTimeout(\'window.location="' . Environment::get('base') . $referer . '"\',1000)</script>';
				echo '<a href="' . Environment::get('base') . $referer . '">Please click here to proceed if you are not using JavaScript</a>';
			}

			// Redirect to the next cycle
			else
			{
				$url = preg_replace('/&(amp;)?(start|mpc|recipient)=[^&]*/', '', Environment::get('request')) . '&start=' . ($intStart + $intPages) . '&mpc=' . $intPages;

				echo '<script>setTimeout(\'window.location="' . Environment::get('base') . $url . '"\',' . ($intTimeout * 1000) . ')</script>';
				echo '<a href="' . Environment::get('base') . $url . '">Please click here to proceed if you are not using JavaScript</a>';
			}

			echo '</div></div>';
			exit;
		}

		$strToken = md5(uniqid(mt_rand(), true));
		$objSession->set('tl_newsletter_send', $strToken);
		$sprintf = ($objNewsletter->senderName != '') ? $objNewsletter->senderName . ' &lt;%s&gt;' : '%s';
		$this->import(BackendUser::class, 'User');

		// Preview newsletter
		$return = Message::generate() . '
<div id="tl_buttons">
<a href="'.$this->getReferer(true).'" class="header_back" title="'.StringUtil::specialchars($GLOBALS['TL_LANG']['MSC']['backBTTitle']).'" accesskey="b">'.$GLOBALS['TL_LANG']['MSC']['backBT'].'</a>
</div>
<form action="'.TL_SCRIPT.'" id="tl_newsletter_send" class="tl_form tl_edit_form" method="get">
<div class="tl_formbody_edit tl_newsletter_send">
<input type="hidden" name="do" value="' . Input::get('do') . '">
<input type="hidden" name="table" value="' . Input::get('table') . '">
<input type="hidden" name="key" value="' . Input::get('key') . '">
<input type="hidden" name="id" value="' . Input::get('id') . '">
<input type="hidden" name="token" value="' . $strToken . '">
<table class="prev_header">
  <tr class="row_0">
    <td class="col_0">' . $GLOBALS['TL_LANG']['tl_newsletter']['from'] . '</td>
    <td class="col_1">' . sprintf($sprintf, Idna::decodeEmail($objNewsletter->sender)) . '</td>
  </tr>
  <tr class="row_1">
    <td class="col_0">' . $GLOBALS['TL_LANG']['tl_newsletter']['subject'][0] . '</td>
    <td class="col_1">' . $objNewsletter->subject . '</td>
  </tr>
  <tr class="row_2">
    <td class="col_0">' . $GLOBALS['TL_LANG']['tl_newsletter']['template'][0] . '</td>
    <td class="col_1">' . $objNewsletter->template . '</td>
  </tr>' . ((!empty($arrAttachments) && \is_array($arrAttachments)) ? '
  <tr class="row_3">
    <td class="col_0">' . $GLOBALS['TL_LANG']['tl_newsletter']['attachments'] . '</td>
    <td class="col_1">' . implode(', ', $arrAttachments) . '</td>
  </tr>' : '') . '
</table>' . (!$objNewsletter->sendText ? '
<div class="preview_html">
' . $html . '
</div>' : '') . '
<div class="preview_text">
<pre style="white-space:pre-wrap">' . $text . '</pre>
</div>

<fieldset class="tl_tbox nolegend">
<div class="w50 widget">
  <h3><label for="ctrl_mpc">' . $GLOBALS['TL_LANG']['tl_newsletter']['mailsPerCycle'][0] . '</label></h3>
  <input type="text" name="mpc" id="ctrl_mpc" value="10" class="tl_text" onfocus="Backend.getScrollOffset()">' . (($GLOBALS['TL_LANG']['tl_newsletter']['mailsPerCycle'][1] && Config::get('showHelp')) ? '
  <p class="tl_help tl_tip">' . $GLOBALS['TL_LANG']['tl_newsletter']['mailsPerCycle'][1] . '</p>' : '') . '
</div>
<div class="w50 widget">
  <h3><label for="ctrl_timeout">' . $GLOBALS['TL_LANG']['tl_newsletter']['timeout'][0] . '</label></h3>
  <input type="text" name="timeout" id="ctrl_timeout" value="1" class="tl_text" onfocus="Backend.getScrollOffset()">' . (($GLOBALS['TL_LANG']['tl_newsletter']['timeout'][1] && Config::get('showHelp')) ? '
  <p class="tl_help tl_tip">' . $GLOBALS['TL_LANG']['tl_newsletter']['timeout'][1] . '</p>' : '') . '
</div>
<div class="w50 widget">
  <h3><label for="ctrl_start">' . $GLOBALS['TL_LANG']['tl_newsletter']['start'][0] . '</label></h3>
  <input type="text" name="start" id="ctrl_start" value="0" class="tl_text" onfocus="Backend.getScrollOffset()">' . (($GLOBALS['TL_LANG']['tl_newsletter']['start'][1] && Config::get('showHelp')) ? '
  <p class="tl_help tl_tip">' . sprintf($GLOBALS['TL_LANG']['tl_newsletter']['start'][1], $objNewsletter->id) . '</p>' : '') . '
</div>
<div class="w50 widget">
  <h3><label for="ctrl_recipient">' . $GLOBALS['TL_LANG']['tl_newsletter']['sendPreviewTo'][0] . '</label></h3>
  <input type="text" name="recipient" id="ctrl_recipient" value="'.Idna::decodeEmail($this->User->email).'" class="tl_text" onfocus="Backend.getScrollOffset()">' . (isset($_SESSION['TL_PREVIEW_MAIL_ERROR']) ? '
  <div class="tl_error">' . $GLOBALS['TL_LANG']['ERR']['email'] . '</div>' : (($GLOBALS['TL_LANG']['tl_newsletter']['sendPreviewTo'][1] && Config::get('showHelp')) ? '
  <p class="tl_help tl_tip">' . $GLOBALS['TL_LANG']['tl_newsletter']['sendPreviewTo'][1] . '</p>' : '')) . '
</div>
</fieldset>
</div>';

		$return .= '

<div class="tl_formbody_submit">
<div class="tl_submit_container">
<button type="submit" name="preview" class="tl_submit" accesskey="p">'.$GLOBALS['TL_LANG']['tl_newsletter']['preview'].'</button>
<button type="submit" id="send" class="tl_submit" accesskey="s" onclick="return confirm(\''. str_replace("'", "\\'", $GLOBALS['TL_LANG']['tl_newsletter']['sendConfirm']) .'\')">'.$GLOBALS['TL_LANG']['tl_newsletter']['send'][0].'</button>
</div>
</div>

</form>';

		unset($_SESSION['TL_PREVIEW_MAIL_ERROR']);

		return $return;
	}
public function send ( DataContainer $ dc ) { $ objNewsletter = $ this -> Database -> prepare ( "SELECT n.*, c.template AS channelTemplate, c.sender AS channelSender, c.senderName as channelSenderName FROM tl_newsletter n LEFT JOIN tl_newsletter_channel c ON n.pid=c.id WHERE n.id=?" ) -> limit ( 1 ) -> execute ( $ dc -> id ) ; // Return if there is no newsletter if ( $ objNewsletter -> numRows < 1 ) { return '' ; } // Set the template if ( $ objNewsletter -> template == '' ) { $ objNewsletter -> template = $ objNewsletter -> channelTemplate ; } // Set the sender address if ( $ objNewsletter -> sender == '' ) { $ objNewsletter -> sender = $ objNewsletter -> channelSender ; } // Set the sender name if ( $ objNewsletter -> senderName == '' ) { $ objNewsletter -> senderName = $ objNewsletter -> channelSenderName ; } // No sender address given if ( $ objNewsletter -> sender == '' ) { throw new InternalServerErrorException ( 'No sender address given. Please check the newsletter channel settings.' ) ; } $ arrAttachments = array ( ) ; // Add attachments if ( $ objNewsletter -> addFile ) { $ files = StringUtil :: deserialize ( $ objNewsletter -> files ) ; if ( ! empty ( $ files ) && \ is_array ( $ files ) ) { $ objFiles = FilesModel :: findMultipleByUuids ( $ files ) ; if ( $ objFiles !== null ) { $ rootDir = System :: getContainer ( ) -> getParameter ( 'kernel.project_dir' ) ; while ( $ objFiles -> next ( ) ) { if ( is_file ( $ rootDir . '/' . $ objFiles -> path ) ) { $ arrAttachments [ ] = $ objFiles -> path ; } } } } } // Replace insert tags $ html = $ this -> replaceInsertTags ( $ objNewsletter -> content , false ) ; $ text = $ this -> replaceInsertTags ( $ objNewsletter -> text , false ) ; // Convert relative URLs if ( $ objNewsletter -> externalImages ) { $ html = $ this -> convertRelativeUrls ( $ html ) ; } /** @var Session $objSession */ $ objSession = System :: getContainer ( ) -> get ( 'session' ) ; // Send newsletter if ( Input :: get ( 'token' ) != '' && Input :: get ( 'token' ) == $ objSession -> get ( 'tl_newsletter_send' ) ) { $ referer = preg_replace ( '/&(amp;)?(start|mpc|token|recipient|preview)=[^&]*/' , '' , Environment :: get ( 'request' ) ) ; // Preview if ( isset ( $ _GET [ 'preview' ] ) ) { // Check the e-mail address if ( ! Validator :: isEmail ( Input :: get ( 'recipient' , true ) ) ) { $ _SESSION [ 'TL_PREVIEW_MAIL_ERROR' ] = true ; $ this -> redirect ( $ referer ) ; } $ arrRecipient [ 'email' ] = urldecode ( Input :: get ( 'recipient' , true ) ) ; // Send $ objEmail = $ this -> generateEmailObject ( $ objNewsletter , $ arrAttachments ) ; $ this -> sendNewsletter ( $ objEmail , $ objNewsletter , $ arrRecipient , $ text , $ html ) ; // Redirect Message :: addConfirmation ( sprintf ( $ GLOBALS [ 'TL_LANG' ] [ 'tl_newsletter' ] [ 'confirm' ] , 1 ) ) ; $ this -> redirect ( $ referer ) ; } // Get the total number of recipients $ objTotal = $ this -> Database -> prepare ( "SELECT COUNT(DISTINCT email) AS count FROM tl_newsletter_recipients WHERE pid=? AND active=1" ) -> execute ( $ objNewsletter -> pid ) ; // Return if there are no recipients if ( $ objTotal -> count < 1 ) { $ objSession -> set ( 'tl_newsletter_send' , null ) ; Message :: addError ( $ GLOBALS [ 'TL_LANG' ] [ 'tl_newsletter' ] [ 'error' ] ) ; $ this -> redirect ( $ referer ) ; } $ intTotal = $ objTotal -> count ; // Get page and timeout $ intTimeout = ( Input :: get ( 'timeout' ) > 0 ) ? Input :: get ( 'timeout' ) : 1 ; $ intStart = Input :: get ( 'start' ) ? : 0 ; $ intPages = Input :: get ( 'mpc' ) ? : 10 ; // Get recipients $ objRecipients = $ this -> Database -> prepare ( "SELECT *, r.email FROM tl_newsletter_recipients r LEFT JOIN tl_member m ON(r.email=m.email) WHERE r.pid=? AND r.active=1 ORDER BY r.email" ) -> limit ( $ intPages , $ intStart ) -> execute ( $ objNewsletter -> pid ) ; echo '<div style="font-family:Verdana,sans-serif;font-size:11px;line-height:16px;margin-bottom:12px">' ; // Send newsletter if ( $ objRecipients -> numRows > 0 ) { // Update status if ( $ intStart == 0 ) { $ this -> Database -> prepare ( "UPDATE tl_newsletter SET sent='1', date=? WHERE id=?" ) -> execute ( time ( ) , $ objNewsletter -> id ) ; $ _SESSION [ 'REJECTED_RECIPIENTS' ] = array ( ) ; } while ( $ objRecipients -> next ( ) ) { // Skip the recipient if the member is not active (see #8812) if ( $ objRecipients -> id !== null && ( $ objRecipients -> disable || ( $ objRecipients -> start != '' && $ objRecipients -> start > time ( ) ) || ( $ objRecipients -> stop != '' && $ objRecipients -> stop < time ( ) ) ) ) { -- $ intTotal ; echo 'Skipping <strong>' . Idna :: decodeEmail ( $ objRecipients -> email ) . '</strong> as the member is not active<br>' ; continue ; } $ objEmail = $ this -> generateEmailObject ( $ objNewsletter , $ arrAttachments ) ; $ this -> sendNewsletter ( $ objEmail , $ objNewsletter , $ objRecipients -> row ( ) , $ text , $ html ) ; echo 'Sending newsletter to <strong>' . Idna :: decodeEmail ( $ objRecipients -> email ) . '</strong><br>' ; } } echo '<div style="margin-top:12px">' ; // Redirect back home if ( $ objRecipients -> numRows < 1 || ( $ intStart + $ intPages ) >= $ intTotal ) { $ objSession -> set ( 'tl_newsletter_send' , null ) ; // Deactivate rejected addresses if ( ! empty ( $ _SESSION [ 'REJECTED_RECIPIENTS' ] ) ) { $ intRejected = \ count ( $ _SESSION [ 'REJECTED_RECIPIENTS' ] ) ; Message :: addInfo ( sprintf ( $ GLOBALS [ 'TL_LANG' ] [ 'tl_newsletter' ] [ 'rejected' ] , $ intRejected ) ) ; $ intTotal -= $ intRejected ; foreach ( $ _SESSION [ 'REJECTED_RECIPIENTS' ] as $ strRecipient ) { $ this -> Database -> prepare ( "UPDATE tl_newsletter_recipients SET active='' WHERE email=?" ) -> execute ( $ strRecipient ) ; $ this -> log ( 'Recipient address "' . Idna :: decodeEmail ( $ strRecipient ) . '" was rejected and has been deactivated' , __METHOD__ , TL_ERROR ) ; } } Message :: addConfirmation ( sprintf ( $ GLOBALS [ 'TL_LANG' ] [ 'tl_newsletter' ] [ 'confirm' ] , $ intTotal ) ) ; echo '<script>setTimeout(\'window.location="' . Environment :: get ( 'base' ) . $ referer . '"\',1000)</script>' ; echo '<a href="' . Environment :: get ( 'base' ) . $ referer . '">Please click here to proceed if you are not using JavaScript</a>' ; } // Redirect to the next cycle else { $ url = preg_replace ( '/&(amp;)?(start|mpc|recipient)=[^&]*/' , '' , Environment :: get ( 'request' ) ) . '&start=' . ( $ intStart + $ intPages ) . '&mpc=' . $ intPages ; echo '<script>setTimeout(\'window.location="' . Environment :: get ( 'base' ) . $ url . '"\',' . ( $ intTimeout * 1000 ) . ')</script>' ; echo '<a href="' . Environment :: get ( 'base' ) . $ url . '">Please click here to proceed if you are not using JavaScript</a>' ; } echo '</div></div>' ; exit ; } $ strToken = md5 ( uniqid ( mt_rand ( ) , true ) ) ; $ objSession -> set ( 'tl_newsletter_send' , $ strToken ) ; $ sprintf = ( $ objNewsletter -> senderName != '' ) ? $ objNewsletter -> senderName . ' &lt;%s&gt;' : '%s' ; $ this -> import ( BackendUser :: class , 'User' ) ; // Preview newsletter $ return = Message :: generate ( ) . '
<div id="tl_buttons">
<a href="' . $ this -> getReferer ( true ) . '" class="header_back" title="' . StringUtil :: specialchars ( $ GLOBALS [ 'TL_LANG' ] [ 'MSC' ] [ 'backBTTitle' ] ) . '" accesskey="b">' . $ GLOBALS [ 'TL_LANG' ] [ 'MSC' ] [ 'backBT' ] . '</a>
</div>
<form action="' . TL_SCRIPT . '" id="tl_newsletter_send" class="tl_form tl_edit_form" method="get">
<div class="tl_formbody_edit tl_newsletter_send">
<input type="hidden" name="do" value="' . Input :: get ( 'do' ) . '">
<input type="hidden" name="table" value="' . Input :: get ( 'table' ) . '">
<input type="hidden" name="key" value="' . Input :: get ( 'key' ) . '">
<input type="hidden" name="id" value="' . Input :: get ( 'id' ) . '">
<input type="hidden" name="token" value="' . $ strToken . '">
<table class="prev_header">
  <tr class="row_0">
    <td class="col_0">' . $ GLOBALS [ 'TL_LANG' ] [ 'tl_newsletter' ] [ 'from' ] . '</td>
    <td class="col_1">' . sprintf ( $ sprintf , Idna :: decodeEmail ( $ objNewsletter -> sender ) ) . '</td>
  </tr>
  <tr class="row_1">
    <td class="col_0">' . $ GLOBALS [ 'TL_LANG' ] [ 'tl_newsletter' ] [ 'subject' ] [ 0 ] . '</td>
    <td class="col_1">' . $ objNewsletter -> subject . '</td>
  </tr>
  <tr class="row_2">
    <td class="col_0">' . $ GLOBALS [ 'TL_LANG' ] [ 'tl_newsletter' ] [ 'template' ] [ 0 ] . '</td>
    <td class="col_1">' . $ objNewsletter -> template . '</td>
  </tr>' . ( ( ! empty ( $ arrAttachments ) && \ is_array ( $ arrAttachments ) ) ? '
  <tr class="row_3">
    <td class="col_0">' . $ GLOBALS [ 'TL_LANG' ] [ 'tl_newsletter' ] [ 'attachments' ] . '</td>
    <td class="col_1">' . implode ( ', ' , $ arrAttachments ) . '</td>
  </tr>' : '' ) . '
</table>' . ( ! $ objNewsletter -> sendText ? '
<div class="preview_html">
' . $ html . '
</div>' : '' ) . '
<div class="preview_text">
<pre style="white-space:pre-wrap">' . $ text . '</pre>
</div>

<fieldset class="tl_tbox nolegend">
<div class="w50 widget">
  <h3><label for="ctrl_mpc">' . $ GLOBALS [ 'TL_LANG' ] [ 'tl_newsletter' ] [ 'mailsPerCycle' ] [ 0 ] . '</label></h3>
  <input type="text" name="mpc" id="ctrl_mpc" value="10" class="tl_text" onfocus="Backend.getScrollOffset()">' . ( ( $ GLOBALS [ 'TL_LANG' ] [ 'tl_newsletter' ] [ 'mailsPerCycle' ] [ 1 ] && Config :: get ( 'showHelp' ) ) ? '
  <p class="tl_help tl_tip">' . $ GLOBALS [ 'TL_LANG' ] [ 'tl_newsletter' ] [ 'mailsPerCycle' ] [ 1 ] . '</p>' : '' ) . '
</div>
<div class="w50 widget">
  <h3><label for="ctrl_timeout">' . $ GLOBALS [ 'TL_LANG' ] [ 'tl_newsletter' ] [ 'timeout' ] [ 0 ] . '</label></h3>
  <input type="text" name="timeout" id="ctrl_timeout" value="1" class="tl_text" onfocus="Backend.getScrollOffset()">' . ( ( $ GLOBALS [ 'TL_LANG' ] [ 'tl_newsletter' ] [ 'timeout' ] [ 1 ] && Config :: get ( 'showHelp' ) ) ? '
  <p class="tl_help tl_tip">' . $ GLOBALS [ 'TL_LANG' ] [ 'tl_newsletter' ] [ 'timeout' ] [ 1 ] . '</p>' : '' ) . '
</div>
<div class="w50 widget">
  <h3><label for="ctrl_start">' . $ GLOBALS [ 'TL_LANG' ] [ 'tl_newsletter' ] [ 'start' ] [ 0 ] . '</label></h3>
  <input type="text" name="start" id="ctrl_start" value="0" class="tl_text" onfocus="Backend.getScrollOffset()">' . ( ( $ GLOBALS [ 'TL_LANG' ] [ 'tl_newsletter' ] [ 'start' ] [ 1 ] && Config :: get ( 'showHelp' ) ) ? '
  <p class="tl_help tl_tip">' . sprintf ( $ GLOBALS [ 'TL_LANG' ] [ 'tl_newsletter' ] [ 'start' ] [ 1 ] , $ objNewsletter -> id ) . '</p>' : '' ) . '
</div>
<div class="w50 widget">
  <h3><label for="ctrl_recipient">' . $ GLOBALS [ 'TL_LANG' ] [ 'tl_newsletter' ] [ 'sendPreviewTo' ] [ 0 ] . '</label></h3>
  <input type="text" name="recipient" id="ctrl_recipient" value="' . Idna :: decodeEmail ( $ this -> User -> email ) . '" class="tl_text" onfocus="Backend.getScrollOffset()">' . ( isset ( $ _SESSION [ 'TL_PREVIEW_MAIL_ERROR' ] ) ? '
  <div class="tl_error">' . $ GLOBALS [ 'TL_LANG' ] [ 'ERR' ] [ 'email' ] . '</div>' : ( ( $ GLOBALS [ 'TL_LANG' ] [ 'tl_newsletter' ] [ 'sendPreviewTo' ] [ 1 ] && Config :: get ( 'showHelp' ) ) ? '
  <p class="tl_help tl_tip">' . $ GLOBALS [ 'TL_LANG' ] [ 'tl_newsletter' ] [ 'sendPreviewTo' ] [ 1 ] . '</p>' : '' ) ) . '
</div>
</fieldset>
</div>' ; $ return .= '

<div class="tl_formbody_submit">
<div class="tl_submit_container">
<button type="submit" name="preview" class="tl_submit" accesskey="p">' . $ GLOBALS [ 'TL_LANG' ] [ 'tl_newsletter' ] [ 'preview' ] . '</button>
<button type="submit" id="send" class="tl_submit" accesskey="s" onclick="return confirm(\'' . str_replace ( "'" , "\\'" , $ GLOBALS [ 'TL_LANG' ] [ 'tl_newsletter' ] [ 'sendConfirm' ] ) . '\')">' . $ GLOBALS [ 'TL_LANG' ] [ 'tl_newsletter' ] [ 'send' ] [ 0 ] . '</button>
</div>
</div>

</form>' ; unset ( $ _SESSION [ 'TL_PREVIEW_MAIL_ERROR' ] ) ; return $ return ; }
Return a form to choose an existing CSV file and import it

@param DataContainer $dc

@return string
Return a form to choose an existing CSV file and import it