Example #1
0
 public function testCreateAllSpool()
 {
     $this->importDataSet(ORIGINAL_ROOT . 'typo3/sysext/core/Tests/Functional/Fixtures/tt_content.xml');
     $db = $this->getDatabaseConnection();
     $count = $db->exec_SELECTcountRows('*', 'tx_newsletter_domain_model_newsletter', 'begin_time != 0 AND end_time != 0');
     $this->assertSame(0, $count);
     Tools::createAllSpool();
     $count = $db->exec_SELECTcountRows('*', 'tx_newsletter_domain_model_newsletter', 'begin_time != 0 AND end_time != 0');
     $this->assertSame(1, $count, 'newsletter should be marked as spooled');
     $count = $db->exec_SELECTcountRows('*', 'tx_newsletter_domain_model_email', 'newsletter = 20 AND begin_time = 0');
     $this->assertSame(2, $count, 'two emails must have been created but not sent yet');
     $lastInsertedEmail = $db->exec_SELECTgetSingleRow('*', 'tx_newsletter_domain_model_email', 'newsletter = 20 AND begin_time = 0');
     $this->assertNotSame(md5('0' . $lastInsertedEmail['recipient_address']), $lastInsertedEmail['auth_code'], 'the UID used in authCode must never be 0');
     $this->assertSame(md5($lastInsertedEmail['uid'] . $lastInsertedEmail['recipient_address']), $lastInsertedEmail['auth_code'], 'the UID used in authCode should be the real value');
     // Prepare a mock to always validate content
     /** @var \Ecodev\Newsletter\Utility\Validator|\PHPUnit_Framework_MockObject_MockObject $mockValidator */
     $mockValidator = $this->getMock(\Ecodev\Newsletter\Utility\Validator::class, ['validate'], [], '', false);
     $mockValidator->method('validate')->will($this->returnValue(['content' => 'some very interesting content <a href="http://example.com/fake-content">link</a>', 'errors' => [], 'warnings' => [], 'infos' => []]));
     // Force email to NOT be sent
     global $TYPO3_CONF_VARS;
     $TYPO3_CONF_VARS['MAIL']['transport'] = 'Swift_NullTransport';
     /** @var \Ecodev\Newsletter\Domain\Repository\NewsletterRepository $newsletterRepository */
     $newsletterRepository = $this->objectManager->get(\Ecodev\Newsletter\Domain\Repository\NewsletterRepository::class);
     $newsletter = $newsletterRepository->findByUid(20);
     $newsletter->setValidator($mockValidator);
     Tools::runSpool($newsletter);
     $count = $db->exec_SELECTcountRows('*', 'tx_newsletter_domain_model_email', 'newsletter = 20 AND begin_time != 0 AND end_time != 0 AND recipient_data != ""');
     $this->assertSame(2, $count, 'should have sent two emails');
     $count = $db->exec_SELECTcountRows('*', 'tx_newsletter_domain_model_link', 'newsletter = 20');
     $this->assertSame(1, $count, 'should have on1 new link');
 }
Example #2
0
 public function testCreateAllSpool()
 {
     $this->importDataSet(ORIGINAL_ROOT . 'typo3/sysext/core/Tests/Functional/Fixtures/tt_content.xml');
     $db = $this->getDatabaseConnection();
     $count = $db->exec_SELECTcountRows('*', 'tx_newsletter_domain_model_newsletter', 'begin_time != 0 AND end_time != 0');
     $this->assertEquals(0, $count);
     \Ecodev\Newsletter\Tools::createAllSpool();
     $count = $db->exec_SELECTcountRows('*', 'tx_newsletter_domain_model_newsletter', 'begin_time != 0 AND end_time != 0');
     $this->assertEquals(1, $count, 'newsletter should be marked as spooled');
     $count = $db->exec_SELECTcountRows('*', 'tx_newsletter_domain_model_email', 'newsletter = 20 AND begin_time = 0');
     $this->assertEquals(2, $count, 'two emails must have been created but not sent yet');
     // Prepare a mock to always validate content
     $mockValidator = $this->getMock('Ecodev\\Newsletter\\Utility\\Validator', array('validate'), array(), '', false);
     $mockValidator->method('validate')->will($this->returnValue(array('content' => 'some very interesting content <a href="http://example.com/fake-content">link</a>', 'errors' => array(), 'warnings' => array(), 'infos' => array())));
     // Force email to NOT be sent
     global $TYPO3_CONF_VARS;
     $TYPO3_CONF_VARS['MAIL']['transport'] = 'Swift_NullTransport';
     $newsletterRepository = $this->objectManager->get('Ecodev\\Newsletter\\Domain\\Repository\\NewsletterRepository');
     $newsletter = $newsletterRepository->findByUid(20);
     $newsletter->setValidator($mockValidator);
     \Ecodev\Newsletter\Tools::runSpool($newsletter);
     $count = $db->exec_SELECTcountRows('*', 'tx_newsletter_domain_model_email', 'newsletter = 20 AND begin_time != 0 AND end_time != 0 AND recipient_data != ""');
     $this->assertEquals(2, $count, 'should have sent two emails');
     $count = $db->exec_SELECTcountRows('*', 'tx_newsletter_domain_model_link', 'newsletter = 20');
     $this->assertEquals(1, $count, 'should have on1 new link');
 }
Example #3
0
 /**
  * Creates the remote api based on the module/plugin configuration using the extbase
  * reflection features.
  *
  * @param string $routeUrl
  * @param string $namespace
  * @return array
  */
 public function createApi($routeUrl, $namespace)
 {
     $api = [];
     $api['url'] = $routeUrl;
     $api['type'] = 'remoting';
     $api['namespace'] = $namespace;
     $api['actions'] = [];
     if (empty($this->frameworkConfiguration['controllerConfiguration'])) {
         # @todo improve me! Hack for fetching API of newsletter the hard way!
         # It looks $this->frameworkConfiguration['controllerConfiguration'] is empty as of TYPO3 6.1. Bug or feature?
         $this->frameworkConfiguration['controllerConfiguration'] = $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['extbase']['extensions']['Newsletter']['modules']['web_NewsletterTxNewsletterM1']['controllers'];
     }
     foreach ($this->frameworkConfiguration['controllerConfiguration'] as $controllerName => $allowedControllerActions) {
         $unstrippedControllerName = $controllerName . 'Controller';
         $controllerObjectName = 'Ecodev\\Newsletter\\Controller\\' . $unstrippedControllerName;
         $controllerActions = [];
         foreach ($allowedControllerActions['actions'] as $actionName) {
             $unstrippedActionName = $actionName . 'Action';
             try {
                 $actionParameters = $this->reflectionService->getMethodParameters($controllerObjectName, $unstrippedActionName);
                 $controllerActions[] = ['len' => count($actionParameters), 'name' => $unstrippedActionName];
             } catch (ReflectionException $re) {
                 if ($unstrippedActionName !== 'extObjAction') {
                     \Ecodev\Newsletter\Tools::getLogger(__CLASS__)->critical('You have a not existing action (' . $controllerObjectName . '::' . $unstrippedActionName . ') in your module/plugin configuration. This action will not be available for Ext.Direct remote execution.');
                 }
             }
         }
         $api['actions'][$unstrippedControllerName] = $controllerActions;
     }
     return $api;
 }
Example #4
0
 public function testEncryption()
 {
     $GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey'] = 'encryptionKeyValue';
     $encrypted = Tools::encrypt('my value');
     $this->assertNotSame('my value', $encrypted, 'must be encrypted');
     $decrypted = Tools::decrypt($encrypted);
     $this->assertSame('my value', $decrypted, 'must be original value');
 }
Example #5
0
 /**
  * @test
  */
 public function getUrlReturnsInitialValueForString()
 {
     if (!$this->canRunLynx()) {
         $this->markTestSkipped('The command "' . Tools::confParam('path_to_lynx') . '" is not available.');
     }
     $html = file_get_contents(__DIR__ . '/input.html');
     $expected = file_get_contents(__DIR__ . '/lynx.txt');
     $actual = $this->subject->getPlainText($html, 'http://my-domain.com');
     $this->assertSame($expected, $actual);
 }
Example #6
0
 public function getPlainText($content, $baseUrl)
 {
     $tmpFile = tempnam(sys_get_temp_dir(), 'newsletter_');
     $contentWithBase = $this->injectBaseUrl($content, $baseUrl);
     file_put_contents($tmpFile, $contentWithBase);
     $cmd = escapeshellcmd(Tools::confParam('path_to_lynx')) . ' -force_html -dump ' . escapeshellarg($tmpFile);
     exec($cmd, $output);
     unlink($tmpFile);
     $plainText = implode("\n", $output);
     return $plainText;
 }
 /**
  * index action for the module controller
  * This will render the HTML needed for ExtJS application
  *
  * @return void
  */
 public function indexAction()
 {
     $pageType = '';
     $record = $GLOBALS['TYPO3_DB']->exec_SELECTgetSingleRow('doktype', 'pages', 'uid =' . $this->pageId);
     if (!empty($record['doktype']) && $record['doktype'] == 254) {
         $pageType = 'folder';
     } elseif (!empty($record['doktype'])) {
         $pageType = 'page';
     }
     $configuration = array('pageId' => $this->pageId, 'pageType' => $pageType, 'emailShowUrl' => Tools::buildFrontendUri('show', array(), 'Email'));
     $this->view->assign('configuration', $configuration);
 }
Example #8
0
 /**
  * Returns the decrypted field value if set.
  * @param array $PA Parameter Array
  * @return string
  */
 public static function getDecryptedFieldValue($field, $value)
 {
     $default = @$GLOBALS['TCA']['tx_newsletter_domain_model_bounceaccount']['columns'][$field]['config']['default'];
     // Set the value
     if (empty($value)) {
         if ($default) {
             $value = $default;
         }
     } elseif ($value != $default) {
         $value = \Ecodev\Newsletter\Tools::decrypt($value);
     }
     return $value;
 }
Example #9
0
 /**
  * This method is designed to return some additional information about the task,
  * that may help to set it apart from other tasks from the same class
  * This additional information is used - for example - in the Scheduler's BE module
  * This method should be implemented in most task classes
  *
  * @return	string	Information to display
  */
 public function getAdditionalInformation()
 {
     $objectManager = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Extbase\Object\ObjectManager::class);
     $newsletterRepository = $objectManager->get(\Ecodev\Newsletter\Domain\Repository\NewsletterRepository::class);
     $newslettersToSend = $newsletterRepository->findAllReadyToSend();
     $newslettersBeingSent = $newsletterRepository->findAllBeingSent();
     $newslettersToSendCount = count($newslettersToSend);
     $newslettersBeingSentCount = count($newslettersBeingSent);
     $emailNotSentCount = 0;
     foreach ($newslettersToSend as $newsletter) {
         $emailNotSentCount += $newsletter->getEmailNotSentCount();
     }
     foreach ($newslettersBeingSent as $newsletter) {
         $emailNotSentCount += $newsletter->getEmailNotSentCount();
     }
     $emailsPerRound = Tools::confParam('mails_per_round');
     return \TYPO3\CMS\Extbase\Utility\LocalizationUtility::translate('task_send_emails_additional_information', 'newsletter', [$emailsPerRound, $emailNotSentCount, $newslettersToSendCount, $newslettersBeingSentCount]);
 }
Example #10
0
 public function init()
 {
     $this->data = array();
     $content = \Ecodev\Newsletter\Tools::getUrl($this->getHtmlUrl());
     switch ($this->getHtmlFetchType()) {
         case 'mailto':
             preg_match_all('|<a[^>]+href="mailto:([^"]+)"[^>]*>(.*)</a>|Ui', $content, $fetched_data);
             foreach ($fetched_data[1] as $i => $email) {
                 $this->data[] = array('email' => $email, 'name' => $fetched_data[2][$i]);
             }
             break;
         case 'regex':
         default:
             preg_match_all("|[\\.a-z0-9!#\$%&'*+-/=?^_`{\\|}]+@[a-z0-9_-][\\.a-z0-9_-]*\\.[a-z]{2,}|i", $content, $fetched_data);
             foreach ($fetched_data[0] as $address) {
                 $this->data[]['email'] = $address;
             }
     }
 }
Example #11
0
 /**
  * Dispatch actions to take according to current bounce level
  */
 public function dispatch()
 {
     $this->findEmail();
     // If couldn't find the original email we cannot do anything
     if (!$this->email) {
         Tools::getLogger(__CLASS__)->warning('Bounced email found but cannot find corresponding record in database. Skipped.');
         return;
     }
     $bounceLevel = $this->emailParser->getBounceLevel();
     if ($bounceLevel != EmailParser::NEWSLETTER_NOT_A_BOUNCE) {
         if ($this->recipientList) {
             $this->recipientList->registerBounce($this->email->getRecipientAddress(), $bounceLevel);
         }
         $this->email->setBounceTime(new DateTime());
         $emailRepository = $this->objectManager->get(\Ecodev\Newsletter\Domain\Repository\EmailRepository::class);
         $emailRepository->updateNow($this->email);
     }
     Tools::getLogger(__CLASS__)->info('Bounced email found with bounce level ' . $bounceLevel);
 }
 /**
  * Return all markers and their values as associative array
  * @param Email $email
  * @return string[]
  */
 private function getMarkers(Email $email)
 {
     $markers = $email->getRecipientData();
     // Add predefined markers
     $authCode = $email->getAuthCode();
     $markers['newsletter_view_url'] = Tools::buildFrontendUri('show', array('c' => $authCode), 'Email');
     $markers['newsletter_unsubscribe_url'] = Tools::buildFrontendUri('unsubscribe', array('c' => $authCode), 'Email');
     return $markers;
 }
Example #13
0
 /**
  * Dispatch actions to take according to current bounce level
  */
 public function dispatch()
 {
     $this->findEmail();
     // If couldn't find the original email we cannot do anything
     if (!$this->email) {
         Tools::log("Bounced email found but cannot find corresponding record in database. Skipped.", 1);
         return;
     }
     if ($this->bounceLevel != self::NEWSLETTER_NOT_A_BOUNCE) {
         if ($this->recipientList) {
             $this->recipientList->registerBounce($this->email->getRecipientAddress(), $this->bounceLevel);
         }
         $this->email->setBounceTime(new DateTime());
         $emailRepository = $this->objectManager->get('Ecodev\\Newsletter\\Domain\\Repository\\EmailRepository');
         $emailRepository->updateNow($this->email);
     }
     Tools::log("Bounced email found with bounce level " . $this->bounceLevel);
 }
Example #14
0
 /**
  * Replace all links in the mail to make spy links.
  *
  * @param \Ecodev\Newsletter\Domain\Model\Email $email The email to prepare the newsletter for
  * @param bool $isPreview whether we are preparing a preview version (if true links will not be stored in database thus no statistics will be available)
  */
 private function injectLinksSpy(Email $email, $isPreview)
 {
     /* Exchange all http:// links  html */
     preg_match_all('|<a [^>]*href="(https?://[^"]*)"|Ui', $this->html, $urls);
     // No-Track Marker
     $notrackMarker = Tools::confParam('no-track');
     foreach ($urls[1] as $i => $url) {
         // Check for a no-track marker
         if (!empty($notrackMarker) && stripos($url, $notrackMarker) != false) {
             continue;
         }
         $newUrl = $this->getLinkAuthCode($email, $url, $isPreview);
         /* Two step replace to be as precise as possible */
         $link = str_replace($url, $newUrl, $urls[0][$i]);
         $this->html = str_replace($urls[0][$i], $link, $this->html);
     }
 }
Example #15
0
 private function getLinkAuthCode(Email $email, $url, $isPreview, $isPlainText = false)
 {
     global $TYPO3_DB;
     $url = html_entity_decode($url);
     // First check in our local cache
     if (isset($this->linksCache[$url])) {
         $linkId = $this->linksCache[$url];
     } elseif ($isPreview) {
         $linkId = count($this->linksCache);
     } else {
         // Look for the link database, it may already exist
         $res = $TYPO3_DB->sql_query('SELECT uid FROM tx_newsletter_domain_model_link WHERE url = ' . $TYPO3_DB->fullQuoteStr($url, 'tx_newsletter_domain_model_link') . ' AND newsletter = ' . $TYPO3_DB->fullQuoteStr($this->newsletter->getUid(), 'tx_newsletter_domain_model_link') . ' LIMIT 1');
         $row = $TYPO3_DB->sql_fetch_row($res);
         if ($row) {
             $linkId = $row[0];
         } else {
             $TYPO3_DB->exec_INSERTquery('tx_newsletter_domain_model_link', array('pid' => $this->newsletter->getPid(), 'url' => $url, 'newsletter' => $this->newsletter->getUid()));
             $linkId = $TYPO3_DB->sql_insert_id();
         }
     }
     // Store link in cache
     $this->linksCache[$url] = $linkId;
     $authCode = md5($email->getAuthCode() . $linkId);
     $newUrl = Tools::buildFrontendUri('clicked', array(), 'Link') . '&n=' . $this->newsletter->getUid() . '&l=' . $authCode . ($isPlainText ? '&p=1' : '');
     return $newUrl;
 }
Example #16
0
 /**
  * Return the content of the given URL
  * @param string $url
  * @return string
  */
 protected function getURL($url)
 {
     return \Ecodev\Newsletter\Tools::getUrl($url);
 }
Example #17
0
    /**
     * Return HTML code showing an extract of recipients (first X recipients)
     */
    public function getExtract($limit = 30)
    {
        if ($this->getError()) {
            $out = 'Error: ' . $this->getError();
        } else {
            $i = 0;
            while ($row = $this->getRecipient()) {
                // Dump formatted table header
                if ($i == 0) {
                    $out .= '<tr>';
                    foreach (array_keys($row) as $key) {
                        $out .= '<th style="padding-right: 1em;">' . $this->getFieldTitle($key) . '</th>';
                    }
                    $out .= '</tr>';
                }
                $out .= '<tr style="border: 1px grey solid; border-collapse: collapse;">';
                foreach ($row as $field) {
                    $out .= '<td style="padding-right: 1em;">' . $field . '</td>';
                }
                $out .= '</tr>';
                if (++$i == $limit) {
                    break;
                }
            }
            $out = '<table style="border: 1px grey solid; border-collapse: collapse;">' . $out . '</table>';
            $authCode = \TYPO3\CMS\Core\Utility\GeneralUtility::stdAuthCode($this->_getCleanProperties());
            $uriXml = Tools::buildFrontendUri('export', array('uidRecipientList' => $this->getUid(), 'authCode' => $authCode, 'format' => 'xml'), 'RecipientList');
            $uriCsv = Tools::buildFrontendUri('export', array('uidRecipientList' => $this->getUid(), 'authCode' => $authCode, 'format' => 'csv'), 'RecipientList');
            $out .= '<p><strong>' . $i . '/' . $this->getCount() . '</strong> recipients
			(<a href="' . $uriXml . '">export XML</a>, ' . '<a href="' . $uriCsv . '">export CSV</a>' . ')</p>';
        }
        $out = '<h4>' . $this->getTitle() . '</h4>' . $out;
        return $out;
    }
Example #18
0
 /**
  * Returns the URL of the content of this newsletter
  * @return string
  */
 public function getContentUrl($language = null)
 {
     $append_url = Tools::confParam('append_url');
     $baseUrl = $this->getBaseUrl();
     if (!is_null($language)) {
         $language = '&L=' . $language;
     }
     return $baseUrl . '/index.php?id=' . $this->getPid() . $language . $append_url;
 }
<?php

return ['ctrl' => ['title' => 'LLL:EXT:newsletter/Resources/Private/Language/locallang_db.xlf:tx_newsletter_domain_model_recipientlist', 'label' => 'title', 'tstamp' => 'tstamp', 'crdate' => 'crdate', 'delete' => 'deleted', 'type' => 'type', 'enablecolumns' => ['disabled' => 'hidden'], 'iconfile' => \Ecodev\Newsletter\Tools::getIconfilePrefix() . 'Resources/Public/Icons/tx_newsletter_domain_model_recipientlist.gif', 'type' => 'type'], 'interface' => ['showRecordFieldList' => 'hidden,title'], 'feInterface' => $TCA['tx_newsletter_domain_model_recipientlist']['feInterface'], 'columns' => ['hidden' => ['exclude' => 1, 'label' => 'LLL:EXT:lang/locallang_general.xlf:LGL.hidden', 'config' => ['type' => 'check', 'default' => '0']], 'title' => ['label' => 'LLL:EXT:newsletter/Resources/Private/Language/locallang_db.xlf:tx_newsletter_domain_model_recipientlist.title', 'config' => ['type' => 'input', 'size' => '30', 'eval' => 'trim,required']], 'plain_only' => ['label' => 'LLL:EXT:newsletter/Resources/Private/Language/locallang_db.xlf:tx_newsletter_domain_model_recipientlist.plain_only', 'config' => ['type' => 'check', 'default' => '0']], 'lang' => ['label' => 'LLL:EXT:lang/locallang_tca.php:sys_language', 'config' => ['type' => 'select', 'renderType' => 'selectSingle', 'foreign_table' => 'sys_language', 'foreign_table_where' => 'ORDER BY sys_language.uid', 'minitems' => 0, 'maxitems' => 1, 'items' => ['0' => ['', -1], '1' => ['LLL:EXT:lang/locallang_general.php:LGL.default_value', 0]]]], 'be_users' => ['label' => 'LLL:EXT:newsletter/Resources/Private/Language/locallang_db.xlf:tx_newsletter_domain_model_recipientlist.be_users', 'config' => ['type' => 'select', 'renderType' => 'selectMultipleSideBySide', 'foreign_table' => 'be_users', 'foreign_table_where' => 'ORDER BY be_users.uid', 'size' => 5, 'minitems' => 0, 'maxitems' => 100]], 'fe_groups' => ['label' => 'LLL:EXT:newsletter/Resources/Private/Language/locallang_db.xlf:tx_newsletter_domain_model_recipientlist.fe_groups', 'config' => ['type' => 'group', 'internal_type' => 'db', 'allowed' => 'fe_groups', 'size' => 5, 'minitems' => 0, 'maxitems' => 100]], 'fe_pages' => ['label' => 'LLL:EXT:newsletter/Resources/Private/Language/locallang_db.xlf:tx_newsletter_domain_model_recipientlist.fe_pages', 'config' => ['type' => 'group', 'internal_type' => 'db', 'allowed' => 'pages', 'size' => 5, 'minitems' => 0, 'maxitems' => 100]], 'sql_statement' => ['label' => 'LLL:EXT:newsletter/Resources/Private/Language/locallang_db.xlf:tx_newsletter_domain_model_recipientlist.sql_statement', 'config' => ['type' => 'text', 'cols' => '50', 'rows' => '10']], 'sql_register_bounce' => ['label' => 'LLL:EXT:newsletter/Resources/Private/Language/locallang_db.xlf:tx_newsletter_domain_model_recipientlist.sql_register_bounce', 'config' => ['type' => 'text', 'cols' => '50', 'rows' => '10']], 'sql_register_open' => ['label' => 'LLL:EXT:newsletter/Resources/Private/Language/locallang_db.xlf:tx_newsletter_domain_model_recipientlist.sql_register_open', 'config' => ['type' => 'text', 'cols' => '50', 'rows' => '10']], 'sql_register_click' => ['label' => 'LLL:EXT:newsletter/Resources/Private/Language/locallang_db.xlf:tx_newsletter_domain_model_recipientlist.sql_register_click', 'config' => ['type' => 'text', 'cols' => '50', 'rows' => '10']], 'csv_separator' => ['label' => 'LLL:EXT:newsletter/Resources/Private/Language/locallang_db.xlf:tx_newsletter_domain_model_recipientlist.csv_separator', 'config' => ['type' => 'input', 'size' => 1]], 'csv_fields' => ['label' => 'LLL:EXT:newsletter/Resources/Private/Language/locallang_db.xlf:tx_newsletter_domain_model_recipientlist.csv_fields', 'config' => ['type' => 'input', 'size' => 20]], 'csv_values' => ['label' => 'LLL:EXT:newsletter/Resources/Private/Language/locallang_db.xlf:tx_newsletter_domain_model_recipientlist.csv_values', 'config' => ['type' => 'text', 'cols' => 40, 'rows' => 10]], 'csv_filename' => ['label' => 'LLL:EXT:newsletter/Resources/Private/Language/locallang_db.xlf:tx_newsletter_domain_model_recipientlist.csv_file', 'config' => ['type' => 'group', 'internal_type' => 'file', 'allowed' => 'csv,txt', 'max_size' => 500, 'uploadfolder' => 'uploads/tx_newsletter', 'size' => 1, 'minitems' => 0, 'maxitems' => 1]], 'csv_url' => ['label' => 'LLL:EXT:newsletter/Resources/Private/Language/locallang_db.xlf:tx_newsletter_domain_model_recipientlist.csv_url', 'config' => ['type' => 'input', 'size' => 20]], 'type' => ['label' => 'LLL:EXT:newsletter/Resources/Private/Language/locallang_db.xlf:tx_newsletter_domain_model_recipientlist.type', 'config' => ['type' => 'select', 'renderType' => 'selectSingle', 'items' => [['LLL:EXT:newsletter/Resources/Private/Language/locallang_db.xlf:tx_newsletter_domain_model_recipientlist.type_be_users', \Ecodev\Newsletter\Domain\Model\RecipientList\BeUsers::class], ['LLL:EXT:newsletter/Resources/Private/Language/locallang_db.xlf:tx_newsletter_domain_model_recipientlist.type_fe_groups', \Ecodev\Newsletter\Domain\Model\RecipientList\FeGroups::class], ['LLL:EXT:newsletter/Resources/Private/Language/locallang_db.xlf:tx_newsletter_domain_model_recipientlist.type_fe_pages', \Ecodev\Newsletter\Domain\Model\RecipientList\FePages::class], ['LLL:EXT:newsletter/Resources/Private/Language/locallang_db.xlf:tx_newsletter_domain_model_recipientlist.type_sql', \Ecodev\Newsletter\Domain\Model\RecipientList\Sql::class], ['LLL:EXT:newsletter/Resources/Private/Language/locallang_db.xlf:tx_newsletter_domain_model_recipientlist.type_csv_file', \Ecodev\Newsletter\Domain\Model\RecipientList\CsvFile::class], ['LLL:EXT:newsletter/Resources/Private/Language/locallang_db.xlf:tx_newsletter_domain_model_recipientlist.type_csv_list', \Ecodev\Newsletter\Domain\Model\RecipientList\CsvList::class], ['LLL:EXT:newsletter/Resources/Private/Language/locallang_db.xlf:tx_newsletter_domain_model_recipientlist.type_csv_url', \Ecodev\Newsletter\Domain\Model\RecipientList\CsvUrl::class], ['LLL:EXT:newsletter/Resources/Private/Language/locallang_db.xlf:tx_newsletter_domain_model_recipientlist.type_html', \Ecodev\Newsletter\Domain\Model\RecipientList\Html::class]], 'maxitems' => 1, 'default' => \Ecodev\Newsletter\Domain\Model\RecipientList\Sql::class]], 'html_url' => ['label' => 'LLL:EXT:newsletter/Resources/Private/Language/locallang_db.xlf:tx_newsletter_domain_model_recipientlist.html_url', 'config' => ['type' => 'input', 'size' => 20, 'eval' => 'trim,required']], 'html_fetch_type' => ['label' => 'LLL:EXT:newsletter/Resources/Private/Language/locallang_db.xlf:tx_newsletter_domain_model_recipientlist.html_fetch_type', 'config' => ['type' => 'select', 'renderType' => 'selectSingle', 'items' => [['LLL:EXT:newsletter/Resources/Private/Language/locallang_db.xlf:tx_newsletter_domain_model_recipientlist.html_fetch_type_mailto', 'mailto'], ['LLL:EXT:newsletter/Resources/Private/Language/locallang_db.xlf:tx_newsletter_domain_model_recipientlist.html_fetch_type_regex', 'regex']], 'size' => 1, 'maxitems' => 1]], 'recipients_preview' => ['label' => 'LLL:EXT:newsletter/Resources/Private/Language/locallang.xlf:preview', 'config' => ['type' => 'user', 'userFunc' => 'Ecodev\\Newsletter\\Tca\\RecipientListTca->render']]], 'types' => ['0' => ['showitem' => 'hidden;;1, title, type'], \Ecodev\Newsletter\Domain\Model\RecipientList\BeUsers::class => ['showitem' => 'hidden;;1, title, plain_only, lang, type, be_users, recipients_preview'], \Ecodev\Newsletter\Domain\Model\RecipientList\FeGroups::class => ['showitem' => 'hidden;;1, title, plain_only, lang, type, fe_groups, recipients_preview'], \Ecodev\Newsletter\Domain\Model\RecipientList\FePages::class => ['showitem' => 'hidden;;1, title, plain_only, lang, type, fe_pages, recipients_preview'], \Ecodev\Newsletter\Domain\Model\RecipientList\Sql::class => ['showitem' => 'hidden;;1, title, plain_only, type, sql_statement, sql_register_bounce, sql_register_open, sql_register_click, recipients_preview'], \Ecodev\Newsletter\Domain\Model\RecipientList\CsvFile::class => ['showitem' => 'hidden;;1, title, plain_only, type, csv_separator, csv_fields, csv_filename, recipients_preview'], \Ecodev\Newsletter\Domain\Model\RecipientList\CsvList::class => ['showitem' => 'hidden;;1, title, plain_only, type, csv_separator, csv_fields, csv_values, recipients_preview'], \Ecodev\Newsletter\Domain\Model\RecipientList\CsvUrl::class => ['showitem' => 'hidden;;1, title, plain_only, type, csv_separator, csv_fields, csv_url, recipients_preview'], \Ecodev\Newsletter\Domain\Model\RecipientList\Html::class => ['showitem' => 'hidden;;1, title, plain_only, lang, type, html_url, html_fetch_type, recipients_preview']], 'palettes' => ['1' => ['showitem' => '']]];
    /**
     * Find all pairs of newsletter-email UIDs that are should be sent
     *
     * @global \TYPO3\CMS\Core\Database\DatabaseConnection $TYPO3_DB
     * @param Newsletter $newsletter
     * @return array [[newsletter => 12, email => 5], ...]
     */
    public static function findAllNewsletterAndEmailUidToSend(Newsletter $newsletter = null)
    {
        global $TYPO3_DB;
        // Apply limit of emails per round
        $mails_per_round = (int) \Ecodev\Newsletter\Tools::confParam('mails_per_round');
        if ($mails_per_round) {
            $limit = ' LIMIT ' . $mails_per_round;
        } else {
            $limit = '';
        }
        // Apply newsletter restriction if any
        if ($newsletter) {
            $newsletterUid = 'AND tx_newsletter_domain_model_newsletter.uid = ' . $newsletter->getUid();
        } else {
            $newsletterUid = '';
        }
        // Find the uid of emails and newsletters that need to be sent
        $rs = $TYPO3_DB->sql_query('SELECT tx_newsletter_domain_model_newsletter.uid AS newsletter, tx_newsletter_domain_model_email.uid AS email
						FROM tx_newsletter_domain_model_email
						INNER JOIN tx_newsletter_domain_model_newsletter ON (tx_newsletter_domain_model_email.newsletter = tx_newsletter_domain_model_newsletter.uid)
						WHERE tx_newsletter_domain_model_email.begin_time = 0
                        ' . $newsletterUid . '
						ORDER BY tx_newsletter_domain_model_email.newsletter ' . $limit);
        $result = array();
        while ($record = $TYPO3_DB->sql_fetch_assoc($rs)) {
            $result[] = $record;
        }
        return $result;
    }
Example #21
0
 /**
  * Load data from a CSV file.
  * @param $filename path to the CSV file may be on disk or remote URL
  */
 protected function loadCsvFromFile($filename)
 {
     $csvdata = null;
     if ($filename) {
         $csvdata = \Ecodev\Newsletter\Tools::getURL($filename);
     }
     $this->loadCsvFromData($csvdata);
 }
 /**
  * Creates a new Newsletter and forwards to the list action.
  *
  * @param \Ecodev\Newsletter\Domain\Model\Newsletter $newNewsletter a fresh Newsletter object which has not yet been added to the repository
  * @dontverifyrequesthash
  * @dontvalidate $newNewsletter
  * @ignorevalidation $newNewsletter
  */
 public function createAction(Newsletter $newNewsletter = null)
 {
     $limitTestRecipientCount = 10;
     // This is a low limit, technically, but it does not make sense to test a newsletter for more people than that anyway
     $recipientList = $newNewsletter->getRecipientList();
     $recipientList->init();
     $count = $recipientList->getCount();
     $validatedContent = $newNewsletter->getValidatedContent($language);
     // If we attempt to create a newsletter as a test but it has too many recipient, reject it (we cannot safely send several emails wihtout slowing down respoonse and/or timeout issues)
     if ($newNewsletter->getIsTest() && $count > $limitTestRecipientCount) {
         $this->addFlashMessage($this->translate('flashmessage_test_maximum_recipients', [$count, $limitTestRecipientCount]), $this->translate('flashmessage_test_maximum_recipients_title'), \TYPO3\CMS\Core\Messaging\FlashMessage::ERROR);
         $this->view->assign('success', false);
     } elseif (count($validatedContent['errors'])) {
         $this->addFlashMessage('The newsletter HTML content does not validate. See tab "Newsletter > Status" for details.', $this->translate('flashmessage_newsletter_invalid'), \TYPO3\CMS\Core\Messaging\FlashMessage::ERROR);
         $this->view->assign('success', false);
     } else {
         // If it's a test newsletter, it's planned to be sent right now
         if ($newNewsletter->getIsTest()) {
             $newNewsletter->setPlannedTime(new DateTime());
         }
         // Save the new newsletter
         $this->newsletterRepository->add($newNewsletter);
         $this->persistenceManager->persistAll();
         $this->view->assign('success', true);
         // If it is test newsletter, send it immediately
         if ($newNewsletter->getIsTest()) {
             try {
                 // Fill the spool and run the queue
                 Tools::createSpool($newNewsletter);
                 Tools::runSpool($newNewsletter);
                 $this->addFlashMessage($this->translate('flashmessage_test_newsletter_sent'), $this->translate('flashmessage_test_newsletter_sent_title'), \TYPO3\CMS\Core\Messaging\FlashMessage::OK);
             } catch (\Exception $exception) {
                 $this->addFlashMessage($exception->getMessage(), $this->translate('flashmessage_test_newsletter_error'), \TYPO3\CMS\Core\Messaging\FlashMessage::ERROR);
             }
         } else {
             $this->addFlashMessage($this->translate('flashmessage_newsletter_queued'), $this->translate('flashmessage_newsletter_queued_title'), \TYPO3\CMS\Core\Messaging\FlashMessage::OK);
         }
     }
     $this->view->setVariablesToRender(['data', 'success', 'flashMessages']);
     $this->view->setConfiguration(['data' => self::resolveJsonViewConfiguration()]);
     $this->view->assign('data', $newNewsletter);
     $this->flushFlashMessages();
 }
Example #23
0
 public function getSubstitutedConfig()
 {
     $markers = ['###SERVER###', '###PROTOCOL###', '###PORT###', '###USERNAME###', '###PASSWORD###'];
     $values = [];
     $values[] = $this->getServer();
     $values[] = $this->getProtocol();
     $values[] = $this->getPort();
     $values[] = $this->getUsername();
     $values[] = \Ecodev\Newsletter\Tools::decrypt($this->getPassword());
     $config = $this->getConfig();
     if (empty($config)) {
         // Keep the old config to not break old installations
         $config = 'poll ###SERVER### proto ###PROTOCOL### username "###USERNAME###" password "###PASSWORD###"';
     } else {
         $config = \Ecodev\Newsletter\Tools::decrypt($config);
     }
     $result = str_replace($markers, $values, $config);
     unset($values);
     // Dont leave unencrypted values in memory around for too long.
     return $result;
 }
Example #24
0
 /**
  * Returns the URL of the content of this newsletter
  * @return string
  */
 public function getContentUrl($language = null)
 {
     $append_url = Tools::confParam('append_url');
     $domain = $this->getDomain();
     if (!is_null($language)) {
         $language = '&L=' . $language;
     }
     $protocol = Tools::confParam('protocol');
     //stefano: protocol is now set through "basic.protocol" parameter
     return "{$protocol}{$domain}/index.php?id=" . $this->getPid() . $language . $append_url;
 }
    /**
     * @test
     */
    public function getSubstitutedConfigCustom()
    {
        $this->subject->setServer('pop.example.com');
        $this->subject->setProtocol('pop');
        $this->subject->setPort(123);
        $this->subject->setUsername('connor');
        $this->subject->setPassword(\Ecodev\Newsletter\Tools::encrypt('skynet'));
        $config = 'server  : ###SERVER###
protocol: ###PROTOCOL###
port    : ###PORT###
username: ###USERNAME###
password: ###PASSWORD###';
        $this->subject->setConfig(\Ecodev\Newsletter\Tools::encrypt($config));
        $expected = 'server  : pop.example.com
protocol: pop
port    : 123
username: connor
password: skynet';
        $this->assertSame($expected, $this->subject->getSubstitutedConfig());
    }
Example #26
0
 /**
  * Encrypt old bounce account passwords and preserve old default config
  *
  * @return string[]
  */
 private function getQueriesToEncryptOldBounceAccountPasswords()
 {
     // Fetch the old records - they will have a default port and an empty config.
     $rs = $this->databaseConnection->exec_SELECTquery('uid, password', 'tx_newsletter_domain_model_bounceaccount', 'port = 0 AND config = \'\'');
     $records = [];
     while ($record = $this->databaseConnection->sql_fetch_assoc($rs)) {
         $records[] = $record;
     }
     $this->databaseConnection->sql_free_result($rs);
     if (empty($records)) {
         return [];
     }
     // Keep the old config to not break old installations
     $config = Tools::encrypt("poll ###SERVER###\nproto ###PROTOCOL### \nusername \"###USERNAME###\"\npassword \"###PASSWORD###\"\n");
     $queries = [];
     foreach ($records as $record) {
         $queries[] = $this->databaseConnection->UPDATEquery('tx_newsletter_domain_model_bounceaccount', 'uid=' . intval($record['uid']), ['password' => Tools::encrypt($record['password']), 'config' => $config]);
     }
     return ['Encrypt bounce account passwords' => $queries];
 }
Example #27
0
 /**
  * Encrypt old bounce account passwords
  *
  * @global \TYPO3\CMS\Core\Database\DatabaseConnection $TYPO3_DB
  * @return string[]
  */
 private static function getQueriesToEncryptOldBounceAccountPasswords()
 {
     // Prepare Queries
     // Keep the old config to not break old installations
     $config = Tools::encrypt("poll ###SERVER###\nproto ###PROTOCOL### \nusername \"###USERNAME###\"\npassword \"###PASSWORD###\"\n");
     // Fetch and update the old records - they will have a default port and an empty config.
     global $TYPO3_DB;
     $rs = $TYPO3_DB->exec_SELECTquery('uid, password', 'tx_newsletter_domain_model_bounceaccount', 'port = 0 AND config = \'\'');
     while (($records[] = $TYPO3_DB->sql_fetch_assoc($rs)) || array_pop($records)) {
     }
     $TYPO3_DB->sql_free_result($rs);
     // Set Queries
     $queries = array();
     if (!empty($records)) {
         foreach ($records as $row) {
             $queries[] = $TYPO3_DB->UPDATEquery('tx_newsletter_domain_model_bounceaccount', 'uid=' . intval($row['uid']), array('password' => Tools::encrypt($row['password']), 'config' => $config));
         }
     }
     return $queries;
 }
Example #28
0
 /**
  * Sends an email to the address configured in extension settings when a recipient unsubscribe
  * @param \Ecodev\Newsletter\Domain\Model\Newsletter $newsletter
  * @param \Ecodev\Newsletter\Domain\Model\RecipientList $recipientList
  * @param \Ecodev\Newsletter\Domain\Model\Email $email
  * @return void
  */
 protected function notifyUnsubscribe($newsletter, $recipientList, Email $email)
 {
     $notificationEmail = Tools::confParam('notification_email');
     // Use the page-owner as user
     if ($notificationEmail == 'user') {
         $rs = $GLOBALS['TYPO3_DB']->sql_query("SELECT email\n\t\t\tFROM be_users\n\t\t\tLEFT JOIN pages ON be_users.uid = pages.perms_userid\n\t\t\tWHERE pages.uid = " . $newsletter->getPid());
         list($notificationEmail) = $GLOBALS['TYPO3_DB']->sql_fetch_row($rs);
     }
     // If cannot find valid email, don't send any notification
     if (!\TYPO3\CMS\Core\Utility\GeneralUtility::validEmail($notificationEmail)) {
         return;
     }
     // Build email texts
     $baseUrl = 'http://' . $newsletter->getDomain();
     $urlRecipient = $baseUrl . '/typo3/alt_doc.php?&edit[tx_newsletter_domain_model_email][' . $email->getUid() . ']=edit';
     $urlRecipientList = $baseUrl . '/typo3/alt_doc.php?&edit[tx_newsletter_domain_model_recipientlist][' . $recipientList->getUid() . ']=edit';
     $urlNewsletter = $baseUrl . '/typo3/alt_doc.php?&edit[tx_newsletter_domain_model_newsletter][' . $newsletter->getUid() . ']=edit';
     $subject = \TYPO3\CMS\Extbase\Utility\LocalizationUtility::translate('unsubscribe_notification_subject', 'newsletter');
     $body = \TYPO3\CMS\Extbase\Utility\LocalizationUtility::translate('unsubscribe_notification_body', 'newsletter', array($email->getRecipientAddress(), $urlRecipient, $recipientList->getTitle(), $urlRecipientList, $newsletter->getTitle(), $urlNewsletter));
     // Actually sends email
     $message = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Mail\\MailMessage');
     $message->setTo($notificationEmail)->setFrom(array($newsletter->getSenderEmail() => $newsletter->getSenderName()))->setSubject($subject)->setBody($body, 'text/html');
     $message->send();
 }
<?php

return ['ctrl' => ['title' => 'LLL:EXT:newsletter/Resources/Private/Language/locallang_db.xlf:tx_newsletter_domain_model_link', 'label' => 'url', 'iconfile' => \Ecodev\Newsletter\Tools::getIconfilePrefix() . 'Resources/Public/Icons/tx_newsletter_domain_model_link.gif'], 'interface' => ['showRecordFieldList' => 'url,opened_count,newsletter'], 'types' => ['1' => ['showitem' => 'url,opened_count,newsletter']], 'palettes' => ['1' => ['showitem' => '']], 'columns' => ['hidden' => ['exclude' => 1, 'label' => 'LLL:EXT:lang/locallang_general.xlf:LGL.hidden', 'config' => ['type' => 'check']], 'url' => ['label' => 'LLL:EXT:newsletter/Resources/Private/Language/locallang_db.xlf:tx_newsletter_domain_model_link.url', 'config' => ['type' => 'input', 'size' => 40, 'eval' => 'trim', 'readOnly' => true]], 'opened_count' => ['label' => 'LLL:EXT:newsletter/Resources/Private/Language/locallang_db.xlf:tx_newsletter_domain_model_link.opened_count', 'config' => ['type' => 'input', 'size' => 4, 'eval' => 'int', 'readOnly' => true]], 'newsletter' => ['label' => 'LLL:EXT:newsletter/Resources/Private/Language/locallang_db.xlf:tx_newsletter_domain_model_link.newsletter', 'config' => ['readOnly' => true, 'type' => 'inline', 'foreign_table' => 'tx_newsletter_domain_model_newsletter', 'minitems' => 0, 'maxitems' => 1, 'appearance' => ['collapse' => 0, 'showSynchronizationLink' => 1, 'showPossibleLocalizationRecords' => 1, 'showAllLocalizationLink' => 1]]]]];
<?php

// From TYPO3 7.4.0 onward we must use EXT prefix
if (version_compare(TYPO3_version, '7.4.0', '>=')) {
    $wizardIcon = 'EXT:backend/Resources/Public/Images/FormFieldWizard/wizard_edit.gif';
} else {
    // But for TYPO3 6.2 family, we still have to use old style
    $wizardIcon = 'edit2.gif';
}
return ['ctrl' => ['title' => 'LLL:EXT:newsletter/Resources/Private/Language/locallang_db.xlf:tx_newsletter_domain_model_newsletter', 'label' => 'planned_time', 'tstamp' => 'tstamp', 'crdate' => 'crdate', 'delete' => 'deleted', 'enablecolumns' => ['disabled' => 'hidden'], 'iconfile' => \Ecodev\Newsletter\Tools::getIconfilePrefix() . 'Resources/Public/Icons/tx_newsletter_domain_model_newsletter.gif'], 'interface' => ['showRecordFieldList' => 'planned_time,begin_time,end_time,repetition,plain_converter,is_test,attachments,sender_name,sender_email,replyto_name,replyto_email,inject_open_spy,inject_links_spy,bounce_account,recipient_list'], 'types' => ['1' => ['showitem' => 'planned_time,begin_time,end_time,repetition,plain_converter,is_test,attachments,sender_name,sender_email,replyto_name,replyto_email,inject_open_spy,inject_links_spy,bounce_account,recipient_list']], 'palettes' => ['1' => ['showitem' => '']], 'columns' => ['hidden' => ['exclude' => 1, 'label' => 'LLL:EXT:lang/locallang_general.xlf:LGL.hidden', 'config' => ['type' => 'check']], 'planned_time' => ['label' => 'LLL:EXT:newsletter/Resources/Private/Language/locallang_db.xlf:tx_newsletter_domain_model_newsletter.planned_time', 'config' => ['type' => 'input', 'size' => 12, 'eval' => 'datetime,required']], 'begin_time' => ['label' => 'LLL:EXT:newsletter/Resources/Private/Language/locallang_db.xlf:tx_newsletter_domain_model_newsletter.begin_time', 'config' => ['type' => 'input', 'size' => 12, 'readOnly' => true, 'eval' => 'datetime']], 'end_time' => ['label' => 'LLL:EXT:newsletter/Resources/Private/Language/locallang_db.xlf:tx_newsletter_domain_model_newsletter.end_time', 'config' => ['type' => 'input', 'size' => 12, 'readOnly' => true, 'eval' => 'datetime']], 'repetition' => ['label' => 'LLL:EXT:newsletter/Resources/Private/Language/locallang_db.xlf:tx_newsletter_domain_model_newsletter.repetition', 'config' => ['type' => 'select', 'renderType' => 'selectSingle', 'items' => [['LLL:EXT:newsletter/Resources/Private/Language/locallang_db.xlf:tx_newsletter_domain_model_newsletter.repetition_none', '0'], ['LLL:EXT:newsletter/Resources/Private/Language/locallang_db.xlf:tx_newsletter_domain_model_newsletter.repetition_daily', '1'], ['LLL:EXT:newsletter/Resources/Private/Language/locallang_db.xlf:tx_newsletter_domain_model_newsletter.repetition_weekly', '2'], ['LLL:EXT:newsletter/Resources/Private/Language/locallang_db.xlf:tx_newsletter_domain_model_newsletter.repetition_biweekly', '3'], ['LLL:EXT:newsletter/Resources/Private/Language/locallang_db.xlf:tx_newsletter_domain_model_newsletter.repetition_monthly', '4'], ['LLL:EXT:newsletter/Resources/Private/Language/locallang_db.xlf:tx_newsletter_domain_model_newsletter.repetition_quarterly', '5'], ['LLL:EXT:newsletter/Resources/Private/Language/locallang_db.xlf:tx_newsletter_domain_model_newsletter.repetition_semiyearly', '6'], ['LLL:EXT:newsletter/Resources/Private/Language/locallang_db.xlf:tx_newsletter_domain_model_newsletter.repetition_yearly', '7']], 'maxitems' => 1]], 'plain_converter' => ['label' => 'LLL:EXT:newsletter/Resources/Private/Language/locallang_db.xlf:tx_newsletter_domain_model_newsletter.plain_converter', 'config' => ['type' => 'select', 'renderType' => 'selectSingle', 'items' => [['LLL:EXT:newsletter/Resources/Private/Language/locallang_db.xlf:tx_newsletter_domain_model_newsletter.plain_converter_builtin', \Ecodev\Newsletter\Domain\Model\PlainConverter\Builtin::class], ['LLL:EXT:newsletter/Resources/Private/Language/locallang_db.xlf:tx_newsletter_domain_model_newsletter.plain_converter_lynx', \Ecodev\Newsletter\Domain\Model\PlainConverter\Lynx::class]], 'maxitems' => 1]], 'is_test' => ['label' => 'LLL:EXT:newsletter/Resources/Private/Language/locallang_db.xlf:tx_newsletter_domain_model_newsletter.is_test', 'config' => ['type' => 'check', 'default' => 0]], 'attachments' => ['label' => 'LLL:EXT:newsletter/Resources/Private/Language/locallang_db.xlf:tx_newsletter_domain_model_newsletter.attachments', 'config' => ['type' => 'group', 'internal_type' => 'file', 'allowed' => '', 'disallowed' => 'php,php3', 'max_size' => 500, 'uploadfolder' => 'uploads/tx_newsletter', 'size' => 3, 'minitems' => 0, 'maxitems' => 10]], 'sender_name' => ['label' => 'LLL:EXT:newsletter/Resources/Private/Language/locallang_db.xlf:tx_newsletter_domain_model_newsletter.sender_name', 'config' => ['type' => 'input', 'size' => 30, 'eval' => 'trim']], 'sender_email' => ['label' => 'LLL:EXT:newsletter/Resources/Private/Language/locallang_db.xlf:tx_newsletter_domain_model_newsletter.sender_email', 'config' => ['type' => 'input', 'size' => 30, 'eval' => 'trim']], 'replyto_name' => ['label' => 'LLL:EXT:newsletter/Resources/Private/Language/locallang_db.xlf:tx_newsletter_domain_model_newsletter.replyto_name', 'config' => ['type' => 'input', 'size' => 30, 'eval' => 'trim']], 'replyto_email' => ['label' => 'LLL:EXT:newsletter/Resources/Private/Language/locallang_db.xlf:tx_newsletter_domain_model_newsletter.replyto_email', 'config' => ['type' => 'input', 'size' => 30, 'eval' => 'trim']], 'inject_open_spy' => ['label' => 'LLL:EXT:newsletter/Resources/Private/Language/locallang_db.xlf:tx_newsletter_domain_model_newsletter.inject_open_spy', 'config' => ['type' => 'check', 'default' => 0]], 'inject_links_spy' => ['label' => 'LLL:EXT:newsletter/Resources/Private/Language/locallang_db.xlf:tx_newsletter_domain_model_newsletter.inject_links_spy', 'config' => ['type' => 'check', 'default' => 0]], 'bounce_account' => ['label' => 'LLL:EXT:newsletter/Resources/Private/Language/locallang_db.xlf:tx_newsletter_domain_model_newsletter.bounce_account', 'config' => ['type' => 'select', 'renderType' => 'selectSingle', 'foreign_table' => 'tx_newsletter_domain_model_bounceaccount', 'items' => [['', 0]], 'maxitems' => 1, 'wizards' => ['edit' => ['type' => 'popup', 'icon' => $wizardIcon, 'module' => ['name' => 'wizard_edit']]]]], 'recipient_list' => ['label' => 'LLL:EXT:newsletter/Resources/Private/Language/locallang_db.xlf:tx_newsletter_domain_model_newsletter.recipient_list', 'config' => ['type' => 'select', 'renderType' => 'selectSingle', 'foreign_table' => 'tx_newsletter_domain_model_recipientlist', 'maxitems' => 1, 'wizards' => ['edit' => ['type' => 'popup', 'icon' => $wizardIcon, 'module' => ['name' => 'wizard_edit']]]]]]];