diff --git a/application/config/mail.php b/application/config/mail.php index 4f1baa85d..17ff7acfc 100644 --- a/application/config/mail.php +++ b/application/config/mail.php @@ -4,34 +4,31 @@ if (!defined('BASEPATH')) exit('No direct script access allowed'); // Define configuration parameters $config['email_number_to_sent'] = 1000; // Number of emails to sent each time sendAll is called -$config['email_number_per_time_range'] = 1; // Number of emails to sent before pause +$config['email_number_per_time_range'] = 882; // Number of emails to sent before pause $config['email_time_range'] = 1; // Length of the pause in seconds $config['email_from_system'] = 'no-reply@technikum-wien.at'; $config['alias_from_system'] = 'No Reply'; -// Smtp: if the CI email library has to connect to a smtp server -// Mail: if the system is setup to send emails with the standard php mail function -// Sendmail: if the system is setup to send email via Sendmail (or similar) -$config['protocol'] = ''; // mail, sendmail, or smtp - -// If protocol is set to sendmail -$config['mailpath'] = ''; // SThe server path to Sendmail (or similar) - // If protocol is set to smtp $config['smtp_host'] = 'localhost'; // SMTP Server Address $config['smtp_port'] = 25; -$config['smtp_timeout'] = 5; // in seconds +$config['smtp_timeout'] = 1; // in seconds $config['smtp_keepalive'] = false; // Enable persistent SMTP connections +$config['smtp_auth'] = false; $config['smtp_user'] = ''; $config['smtp_pass'] = ''; -$config['wordwrap'] = true; // {unwrap}http://example.com/a_long_link_that_should_not_be_wrapped.html{/unwrap} -$config['wrapchars'] = 76; // Character count to wrap at. -$config['mailtype'] = 'html'; // html or text -$config['priority'] = 3; // Email Priority. 1 = highest. 5 = lowest. 3 = normal -$config['validate'] = false; // If true then the email address will be validated +$config['smtp_encryption'] = ''; // '', 'tls' or 'ssl' +$config['wordwrap'] = 76; +$config['is_html'] = true; // html or text +$config['priority'] = 3; // 1 = High, 3 = Normal, 5 = low. When null, the header is not set at all. -// If enabled will be logged info about emails in Codeigniter error logs -$config['enable_debug'] = false; +// If enabled will be logged info about emails +// 0: Disable debugging (you can also leave this out completely, 0 is the default). +// 1: Output messages sent by the client. +// 2: as 1, plus responses received from the server (this is the most useful setting). +// 3: as 2, plus more information about the initial connection - this level can help diagnose STARTTLS failures. +// 4: as 3, plus even lower-level information, very verbose, don't use for debugging SMTP, only low-level problems. +$config['enable_debug'] = 0; // default sender $config['sancho_mail_default_sender'] = defined('SANCHO_MAIL_DEFAULT_SENDER') ? SANCHO_MAIL_DEFAULT_SENDER : ''; @@ -47,3 +44,4 @@ $config['sancho_mail_header_img'] = defined('SANCHO_MAIL_HEADER_IMG') ? SANCHO_M // footer image for custom mails $config['sancho_mail_footer_img'] = defined('SANCHO_MAIL_FOOTER_IMG') ? SANCHO_MAIL_FOOTER_IMG : ''; + diff --git a/application/helpers/hlp_sancho_helper.php b/application/helpers/hlp_sancho_helper.php index 9a32f5e1a..cbc2873fd 100644 --- a/application/helpers/hlp_sancho_helper.php +++ b/application/helpers/hlp_sancho_helper.php @@ -35,41 +35,20 @@ if (! defined('BASEPATH')) exit('No direct script access allowed'); * @param string $bcc Sets BCC of mail. * @return void */ -function sendSanchoMail( - $vorlage_kurzbz, - $vorlage_data, - $to, - $subject, - $headerImg = '', - $footerImg = '', - $from = null, - $cc = null, - $bcc = null -) +function sendSanchoMail($vorlage_kurzbz, $vorlage_data, $to, $subject, $headerImg = '', $footerImg = '', $from = null, $cc = null, $bcc = null) { $ci =& get_instance(); - $ci->load->library('email'); $ci->load->library('MailLib'); + $embeddedImages = array(); + $_from = 'noreply@' . DOMAIN; $sancho_mail_config = $ci->config->item('mail'); - - if ($from == '') + if ($from == null && isset($sancho_mail_config['sancho_mail_default_sender']) && $sancho_mail_config['sancho_mail_default_sender']) { - $from = ((isset($sancho_mail_config['sancho_mail_default_sender']) - && $sancho_mail_config['sancho_mail_default_sender']) - ? $sancho_mail_config['sancho_mail_default_sender'] - : 'noreply') - . '@' . DOMAIN; + $_from = $sancho_mail_config['sancho_mail_default_sender'] . '@' . DOMAIN; } - // Embed sancho header and footer image - // reset important to ensure embedding of images when called in a loop - $ci->email->clear(true); // clear vars and attachments - - $cid_header = ''; - $cid_footer = ''; - if (isset($sancho_mail_config['sancho_mail_use_images']) && $sancho_mail_config['sancho_mail_use_images']) { $sanchoHeader_img = ''; @@ -111,29 +90,27 @@ function sendSanchoMail( } } - // attach header and footer - $ci->email->attach($sanchoHeader_img, 'inline'); - $ci->email->attach($sanchoFooter_img, 'inline'); - $cid_header = $ci->email->attachment_cid($sanchoHeader_img); // sets unique content id for embedding - $cid_footer = $ci->email->attachment_cid($sanchoFooter_img); // sets unique content id for embedding + // Attach header and footer + $embeddedImages[] = array('file_name' => $sanchoHeader_img, 'cid' => 'sancho_header'); + $embeddedImages[] = array('file_name' => $sanchoFooter_img, 'cid' => 'sancho_footer'); } // Set specific mail content into specific content template $content = _parseMailContent($vorlage_kurzbz, $vorlage_data); - // overall main content data array - $layout = array( - 'CID_header' => $cid_header, - 'CID_footer' => $cid_footer, - 'content' => $content - ); - // Set overall main content into the sancho mail template - $body = _parseMailContent('Sancho_Mail_Template', $layout); + $body = _parseMailContent( + 'Sancho_Mail_Template', + array( + 'CID_header' => 'sancho_header', + 'CID_footer' => 'sancho_footer', + 'content' => $content + ) + ); // Send mail return $ci->maillib->send( - $from, + $_from, $to, $subject, $body, @@ -142,7 +119,8 @@ function sendSanchoMail( $bcc, '', // altMessage true, // bulk - true // autogenerated + true, // autogenerated + $embeddedImages ); } @@ -171,3 +149,4 @@ function _parseMailContent($vorlage_kurzbz, $vorlage_data) } } } + diff --git a/application/libraries/MailLib.php b/application/libraries/MailLib.php index 60dd52342..b65295786 100644 --- a/application/libraries/MailLib.php +++ b/application/libraries/MailLib.php @@ -2,6 +2,10 @@ if (! defined('BASEPATH')) exit('No direct script access allowed'); +use PHPMailer\PHPMailer\PHPMailer; +use PHPMailer\PHPMailer\SMTP; +use PHPMailer\PHPMailer\Exception; + /** * Library to manage the sending of the email */ @@ -9,7 +13,7 @@ class MailLib { const ENABLE_DEBUG = 'enable_debug'; - private $sended; // Sended email counter + private $_sended; // Sended email counter // Properties for storing the configuration private $email_number_to_sent; @@ -18,6 +22,7 @@ class MailLib private $email_from_system; private $_ci; // Codeigniter instance + private $_mail; // PHPMailer instance /** * Class constructor @@ -25,7 +30,7 @@ class MailLib public function __construct() { // Set the counter to 0 - $this->sended = 0; + $this->_sended = 0; // Get CI instance $this->_ci =& get_instance(); @@ -33,97 +38,134 @@ class MailLib // The second parameter is used to avoiding name collisions in the config array $this->_ci->config->load('mail', true); - // CI Email library - $this->_ci->load->library('email'); + try + { + // PHPMailer configuration + $this->_mail = new PHPMailer(true); + $this->_mail->isSMTP(); // Send using SMTP + $this->_mail->Host = $this->_getEmailCfgItem('smtp_host'); // Set the SMTP server to send through + $this->_mail->Port = $this->_getEmailCfgItem('smtp_port'); // TCP port to connect to; use 587 if you have set `SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS` + $this->_mail->SMTPAuth = $this->_getEmailCfgItem('smtp_auth'); // Enable SMTP authentication + $this->_mail->Username = $this->_getEmailCfgItem('smtp_user'); // SMTP username + $this->_mail->Password = $this->_getEmailCfgItem('smtp_pass'); // SMTP password + $this->_mail->SMTPSecure = $this->_getEmailCfgItem('smtp_encryption'); // Enable implicit TLS encryption + $this->_mail->Timeout = $this->_getEmailCfgItem('smtp_timeout'); // set the timeout (seconds) + $this->_mail->SMTPKeepAlive = $this->_getEmailCfgItem('smtp_keepalive'); // Persistent SMTP connection + $this->_mail->Priority = $this->_getEmailCfgItem('priority'); // 1 = High, 3 = Normal, 5 = low. When null, the header is not set at all. + $this->_mail->WordWrap = $this->_getEmailCfgItem('wordwrap'); + $this->_mail->isHTML($this->_getEmailCfgItem('is_html')); // html or text + $this->_mail->SMTPDebug = $this->_getEmailCfgItem('enable_debug'); - // Initializing email library with the loaded configurations - $this->_ci->email->initialize($this->_ci->config->config['mail']); - - // Set the configuration properties with the standard configuration values - $this->email_number_to_sent = $this->getEmailCfgItem('email_number_to_sent'); - $this->email_number_per_time_range = $this->getEmailCfgItem('email_number_per_time_range'); - $this->email_time_range = $this->getEmailCfgItem('email_time_range'); - $this->email_from_system = $this->getEmailCfgItem('email_from_system'); - $this->alias_from_system = $this->getEmailCfgItem('alias_from_system'); + // Set the configuration properties with the standard configuration values + $this->email_number_to_sent = $this->_getEmailCfgItem('email_number_to_sent'); + $this->email_number_per_time_range = $this->_getEmailCfgItem('email_number_per_time_range'); + $this->email_time_range = $this->_getEmailCfgItem('email_time_range'); + $this->email_from_system = $this->_getEmailCfgItem('email_from_system'); + $this->alias_from_system = $this->_getEmailCfgItem('alias_from_system'); + } + catch(Exception $e) + { + error_log($e->errorMessage()); + } } /** * Sends a single email */ - public function send($from, $to, $subject, $message, $alias = '', $cc = null, $bcc = null, $altMessage = '', $bulk = false, $autogenerated = false) + public function send($from, $to, $subject, $message, $alias = '', $cc = null, $bcc = null, $altMessage = '', $bulk = false, $autogenerated = false, $embeddedImages = array()) { - // If it is configured then log mail info into the CI error logs - if ($this->getEmailCfgItem(self::ENABLE_DEBUG) === true) - { - $this->_ci->load->library('LogLib'); // Loads logging library + $result = false; - // Log them all! - $this->_ci->loglib->logError('From: '.$from); - $this->_ci->loglib->logError('To: '.$to); - $this->_ci->loglib->logError('Subject: '.$subject); - $this->_ci->loglib->logError('Message: '.$message); - $this->_ci->loglib->logError('Alias: '.$alias); - $this->_ci->loglib->logError('CC: '.$cc); - $this->_ci->loglib->logError('BCC: '.$bcc); - $this->_ci->loglib->logError('Alternative message: '.$altMessage); - } - - // If from is not specified then use the standard one - if (is_null($from) || $from == '') + try { - $from = $this->email_from_system; - // If alias is not specified then use the standard one - if (is_null($alias) || $alias == '') + // If it is configured then log mail info into the CI error logs + if ($this->_getEmailCfgItem(self::ENABLE_DEBUG) === true) { - $alias = $this->alias_from_system; + $this->_ci->load->library('LogLib'); // Loads logging library + + // Log them all! + $this->_ci->loglib->logError('From: '.$from); + $this->_ci->loglib->logError('To: '.$to); + $this->_ci->loglib->logError('Subject: '.$subject); + $this->_ci->loglib->logError('Message: '.$message); + $this->_ci->loglib->logError('Alias: '.$alias); + $this->_ci->loglib->logError('CC: '.$cc); + $this->_ci->loglib->logError('BCC: '.$bcc); + $this->_ci->loglib->logError('Alternative message: '.$altMessage); } - } - if (defined('MAIL_FROM') && MAIL_FROM != '') - { - $from = MAIL_FROM; - if (is_null($alias) || $alias == '') + + // If from is not specified then use the standard one + if (is_null($from) || $from == '') { - $alias = $this->alias_from_system; + $from = $this->email_from_system; + // If alias is not specified then use the standard one + if (is_null($alias) || $alias == '') + { + $alias = $this->alias_from_system; + } } + if (defined('MAIL_FROM') && MAIL_FROM != '') + { + $from = MAIL_FROM; + if (is_null($alias) || $alias == '') + { + $alias = $this->alias_from_system; + } + } + + $this->_mail->setFrom($from, $alias); + + // Check if the email address of the debug recipient is a valid one + $recipient = $to; + $recipientCC = $cc; + $recipientBCC = $bcc; + + // If we the an email for debugging has been set + if (defined('MAIL_DEBUG') && MAIL_DEBUG != '') + { + // if is it valid use it!!! + $recipient = MAIL_DEBUG; + if ($recipientCC != '') $recipientCC = MAIL_DEBUG; + if ($recipientBCC != '') $recipientBCC = MAIL_DEBUG; + } + + // Recipients + $this->_mail->addAddress($recipient); + if (!is_null($recipientCC)) $this->_mail->addCC($recipientCC); + if (!is_null($recipientBCC)) $this->_mail->addBCC($recipientBCC); + + // Subject & body & alternative body + $this->_mail->Subject = $subject; + $this->_mail->Body = $message; + if (!isEmptyString($altMessage)) $this->_mail->AltBody = $altMessage; + + // Custom headers + if ($bulk) $this->_mail->addCustomHeader('Precedence', 'bulk'); + if ($autogenerated) $this->_mail->addCustomHeader('Auto-Submitted', 'auto-generated'); + + // Embedded images + foreach ($embeddedImages as $embeddedImage) + { + if (!$this->_mail->addEmbeddedImage($embeddedImage['file_name'], $embeddedImage['cid'])) return false; + } + + $result = $this->_mail->send(); + + // If the email was succesfully sended then increment the counter and checks if it has to _wait until the sending of the next + if ($result != false) + { + $this->_sended++; + $this->_wait(); + } + + // Clear the properties for the next message + $this->_mail->clearAddresses(); + $this->_mail->clearAllRecipients(); + $this->_mail->clearAttachments(); } - - $this->_ci->email->from($from, $alias); - - // Check if the email address of the debug recipient is a valid one - $recipient = $to; - $recipientCC = $cc; - $recipientBCC = $bcc; - if (defined('MAIL_DEBUG') && MAIL_DEBUG != '') + catch (Exception $e) { - // if is it valid use it!!! - $recipient = MAIL_DEBUG; - if ($recipientCC != '') - $recipientCC = MAIL_DEBUG; - if ($recipientBCC != '') - $recipientBCC = MAIL_DEBUG; - } - - $this->_ci->email->to($recipient); - if (!is_null($recipientCC)) $this->_ci->email->cc($recipientCC); - if (!is_null($recipientBCC)) $this->_ci->email->bcc($recipientBCC); - $this->_ci->email->subject($subject); - $this->_ci->email->message($message); - if (!isEmptyString($altMessage)) $this->_ci->email->set_alt_message($altMessage); - - if($bulk) - $this->_ci->email->set_header('Precedence', 'bulk'); - if($autogenerated) - $this->_ci->email->set_header('Auto-Submitted', 'auto-generated'); - - // Avoid printing on standard output ugly error messages - $result = @$this->_ci->email->send(); - - // If the email was succesfully sended then increment the counter - // and checks if it has to wait until the sending of the next - if ($result) - { - $this->sended++; - $this->wait(); + error_log($e->errorMessage()); } return $result; @@ -176,13 +218,13 @@ class MailLib } /** - * Checks if it has to wait until the sending of the next + * Checks if it has to _wait until the sending of the next */ - private function wait() + private function _wait() { - if ($this->sended == $this->email_number_per_time_range) + if ($this->_sended == $this->email_number_per_time_range) { - $this->sended = 0; + $this->_sended = 0; sleep($this->email_time_range); // Wait!!! } } @@ -190,7 +232,7 @@ class MailLib /** * Gets an item from the email configuration array */ - private function getEmailCfgItem($itemName) + private function _getEmailCfgItem($itemName) { return $this->_ci->config->item($itemName, EMAIL_CONFIG_INDEX); } diff --git a/composer.json b/composer.json index 370c2eda1..03880dfeb 100644 --- a/composer.json +++ b/composer.json @@ -504,7 +504,8 @@ "vuejs/vuedatepicker_js": "7.2.0", "vuejs/vuedatepicker_css": "7.2.0", "vuejs/vuedatepicker_js11": "11.0.1", - "vuejs/vuedatepicker_css11": "11.0.1" + "vuejs/vuedatepicker_css11": "11.0.1", + "phpmailer/phpmailer": "^7.0" }, "config": { diff --git a/composer.lock b/composer.lock index f2ce3923c..0483c090a 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "1de37a74ba51a66057eb2712b21340c8", + "content-hash": "00798f1647938b79b8a3bfc109836a6a", "packages": [ { "name": "afarkas/html5shiv", @@ -1547,6 +1547,88 @@ }, "type": "library" }, + { + "name": "phpmailer/phpmailer", + "version": "v7.0.1", + "source": { + "type": "git", + "url": "https://github.com/PHPMailer/PHPMailer.git", + "reference": "360ae911ce62e25e11249f6140fa58939f556ebe" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/360ae911ce62e25e11249f6140fa58939f556ebe", + "reference": "360ae911ce62e25e11249f6140fa58939f556ebe", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "ext-filter": "*", + "ext-hash": "*", + "php": ">=5.5.0" + }, + "require-dev": { + "dealerdirect/phpcodesniffer-composer-installer": "^1.0", + "doctrine/annotations": "^1.2.6 || ^1.13.3", + "php-parallel-lint/php-console-highlighter": "^1.0.0", + "php-parallel-lint/php-parallel-lint": "^1.3.2", + "phpcompatibility/php-compatibility": "^10.0.0@dev", + "squizlabs/php_codesniffer": "^3.13.5", + "yoast/phpunit-polyfills": "^1.0.4" + }, + "suggest": { + "decomplexity/SendOauth2": "Adapter for using XOAUTH2 authentication", + "directorytree/imapengine": "For uploading sent messages via IMAP, see gmail example", + "ext-imap": "Needed to support advanced email address parsing according to RFC822", + "ext-mbstring": "Needed to send email in multibyte encoding charset or decode encoded addresses", + "ext-openssl": "Needed for secure SMTP sending and DKIM signing", + "greew/oauth2-azure-provider": "Needed for Microsoft Azure XOAUTH2 authentication", + "hayageek/oauth2-yahoo": "Needed for Yahoo XOAUTH2 authentication", + "league/oauth2-google": "Needed for Google XOAUTH2 authentication", + "psr/log": "For optional PSR-3 debug logging", + "symfony/polyfill-mbstring": "To support UTF-8 if the Mbstring PHP extension is not enabled (^1.2)", + "thenetworg/oauth2-azure": "Needed for Microsoft XOAUTH2 authentication" + }, + "type": "library", + "autoload": { + "psr-4": { + "PHPMailer\\PHPMailer\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-2.1-only" + ], + "authors": [ + { + "name": "Marcus Bointon", + "email": "phpmailer@synchromedia.co.uk" + }, + { + "name": "Jim Jagielski", + "email": "jimjag@gmail.com" + }, + { + "name": "Andy Prevost", + "email": "codeworxtech@users.sourceforge.net" + }, + { + "name": "Brent R. Matzelle" + } + ], + "description": "PHPMailer is a full-featured email creation and transfer class for PHP", + "support": { + "issues": "https://github.com/PHPMailer/PHPMailer/issues", + "source": "https://github.com/PHPMailer/PHPMailer/tree/v7.0.1" + }, + "funding": [ + { + "url": "https://github.com/Synchro", + "type": "github" + } + ], + "time": "2025-11-25T07:18:09+00:00" + }, { "name": "phpseclib/phpseclib", "version": "2.0.48",