diff --git a/adm_program/installation/db_scripts/preferences.php b/adm_program/installation/db_scripts/preferences.php index b10c6ced80..8e787aa1a5 100644 --- a/adm_program/installation/db_scripts/preferences.php +++ b/adm_program/installation/db_scripts/preferences.php @@ -49,6 +49,7 @@ // E-mail dispatch 'mail_send_method' => 'phpmail', + 'mail_sending_mode' => '0', 'mail_recipients_with_roles' => '1', 'mail_number_recipients' => '50', 'mail_into_to' => '0', diff --git a/adm_program/languages/de-DE.xml b/adm_program/languages/de-DE.xml index 9e5d3d59fc..0be5004006 100644 --- a/adm_program/languages/de-DE.xml +++ b/adm_program/languages/de-DE.xml @@ -1043,6 +1043,10 @@ #VAR1# verschieben Mehrere Empfänger:innen E-Mails an mehrere Empfänger:innen enthalten alle Empfänger:innen im BCC-Feld. Damit ist sichergestellt, dass keiner die E-Mail-Adressen der anderen Empfänger:innen sieht. Das TO-Feld muss allerdings auch befüllt werden. Über diese Einstellung kann festgelegt werden, was im Empfängerfeld (TO) hinterlegt wird. Dies kein ein versteckter Wert \"Undisclosed Recipients\" sein, was aber bei manchen Providern zu Problemen führt. Alternativ kann das Empfängerfeld (TO) mit der Absenderadresse bzw. der Administrator:innen-Adresse aus den Systembenachrichtigungen gefüllt werden. Hinweis: Alle Emails an mehrere Empfänger:innen werden dann auch an die E-Mail-Adresse im Empfängerfeld (TO) geschickt. (Voreinstellung: Absender:in) + Versandmodus + Im Modus 'Gebündelt' werden E-Mails an mehrere Empfänger zusammengefasst. Eine E-Mail erhält dann eine konfigurierte Anzahl an Empfänger im TO oder BCC Feld. Dies ist sinnvoll, wenn der Hoster den Versand von vielen E-Mails nicht erlaubt. Im Modus 'Einzeln' erhält jeder Empfänger eine separate E-Mail. In diesem Modus können einer E-Mail-Vorlage weitere Felder hinzugefügt werden. + Gebündelt + Einzeln Die Rolle Administrator:in muss mindestens ein Mitglied haben! Hier können Sie Bedingungen zu jedem Feld in Ihrer Liste hinterlegen. Damit werden die ermittelten Mitglieder der ausgewählten Rolle mit Ihren Bedingungen weiter eingeschränkt. Name diff --git a/adm_program/languages/de.xml b/adm_program/languages/de.xml index 25cf96e179..7522fddd66 100644 --- a/adm_program/languages/de.xml +++ b/adm_program/languages/de.xml @@ -1039,6 +1039,10 @@ #VAR1# verschieben Mehrere Empfänger:innen E-Mails an mehrere Empfänger:innen enthalten alle Empfänger:innen im BCC-Feld. Damit ist sichergestellt, dass keiner die E-Mail-Adressen der anderen Empfänger:innen sieht. Das TO-Feld muss allerdings auch befüllt werden. Über diese Einstellung kann festgelegt werden, was im Empfängerfeld (TO) hinterlegt wird. Dies kein ein versteckter Wert \"Undisclosed Recipients\" sein, was aber bei manchen Providern zu Problemen führt. Alternativ kann das Empfängerfeld (TO) mit der Absenderadresse bzw. der Administrator:innen-Adresse aus den Systembenachrichtigungen gefüllt werden. Hinweis: Alle Emails an mehrere Empfänger:innen werden dann auch an die E-Mail-Adresse im Empfängerfeld (TO) geschickt. (Voreinstellung: Absender:in) + Versandmodus + Im Modus 'Gebündelt' werden E-Mails an mehrere Empfänger zusammengefasst. Eine E-Mail erhält dann eine konfigurierte Anzahl an Empfänger im TO oder BCC Feld. Dies ist sinnvoll, wenn der Hoster den Versand von vielen E-Mails nicht erlaubt. Im Modus 'Einzeln' erhält jeder Empfänger eine separate E-Mail. In diesem Modus können einer E-Mail-Vorlage weitere Felder hinzugefügt werden. + Gebündelt + Einzeln Die Rolle Administrator:in muss mindestens ein Mitglied haben! Hier kannst du Bedingungen zu jedem Feld in deiner Liste hinterlegen. Damit werden die ermittelten Mitglieder der ausgewählten Rolle mit deinen Bedingungen weiter eingeschränkt. Name diff --git a/adm_program/languages/en.xml b/adm_program/languages/en.xml index 04d30ebb19..3e684a2382 100644 --- a/adm_program/languages/en.xml +++ b/adm_program/languages/en.xml @@ -1039,6 +1039,10 @@ Move #VAR1# Multiple recipients E-mails to multiple recipients contain all recipients in the BCC field. This ensures that nobody sees the e-mail addresses of the other recipients. However, the TO field must also be filled. This setting can be used to define what is entered in the recipient (TO) field. This could be a hidden value "Undisclosed Recipients", but this causes problems with some providers. Alternatively the recipient field (TO) can be filled with the sender address or the administrator address from the system notifications. Note: All emails to multiple recipients will then also be sent to the email address in the recipient field (TO). (Default: Sender) + E-mail sending mode + In 'Bundled' mode, emails to multiple recipients are grouped together. An e-mail then receives a configured number of recipients in the TO or BCC field. This is useful if the hoster does not allow sending many emails. In 'Single' mode, each recipient receives a separate e-mail. In this mode, additional fields can be added to an email template. + Bundled + Single The role \'administrator\' must have at least one member assigned! Here you can define conditions for each field in your list. This will further restrict the determined members of the selected role with your conditions. Name diff --git a/adm_program/modules/ecards/ecard_function.php b/adm_program/modules/ecards/ecard_function.php index bbcc7fccc6..b57f72d613 100644 --- a/adm_program/modules/ecards/ecard_function.php +++ b/adm_program/modules/ecards/ecard_function.php @@ -151,12 +151,13 @@ public function parseEcardTemplate($imageName, $ecardMessage, $ecardData, $recip * @param string $senderName * @param string $senderEmail * @param string $ecardHtmlData geparste Daten vom Template - * @param string $recipientName der Name des Empfaengers + * @param string $recipientFirstName der Name des Empfaengers + * @param string $recipientLastName der Name des Empfaengers * @param string $recipientEmail die Email des Empfaengers * @param string $photoServerPath der Pfad wo die Bilder in der Grußkarte am Server liegen * @return bool|string */ - public function sendEcard($senderName, $senderEmail, $ecardHtmlData, $recipientName, $recipientEmail, $photoServerPath) + public function sendEcard($senderName, $senderEmail, $ecardHtmlData, $recipientFirstName, $recipientLastName, $recipientEmail, $photoServerPath) { global $gSettingsManager, $gLogger; @@ -166,7 +167,7 @@ public function sendEcard($senderName, $senderEmail, $ecardHtmlData, $recipientN $email = new Email(); $email->setSender($senderEmail, $senderName); $email->setSubject($this->newMessageReceivedString); - $email->addRecipient($recipientEmail, $recipientName); + $email->addRecipient($recipientEmail, $recipientFirstName, $recipientLastName); // alle Bilder werden aus dem Template herausgeholt, damit diese als Anhang verschickt werden koennen if (preg_match_all('/()/Uim', $ecardHtmlData, $matchArray)) { diff --git a/adm_program/modules/ecards/ecard_send.php b/adm_program/modules/ecards/ecard_send.php index c96c227c42..d494eba2ef 100644 --- a/adm_program/modules/ecards/ecard_send.php +++ b/adm_program/modules/ecards/ecard_send.php @@ -144,7 +144,7 @@ if ($ecardSendResult) { // create and send ecard $ecardHtmlData = $funcClass->parseEcardTemplate($imageUrl, $postMessage, $ecardDataToParse, $row['first_name'].' '.$row['last_name'], $row['email']); - $ecardSendResult = $funcClass->sendEcard($senderName, $senderEmail, $ecardHtmlData, $row['first_name'].' '.$row['last_name'], $row['email'], $imageServerPath); + $ecardSendResult = $funcClass->sendEcard($senderName, $senderEmail, $ecardHtmlData, $row['first_name'], $row['last_name'], $row['email'], $imageServerPath); } } @@ -183,7 +183,7 @@ if ($ecardSendResult) { // create and send ecard $ecardHtmlData = $funcClass->parseEcardTemplate($imageUrl, $postMessage, $ecardDataToParse, $row['first_name'].' '.$row['last_name'], $row['email']); - $ecardSendResult = $funcClass->sendEcard($senderName, $senderEmail, $ecardHtmlData, $row['first_name'].' '.$row['last_name'], $row['email'], $imageServerPath); + $ecardSendResult = $funcClass->sendEcard($senderName, $senderEmail, $ecardHtmlData, $row['first_name'], $row['last_name'], $row['email'], $imageServerPath); } } diff --git a/adm_program/modules/preferences/preferences.php b/adm_program/modules/preferences/preferences.php index 1b32e369b6..2fc53cbc41 100644 --- a/adm_program/modules/preferences/preferences.php +++ b/adm_program/modules/preferences/preferences.php @@ -513,6 +513,32 @@ function getPreferencePanel($group, $id, $parentId, $title, $icon, $body) $formValues['mail_sendmail_name'], array('maxLength' => 50, 'helpTextIdInline' => 'SYS_SENDER_NAME_DESC') ); + +// Add js to show or hide mail options +$page->addJavascript(' + $(function(){ + var fieldsToHideOnSingleMode = "#mail_recipients_with_roles_group, #mail_into_to_group, #mail_number_recipients_group"; + if($("#mail_sending_mode").val() == 1) { + $(fieldsToHideOnSingleMode).hide(); + } + $("#mail_sending_mode").on("change", function() { + if($("#mail_sending_mode").val() == 1) { + $(fieldsToHideOnSingleMode).hide(); + } else { + $(fieldsToHideOnSingleMode).show(); + } + }); + }); +'); + +$selectBoxEntries = array(0 => $gL10n->get('SYS_MAIL_BULK'), 1 => $gL10n->get('SYS_MAIL_SINGLE')); +$formEmailDispatch->addSelectBox( + 'mail_sending_mode', + $gL10n->get('SYS_MAIL_SENDING_MODE'), + $selectBoxEntries, + array('defaultValue' => $formValues['mail_sending_mode'], 'showContextDependentFirstEntry' => false, 'helpTextIdInline' => 'SYS_MAIL_SENDING_MODE_DESC') +); + $selectBoxEntries = array(0 => $gL10n->get('SYS_HIDDEN'), 1 => $gL10n->get('SYS_SENDER'), 2 => $gL10n->get('SYS_ADMINISTRATOR')); $formEmailDispatch->addSelectBox( 'mail_recipients_with_roles', @@ -532,6 +558,7 @@ function getPreferencePanel($group, $id, $parentId, $title, $icon, $body) $formValues['mail_number_recipients'], array('type' => 'number', 'minNumber' => 0, 'maxNumber' => 9999, 'step' => 1, 'helpTextIdInline' => 'SYS_NUMBER_RECIPIENTS_DESC') ); + $selectBoxEntries = array('iso-8859-1' => $gL10n->get('SYS_ISO_8859_1'), 'utf-8' => $gL10n->get('SYS_UTF8')); $formEmailDispatch->addSelectBox( 'mail_character_encoding', diff --git a/adm_program/system/classes/Email.php b/adm_program/system/classes/Email.php index 3a65bd60c6..ad3b6862c2 100644 --- a/adm_program/system/classes/Email.php +++ b/adm_program/system/classes/Email.php @@ -73,6 +73,9 @@ class Email extends PHPMailer public const EMAIL_ONLY_ACTIVE_MEMBERS = 1; public const EMAIL_ONLY_FORMER_MEMBERS = 2; + public const SENDINGMODE_BULK = 1; + public const SENDINGMODE_SINGLE = 1; + /** * @var string Plain text of email */ @@ -101,6 +104,10 @@ class Email extends PHPMailer * @var bool */ private $emSendAsHTML = false; + /** + * @var int The sending mode from the settings: 0 = BULK, 1 = SINGLE + */ + private $sendingMode = Email::SENDINGMODE_BULK; /** * @var array> */ @@ -139,6 +146,7 @@ public function __construct() $this->isMail(); } + $this->sendingMode = $gSettingsManager->getInt('mail_sending_mode'); // set language for error reporting $this->setLanguage($gL10n->getLanguageIsoCode()); $this->CharSet = $gSettingsManager->getString('mail_character_encoding'); @@ -149,19 +157,24 @@ public function __construct() * in the recipients list. The decision if the recipient will be sent as TO or BCC will be done later * in the email send process. * @param string $address A valid email address to which the email should be sent. - * @param string $name The name of the recipient that will be shown in the email header. + * @param string $firstName The first name of the recipient that will be shown in the email header. + * @param string $lastName The last name of the recipient that will be shown in the email header. + * @param array $additionalFields Additional fields to map in a Key Value like Array. Not used at all yet. * @return bool Returns **true** if the address was added to the recipients list. */ - public function addRecipient($address, $name = '') + public function addRecipient($address, $firstName = '', $lastName = '', $additionalFields = array()) { // Recipients must be Ascii-US formatted, so encode in MimeHeader - $asciiName = stripslashes($name); + $asciiName = stripslashes($firstName . ' ' . $lastName); // check if valid email address and if email not in the recipients array if (StringUtils::strValidCharacters($address, 'email') && array_search($address, array_column($this->emRecipientsArray, 'address')) === false) { - $this->emRecipientsArray[] = array('name' => $asciiName, 'address' => $address); - $this->emRecipientsNames[] = $name; + $recipient = array('name' => $asciiName, 'address' => $address, 'firstname' => $firstName, 'surname' => $lastName); + $recipient = array_merge($recipient , $additionalFields); + $this->emRecipientsArray[] = $recipient; + $this->emRecipientsNames[] = $firstName . ' ' . $lastName; + return true; } return false; @@ -252,7 +265,7 @@ public function addRecipientsByRole($roleUuid, $memberStatus = self::EMAIL_ONLY_ // all email addresses will be attached as BCC while ($row = $statement->fetch()) { if (StringUtils::strValidCharacters($row['email'], 'email')) { - $this->addRecipient($row['email'], $row['firstname'] . ' ' . $row['lastname']); + $this->addRecipient($row['email'], $row['firstname'], $row['lastname']); ++$numberRecipientsAdded; } } @@ -306,7 +319,7 @@ public function addRecipientsByUserId($userId) // all email addresses will be attached as BCC while ($row = $statement->fetch()) { if (StringUtils::strValidCharacters($row['email'], 'email')) { - $this->addRecipient($row['email'], $row['firstname'] . ' ' . $row['lastname']); + $this->addRecipient($row['email'], $row['firstname'], $row['lastname']); ++$numberRecipientsAdded; } } @@ -320,20 +333,20 @@ public function addRecipientsByUserId($userId) /** * method adds CC recipients to mail * @param string $address - * @param string $name + * @param string $lastName * @return true|string */ - public function addCopy($address, $name = '') + public function addCopy($address, $firstName = '', $lastName = '') { try { - $this->addCC($address, $name); + $this->addCC($address, $firstName .' '. $lastName); } catch (Exception $e) { return $e->errorMessage(); } catch (\Exception $e) { return $e->getMessage(); } - $this->emRecipientsNames[] = $name; + $this->emRecipientsNames[] = $lastName; return true; } @@ -342,13 +355,13 @@ public function addCopy($address, $name = '') * method adds BCC recipients to mail * Bcc Empfänger werden ersteinmal gesammelt, damit später Päckchen verschickt werden können * @param string $address - * @param string $name + * @param string $lastName * @return bool * @deprecated 4.2.0:4.3.0 "addBlindCopy()" is deprecated, use "addRecipient()" instead. */ - public function addBlindCopy($address, $name = '') + public function addBlindCopy($address, $firstName = '', $lastName = '') { - return $this->addRecipient($address, $name); + return $this->addRecipient($address, $firstName, $lastName); } /** @@ -565,6 +578,30 @@ public function setTemplateText($text, $senderName, $senderEmail, $senderUuid, $ $this->emHtmlText = $emailHtmlText; } + + /** + * Add the user specific template text to the email message and replace the plaeholders of the template. + * @param string $text Email text that should be send + * @param string $firstname Receiver firstname + * @param string $surname Receiver surname + * @param string $email Receiver email address + * @param string $name Receiver firstname and surname + */ + public function setUserSpecificTemplateText($text, $firstName, $surname, $email, $name) + { + // replace all line feeds within the mailtext into simple breaks because only those are valid within mails + $text = str_replace("\r\n", "\n", $text); + + // replace parameters in email template + $replaces = array( + '#receiver_firstname#' => $firstName, + '#receiver_lastname#' => $surname, + '#receiver_email#' => $email, + '#receiver_name#' => $name + ); + return StringUtils::strMultiReplace($text, $replaces); + } + /** * Funktion um den Nachrichtentext an die Mail uebergeben * @param string $text @@ -628,72 +665,94 @@ private function sendCopyMail() * Method will send the email to all recipients. Therefore, the method will evaluate how to send the email. * If it's necessary all recipients will be added to BCC and also smaller packages of recipients will be * created. So maybe several emails will be send. Also a copy to the sender will be send if the preferences are set. + * If the Sending Mode is set to "SINGLE" every e-mail will be send on its own, so there will be send out a lot e-mails. * @return true|string */ public function sendEmail() { global $gSettingsManager, $gLogger, $gDebug, $gValidLogin, $gCurrentUser; - - // add body to the email - if ($this->emSendAsHTML) { - $this->msgHTML($this->emHtmlText); - } else { - $this->Body = $this->emText; - } - try { - // if there is a limit of email recipients than split the recipients into smaller packages - $recipientsArrays = array_chunk($this->emRecipientsArray, $gSettingsManager->getInt('mail_number_recipients')); - - foreach ($recipientsArrays as $recipientsArray) { - // if number of bcc recipients = 1 then send the mail directly to the user and not as bcc - if ($this->countRecipients() === 1) { - // remove all current recipients from mail + // If sending mode is "SINGLE" every E-mail is send on its own, so we do not need to check anything else here + if($this->sendingMode == Email::SENDINGMODE_SINGLE) { + foreach ($this->emRecipientsArray as $recipient) { $this->clearAllRecipients(); - - $this->addAddress($recipientsArray[0]['address'], $recipientsArray[0]['name']); + $this->addAddress($recipient['address'], $recipient['name']); if ($gDebug) { - $gLogger->notice('Email send as TO to ' . $recipientsArray[0]['name'] . ' (' . $recipientsArray[0]['address'] . ')'); + $gLogger->notice('Email send as TO to ' . $recipient['name'] . ' (' . $recipient['address'] . ')'); } - } elseif ($gSettingsManager->getBool('mail_into_to')) { - // remove all current recipients from mail - $this->clearAllRecipients(); - // add all recipients as bcc to the mail - foreach ($recipientsArray as $recipientTO) { - $this->addAddress($recipientTO['address'], $recipientTO['name']); - if ($gDebug) { - $gLogger->notice('Email send as TO to ' . $recipientTO['name'] . ' (' . $recipientTO['address'] . ')'); - } + // add body to the email + if ($this->emSendAsHTML) { + $html = $this->setUserSpecificTemplateText($this->emHtmlText, $recipient['firstname'], $recipient['surname'], $recipient['address'], $recipient['name']); + $this->msgHTML($html); + } else { + $txt = $this->setUserSpecificTemplateText($this->emText, $recipient['firstname'], $recipient['surname'], $recipient['address'], $recipient['name']); + $this->Body = $txt; } + + // now send mail + $this->send(); + } + } else { + // add body to the email + if ($this->emSendAsHTML) { + $this->msgHTML($this->emHtmlText); } else { - // remove only all BCC because to-address could be explicit set if undisclosed recipients won't work - $this->clearBCCs(); - - // normally we need no To-address and set "undisclosed recipients", but if - // that won't work than the following address will be set - if ($gValidLogin && (int) $gSettingsManager->get('mail_recipients_with_roles') === 1) { - // fill recipient with sender address to prevent problems with provider - $this->addAddress($gCurrentUser->getValue('EMAIL'), $gCurrentUser->getValue('FIRST_NAME').' '.$gCurrentUser->getValue('LAST_NAME')); - } elseif ((int) $gSettingsManager->get('mail_recipients_with_roles') === 2 - || (!$gValidLogin && (int) $gSettingsManager->get('mail_recipients_with_roles') === 1)) { - // fill recipient with administrators address to prevent problems with provider - $this->addAddress($gSettingsManager->getString('email_administrator'), $gL10n->get('SYS_ADMINISTRATOR')); - } + $this->Body = $this->emText; + } + + // if there is a limit of email recipients than split the recipients into smaller packages + $recipientsArrays = array_chunk($this->emRecipientsArray, $gSettingsManager->getInt('mail_number_recipients')); + + foreach ($recipientsArrays as $recipientsArray) { + // if number of bcc recipients = 1 then send the mail directly to the user and not as bcc + if ($this->countRecipients() === 1) { + // remove all current recipients from mail + $this->clearAllRecipients(); - // add all recipients as bcc to the mail - foreach ($recipientsArray as $recipientBCC) { - $this->addBCC($recipientBCC['address'], $recipientBCC['name']); + $this->addAddress($recipientsArray[0]['address'], $recipientsArray[0]['name']); if ($gDebug) { - $gLogger->notice('Email send as BCC to ' . $recipientBCC['name'] . ' (' . $recipientBCC['address'] . ')'); + $gLogger->notice('Email send as TO to ' . $recipientsArray[0]['name'] . ' (' . $recipientsArray[0]['address'] . ')'); + } + } elseif ($gSettingsManager->getBool('mail_into_to')) { + // remove all current recipients from mail + $this->clearAllRecipients(); + + // add all recipients as bcc to the mail + foreach ($recipientsArray as $recipientTO) { + $this->addAddress($recipientTO['address'], $recipientTO['name']); + if ($gDebug) { + $gLogger->notice('Email send as TO to ' . $recipientTO['name'] . ' (' . $recipientTO['address'] . ')'); + } + } + } else { + // remove only all BCC because to-address could be explicit set if undisclosed recipients won't work + $this->clearBCCs(); + + // normally we need no To-address and set "undisclosed recipients", but if + // that won't work than the following address will be set + if ($gValidLogin && (int) $gSettingsManager->get('mail_recipients_with_roles') === 1) { + // fill recipient with sender address to prevent problems with provider + $this->addAddress($gCurrentUser->getValue('EMAIL'), $gCurrentUser->getValue('FIRST_NAME').' '.$gCurrentUser->getValue('LAST_NAME')); + } elseif ((int) $gSettingsManager->get('mail_recipients_with_roles') === 2 + || (!$gValidLogin && (int) $gSettingsManager->get('mail_recipients_with_roles') === 1)) { + // fill recipient with administrators address to prevent problems with provider + $this->addAddress($gSettingsManager->getString('email_administrator'), $gL10n->get('SYS_ADMINISTRATOR')); + } + + // add all recipients as bcc to the mail + foreach ($recipientsArray as $recipientBCC) { + $this->addBCC($recipientBCC['address'], $recipientBCC['name']); + if ($gDebug) { + $gLogger->notice('Email send as BCC to ' . $recipientBCC['name'] . ' (' . $recipientBCC['address'] . ')'); + } } } - } - // now send mail - $this->send(); + // now send mail + $this->send(); + } } - // now send the email as a copy to the sender if ($this->emCopyToSender) { $this->sendCopyMail(); diff --git a/adm_program/system/classes/UserRegistration.php b/adm_program/system/classes/UserRegistration.php index 7fe447e6bf..f9985d7ba6 100644 --- a/adm_program/system/classes/UserRegistration.php +++ b/adm_program/system/classes/UserRegistration.php @@ -263,7 +263,7 @@ public function save($updateFingerPrint = true) while ($row = $emailStatement->fetch()) { // send mail that a new registration is available $sysmail = new SystemMail($this->db); - $sysmail->addRecipient($row['email'], $row['first_name']. ' '. $row['last_name']); + $sysmail->addRecipient($row['email'], $row['first_name'], $row['last_name']); $sysmail->sendSystemMail('SYSMAIL_REGISTRATION_WEBMASTER', $this); // TODO Exception handling } }