From 368732246af89fba21f0c6cf3d5250c7a92741d6 Mon Sep 17 00:00:00 2001 From: Jonas Gonka Date: Wed, 25 Jul 2018 15:24:59 +0200 Subject: [PATCH 01/16] Updated the Mail.php file to the changes in PR #12179 --- libraries/src/Mail/Mail.php | 228 +++++++++++++----------------------- 1 file changed, 81 insertions(+), 147 deletions(-) diff --git a/libraries/src/Mail/Mail.php b/libraries/src/Mail/Mail.php index 960c167f57fd3..eac8b31c170f1 100644 --- a/libraries/src/Mail/Mail.php +++ b/libraries/src/Mail/Mail.php @@ -95,10 +95,12 @@ public static function getInstance($id = 'Joomla', $exceptions = true) /** * Send the mail * - * @return boolean Boolean true if successful. + * @return boolean Boolean true if successful, false if exception throwing is disabled. * * @since 11.1 - * @throws \RuntimeException + * + * @throws \RuntimeException if the mail function is disabled + * @throws phpmailerException if sending failed and exception throwing is enabled */ public function Send() { @@ -111,36 +113,25 @@ public function Send() try { - // Try sending with default settings $result = parent::send(); } catch (phpmailerException $e) { - $result = false; - - if ($this->SMTPAutoTLS) + // If auto TLS is disabled just let this bubble up + if (!$this->SMTPAutoTLS) { - /** - * PHPMailer has an issue with servers with invalid certificates - * - * See: https://github.com/PHPMailer/PHPMailer/wiki/Troubleshooting#opportunistic-tls - */ - $this->SMTPAutoTLS = false; - - try - { - // Try it again with TLS turned off - $result = parent::send(); - } - catch (phpmailerException $e) - { - // Keep false for B/C compatibility - $result = false; - } + throw $e; } + + $result = false; } - if ($result == false) + /* + * If sending failed and auto TLS is enabled, retry sending with the feature disabled + * + * See https://github.com/PHPMailer/PHPMailer/wiki/Troubleshooting#opportunistic-tls for more info + */ + if (!$result && $this->SMTPAutoTLS) { throw new \RuntimeException(Text::_($this->ErrorInfo), 500); } @@ -153,35 +144,6 @@ public function Send() return false; } - /** - * Set the From and FromName properties. - * - * @param string $address The sender email address - * @param string $name The sender name - * @param boolean $auto Whether to also set the Sender address, defaults to true - * - * @return boolean - * - * @since 11.1 - */ - public function setFrom($address, $name = '', $auto = true) - { - try - { - if (parent::setFrom($address, $name, $auto) === false) - { - return false; - } - } - catch (phpmailerException $e) - { - // The parent method will have already called the logging callback, just log our deprecated error handling message - Log::add(__METHOD__ . '() will not catch phpmailerException objects as of 4.0.', Log::WARNING, 'deprecated'); - - return false; - } - } - /** * Set the email sender * @@ -192,50 +154,40 @@ public function setFrom($address, $name = '', $auto = true) * @return Mail|boolean Returns this object for chaining on success or boolean false on failure. * * @since 11.1 - * @throws \UnexpectedValueException + * + * @throws \UnexpectedValueException if the sender is not a valid address + * @throws phpmailerException if setting the sender failed and exception throwing is enabled */ public function setSender($from) { - // Wrapped in try/catch if PHPMailer is configured to throw exceptions - try + if (is_array($from)) { - if (is_array($from)) - { - // If $from is an array we assume it has an address and a name - if (isset($from[2])) - { - // If it is an array with entries, use them - $result = $this->setFrom(MailHelper::cleanLine($from[0]), MailHelper::cleanLine($from[1]), (bool) $from[2]); - } - else - { - $result = $this->setFrom(MailHelper::cleanLine($from[0]), MailHelper::cleanLine($from[1])); - } - } - elseif (is_string($from)) + // If $from is an array we assume it has an adress and a name + if (isset($from[2])) { - // If it is a string we assume it is just the address - $result = $this->setFrom(MailHelper::cleanLine($from)); + // If it is an array with entries, use them + $result = $this->setFrom(MailHelper::cleanLine($from[0]), MailHelper::cleanLine($from[1]), (bool) $from[2]); } else { - // If it is neither, we log a message and throw an exception - Log::add(Text::sprintf('JLIB_MAIL_INVALID_EMAIL_SENDER', $from), Log::WARNING, 'jerror'); - - throw new \UnexpectedValueException(sprintf('Invalid email Sender: %s, Mail::setSender(%s)', $from)); - } - - // Check for boolean false return if exception handling is disabled - if ($result === false) - { - return false; + $result = $this->setFrom(MailHelper::cleanLine($from[0]), MailHelper::cleanLine($from[1])); } } - catch (phpmailerException $e) + elseif (is_string($from)) { - // The parent method will have already called the logging callback, just log our deprecated error handling message - Log::add(__METHOD__ . '() will not catch phpmailerException objects as of 4.0.', Log::WARNING, 'deprecated'); + // If it is a string we assume it is just the address + $result = $this->setFrom(MailHelper::cleanLine($from)); + } + else + { + // If it is neither, we log a message and throw an exception + Log::add(Text::sprintf('JLIB_MAIL_INVALID_EMAIL_SENDER', $from), Log::WARNING, 'jerror'); + + throw new \UnexpectedValueException(sprintf('Invalid email Sender: %s, Mail::setSender(%s)', $from)); + } + if ($result === false) + { return false; } @@ -288,7 +240,9 @@ public function setBody($content) * @return Mail|boolean Returns this object for chaining on success or boolean false on failure. * * @since 11.1 - * @throws \InvalidArgumentException + * + * @throws \InvalidArgumentException if the argument array counts do not match + * @throws phpmailerException if setting the address failed and exception throwing is enabled */ protected function add($recipient, $name = '', $method = 'addAddress') { @@ -311,20 +265,9 @@ protected function add($recipient, $name = '', $method = 'addAddress') $recipientEmail = MailHelper::cleanLine($recipientEmail); $recipientName = MailHelper::cleanLine($recipientName); - // Wrapped in try/catch if PHPMailer is configured to throw exceptions - try - { - // Check for boolean false return if exception handling is disabled - if (call_user_func('parent::' . $method, $recipientEmail, $recipientName) === false) - { - return false; - } - } - catch (phpmailerException $e) + // Check for boolean false return if exception handling is disabled + if (call_user_func('parent' . $method, $recipientEmail, $recipientName) === false) { - // The parent method will have already called the logging callback, just log our deprecated error handling message - Log::add(__METHOD__ . '() will not catch phpmailerException objects as of 4.0.', Log::WARNING, 'deprecated'); - return false; } } @@ -337,20 +280,9 @@ protected function add($recipient, $name = '', $method = 'addAddress') { $to = MailHelper::cleanLine($to); - // Wrapped in try/catch if PHPMailer is configured to throw exceptions - try - { - // Check for boolean false return if exception handling is disabled - if (call_user_func('parent::' . $method, $to, $name) === false) - { - return false; - } - } - catch (phpmailerException $e) + // Check for boolean false return if exception handling is disabled + if (call_user_func('parent::' . $method, $to, $name) === false) { - // The parent method will have already called the logging callback, just log our deprecated error handling message - Log::add(__METHOD__ . '() will not catch phpmailerException objects as of 4.0.', Log::WARNING, 'deprecated'); - return false; } } @@ -360,20 +292,9 @@ protected function add($recipient, $name = '', $method = 'addAddress') { $recipient = MailHelper::cleanLine($recipient); - // Wrapped in try/catch if PHPMailer is configured to throw exceptions - try - { - // Check for boolean false return if exception handling is disabled - if (call_user_func('parent::' . $method, $recipient, $name) === false) - { - return false; - } - } - catch (phpmailerException $e) + // Check for boolean false return if exception handling is disabled + if (call_user_func('parent::' . $method, $recipient, $name) === false) { - // The parent method will have already called the logging callback, just log our deprecated error handling message - Log::add(__METHOD__ . '() will not catch phpmailerException objects as of 4.0.', Log::WARNING, 'deprecated'); - return false; } } @@ -387,9 +308,11 @@ protected function add($recipient, $name = '', $method = 'addAddress') * @param mixed $recipient Either a string or array of strings [email address(es)] * @param mixed $name Either a string or array of strings [name(s)] * - * @return Mail|boolean Returns this object for chaining. + * @return Mail|boolean Returns this object for chaining on success or false on failure when exception throwing is disabled. * * @since 11.1 + * + * @throws phpmailerException if exception throwing is enabled */ public function addRecipient($recipient, $name = '') { @@ -402,9 +325,11 @@ public function addRecipient($recipient, $name = '') * @param mixed $cc Either a string or array of strings [email address(es)] * @param mixed $name Either a string or array of strings [name(s)] * - * @return Mail|boolean Returns this object for chaining on success or boolean false on failure. + * @return Mail|boolean Returns this object for chaining on success or boolean false on failure when exception throwing is enabled. * * @since 11.1 + * + * @throws phpmailerException if exception throwing is enabled */ public function addCc($cc, $name = '') { @@ -423,9 +348,11 @@ public function addCc($cc, $name = '') * @param mixed $bcc Either a string or array of strings [email address(es)] * @param mixed $name Either a string or array of strings [name(s)] * - * @return Mail|boolean Returns this object for chaining on success or boolean false on failure. + * @return Mail|boolean Returns this object for chaining on success or boolean false on failure when exception throwing is disabled. * * @since 11.1 + * + * @throws phpmailerException if exception throwing is enabled */ public function addBcc($bcc, $name = '') { @@ -447,29 +374,33 @@ public function addBcc($bcc, $name = '') * @param mixed $type The mime type * @param string $disposition The disposition of the attachment * - * @return Mail|boolean Returns this object for chaining on success or boolean false on failure. + * @return Mail|boolean Returns this object for chaining on success or boolean false on failure when exception throwing is disabled. * * @since 12.2 - * @throws \InvalidArgumentException + * @throws \InvalidArgumentException if the argument array counts do not match + * @throws phpmailerException if setting the attatchment failed and exception throwing is enabled */ public function addAttachment($path, $name = '', $encoding = 'base64', $type = 'application/octet-stream', $disposition = 'attachment') { // If the file attachments is an array, add each file... otherwise just add the one if (isset($path)) { - // Wrapped in try/catch if PHPMailer is configured to throw exceptions - try + $result = true; + + if (is_array($path)) { - $result = true; + if (!empty($name) && count($path) != count($name)) + { + throw new \InvalidArgumentException('The number of attachments must be equal with the number of name'); + } - if (is_array($path)) + foreach ($path as $key => $file) { - if (!empty($name) && count($path) != count($name)) + if (!empty($name)) { - throw new \InvalidArgumentException('The number of attachments must be equal with the number of name'); + $result = parent::addAttachment($file, $name[$key], $encoding, $type); } - - foreach ($path as $key => $file) + else { if (!empty($name)) { @@ -481,10 +412,6 @@ public function addAttachment($path, $name = '', $encoding = 'base64', $type = ' } } } - else - { - $result = parent::addAttachment($path, $name, $encoding, $type, $disposition); - } // Check for boolean false return if exception handling is disabled if ($result === false) @@ -492,11 +419,14 @@ public function addAttachment($path, $name = '', $encoding = 'base64', $type = ' return false; } } - catch (phpmailerException $e) + else { - // The parent method will have already called the logging callback, just log our deprecated error handling message - Log::add(__METHOD__ . '() will not catch phpmailerException objects as of 4.0.', Log::WARNING, 'deprecated'); + $result = parent::addAttachment($path, $name, $encoding, $type); + } + // Check for boolean false return if exception handling is disabled + if ($result === false) + { return false; } } @@ -543,9 +473,11 @@ public function removeAttachment($index = 0) * @param mixed $replyto Either a string or array of strings [email address(es)] * @param mixed $name Either a string or array of strings [name(s)] * - * @return Mail|boolean Returns this object for chaining on success or boolean false on failure. + * @return Mail|boolean Returns this object for chaining on success or boolean false on failure when exception throwing is disabled. * * @since 11.1 + * + * @throws phpmailerException if exception throwing is enabled */ public function addReplyTo($replyto, $name = '') { @@ -676,9 +608,11 @@ public function useSmtp($auth = null, $host = null, $user = null, $pass = null, * @param mixed $replyTo Reply to email address(es) * @param mixed $replyToName Reply to name(s) * - * @return boolean True on success + * @return boolean True on success, false on failure when exception throwing is disabled. * * @since 11.1 + * + * @throws phpmailerException if exception throwing is enabled */ public function sendMail($from, $fromName, $recipient, $subject, $body, $mode = false, $cc = null, $bcc = null, $attachment = null, $replyTo = null, $replyToName = null) From 90a6220a8435052055b9d8fbd6c67cca11c7d2af Mon Sep 17 00:00:00 2001 From: Jonas Gonka Date: Fri, 27 Jul 2018 09:56:49 +0200 Subject: [PATCH 02/16] Added Exception Handling for the Mails that get send after sending private messages in the Backend --- .../com_messages/Model/MessageModel.php | 52 ++++++++++++------- 1 file changed, 33 insertions(+), 19 deletions(-) diff --git a/administrator/components/com_messages/Model/MessageModel.php b/administrator/components/com_messages/Model/MessageModel.php index cb8a7aed7ff6d..887f42381b72e 100644 --- a/administrator/components/com_messages/Model/MessageModel.php +++ b/administrator/components/com_messages/Model/MessageModel.php @@ -360,40 +360,54 @@ public function save($data) // Send the email $mailer = Factory::getMailer(); - if (!$mailer->addReplyTo($fromUser->email, $fromUser->name)) + try { - try + if (!$mailer->addReplyTo($fromUser->email, $fromUser->name)) { - Log::add(Text::_('COM_MESSAGES_ERROR_COULD_NOT_SEND_INVALID_REPLYTO'), Log::WARNING, 'jerror'); + try + { + Log::add(Text::_('COM_MESSAGES_ERROR_COULD_NOT_SEND_INVALID_REPLYTO'), Log::WARNING, 'jerror'); + } + catch (\RuntimeException $exception) + { + Factory::getApplication()->enqueueMessage(Text::_('COM_MESSAGES_ERROR_COULD_NOT_SEND_INVALID_REPLYTO'), 'warning'); + } + + // The message is still saved in the database, we do not allow this failure to cause the entire save routine to fail + return true; } - catch (\RuntimeException $exception) + + if (!$mailer->addRecipient($toUser->email, $toUser->name)) { - Factory::getApplication()->enqueueMessage(Text::_('COM_MESSAGES_ERROR_COULD_NOT_SEND_INVALID_REPLYTO'), 'warning'); + try + { + Log::add(Text::_('COM_MESSAGES_ERROR_COULD_NOT_SEND_INVALID_RECIPIENT'), Log::WARNING, 'jerror'); + } + catch (\RuntimeException $exception) + { + Factory::getApplication()->enqueueMessage(Text::_('COM_MESSAGES_ERROR_COULD_NOT_SEND_INVALID_RECIPIENT'), 'warning'); + } + + // The message is still saved in the database, we do not allow this failure to cause the entire save routine to fail + return true; } - // The message is still saved in the database, we do not allow this failure to cause the entire save routine to fail - return true; - } + $mailer->setSubject($subject); + $mailer->setBody($msg); - if (!$mailer->addRecipient($toUser->email, $toUser->name)) + $mailer->Send(); + } + catch (\Exception $exception) { try { - Log::add(Text::_('COM_MESSAGES_ERROR_COULD_NOT_SEND_INVALID_RECIPIENT'), Log::WARNING, 'jerror'); + Log::add(Text::_($exception->getMessage()), Log::WARNING, 'jerror'); } catch (\RuntimeException $exception) { - Factory::getApplication()->enqueueMessage(Text::_('COM_MESSAGES_ERROR_COULD_NOT_SEND_INVALID_RECIPIENT'), 'warning'); + Factory::getApplication()->enqueueMessage(Text::_($exception->errorMessage()), 'warning'); } - - // The message is still saved in the database, we do not allow this failure to cause the entire save routine to fail - return true; } - - $mailer->setSubject($subject); - $mailer->setBody($msg); - - $mailer->Send(); } return true; From 219201a9fdeea12db4d98aee92dc5e16b10bcc54 Mon Sep 17 00:00:00 2001 From: Jonas Gonka Date: Fri, 27 Jul 2018 13:15:06 +0200 Subject: [PATCH 03/16] Update Mass-Mail Function to handle the Exceptions from the JMail class --- .../components/com_users/Model/MailModel.php | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/administrator/components/com_users/Model/MailModel.php b/administrator/components/com_users/Model/MailModel.php index 7d9d9a1b3011d..65f5f0b5fa746 100644 --- a/administrator/components/com_users/Model/MailModel.php +++ b/administrator/components/com_users/Model/MailModel.php @@ -16,6 +16,7 @@ use Joomla\CMS\Filter\InputFilter; use Joomla\CMS\Language\Text; use Joomla\CMS\Factory; +use Joomla\CMS\Log\Log; /** * Users mail model. @@ -188,7 +189,22 @@ public function send() } // Send the Mail - $rs = $mailer->Send(); + try + { + $rs = $mailer->Send(); + } + catch (\Exception $exception) + { + try + { + Log::add(Text::_($exception->getMessage()), Log::WARNING, 'jerror'); + } + catch (\RuntimeException $exception) + { + Factory::getApplication()->enqueueMessage(Text::_($exception->errorMessage()), 'warning'); + } + } + // Check for an error if ($rs instanceof \Exception) From d6486731f18de1c41d995b3d6b7a3bce9366d629 Mon Sep 17 00:00:00 2001 From: Jonas Gonka Date: Fri, 27 Jul 2018 13:16:38 +0200 Subject: [PATCH 04/16] Update the update notification plugin to handle the new Exceptions from the JMail class --- .../updatenotification/updatenotification.php | 27 ++++++++++++++----- 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/plugins/system/updatenotification/updatenotification.php b/plugins/system/updatenotification/updatenotification.php index bb0dbc4a20b98..f3844465e322b 100644 --- a/plugins/system/updatenotification/updatenotification.php +++ b/plugins/system/updatenotification/updatenotification.php @@ -20,6 +20,7 @@ use Joomla\CMS\Plugin\CMSPlugin; use Joomla\CMS\Component\ComponentHelper; use Joomla\Component\Installer\Administrator\Model\UpdateModel; +use Joomla\CMS\Log\Log; // Uncomment the following line to enable debug mode (update notification email sent every single time) // define('PLG_SYSTEM_UPDATENOTIFICATION_DEBUG', 1); @@ -255,12 +256,26 @@ public function onAfterRender() // Send the emails to the Super Users foreach ($superUsers as $superUser) { - $mailer = Factory::getMailer(); - $mailer->setSender(array($mailFrom, $fromName)); - $mailer->addRecipient($superUser->email); - $mailer->setSubject($email_subject); - $mailer->setBody($email_body); - $mailer->Send(); + try + { + $mailer = Factory::getMailer(); + $mailer->setSender(array($mailFrom, $fromName)); + $mailer->addRecipient($superUser->email); + $mailer->setSubject($email_subject); + $mailer->setBody($email_body); + $mailer->Send(); + } + catch (\Exception $exception) + { + try + { + Log::add(Text::_($exception->getMessage()), Log::WARNING, 'jerror'); + } + catch (\RuntimeException $exception) + { + Factory::getApplication()->enqueueMessage(Text::_($exception->errorMessage()), 'warning'); + } + } } } From 677920d341e80930bb99c81ced803de7ab0b3a83 Mon Sep 17 00:00:00 2001 From: Jonas Gonka Date: Fri, 27 Jul 2018 13:26:06 +0200 Subject: [PATCH 05/16] Update the Contact-Module to handle the exceptions thrown by the JMail class --- .../Controller/ContactController.php | 57 ++++++++++++------- 1 file changed, 36 insertions(+), 21 deletions(-) diff --git a/components/com_contact/Controller/ContactController.php b/components/com_contact/Controller/ContactController.php index d4b7c49a8601c..c78c273a7f36c 100644 --- a/components/com_contact/Controller/ContactController.php +++ b/components/com_contact/Controller/ContactController.php @@ -19,6 +19,7 @@ use Joomla\CMS\Uri\Uri; use Joomla\CMS\Language\Text; use Joomla\CMS\Factory; +use Joomla\CMS\Log\Log; /** * Controller for single contact view @@ -221,32 +222,46 @@ private function _sendEmail($data, $contact, $copy_email_activated) } } - $mail = Factory::getMailer(); - $mail->addRecipient($contact->email_to); - $mail->addReplyTo($email, $name); - $mail->setSender(array($mailfrom, $fromname)); - $mail->setSubject($sitename . ': ' . $subject); - $mail->setBody($body); - $sent = $mail->Send(); - - // If we are supposed to copy the sender, do so. - - // Check whether email copy function activated - if ($copy_email_activated == true && !empty($data['contact_email_copy'])) + try { - $copytext = Text::sprintf('COM_CONTACT_COPYTEXT_OF', $contact->name, $sitename); - $copytext .= "\r\n\r\n" . $body; - $copysubject = Text::sprintf('COM_CONTACT_COPYSUBJECT_OF', $subject); - $mail = Factory::getMailer(); - $mail->addRecipient($email); + $mail->addRecipient($contact->email_to); $mail->addReplyTo($email, $name); $mail->setSender(array($mailfrom, $fromname)); - $mail->setSubject($copysubject); - $mail->setBody($copytext); + $mail->setSubject($sitename . ': ' . $subject); + $mail->setBody($body); $sent = $mail->Send(); - } - return $sent; + // If we are supposed to copy the sender, do so. + + // Check whether email copy function activated + if ($copy_email_activated == true && !empty($data['contact_email_copy'])) { + $copytext = Text::sprintf('COM_CONTACT_COPYTEXT_OF', $contact->name, $sitename); + $copytext .= "\r\n\r\n" . $body; + $copysubject = Text::sprintf('COM_CONTACT_COPYSUBJECT_OF', $subject); + + $mail = Factory::getMailer(); + $mail->addRecipient($email); + $mail->addReplyTo($email, $name); + $mail->setSender(array($mailfrom, $fromname)); + $mail->setSubject($copysubject); + $mail->setBody($copytext); + $sent = $mail->Send(); + } + + return $sent; + + } + catch (\Exception $exception) + { + try + { + Log::add(Text::_($exception->getMessage()), Log::WARNING, 'jerror'); + } + catch (\RuntimeException $exception) + { + Factory::getApplication()->enqueueMessage(Text::_($exception->errorMessage()), 'warning'); + } + } } } From 59b66f1e9eafa0e5d9ee29ccc4cb0efc2d48c60d Mon Sep 17 00:00:00 2001 From: Jonas Gonka Date: Fri, 27 Jul 2018 14:15:36 +0200 Subject: [PATCH 06/16] Update joomla.php When you create a user and the creation email cant be sent, the thrown exception from the JMail class is handled --- plugins/user/joomla/joomla.php | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/plugins/user/joomla/joomla.php b/plugins/user/joomla/joomla.php index 510eef5c45fef..d7d9e395d23eb 100644 --- a/plugins/user/joomla/joomla.php +++ b/plugins/user/joomla/joomla.php @@ -169,13 +169,27 @@ public function onUserAfterSave($user, $isnew, $success, $msg) $user['password_clear'] ); - $res = Factory::getMailer()->sendMail( - $this->app->get('mailfrom'), - $this->app->get('fromname'), - $user['email'], - $emailSubject, - $emailBody - ); + try + { + $res = Factory::getMailer()->sendMail( + $this->app->get('mailfrom'), + $this->app->get('fromname'), + $user['email'], + $emailSubject, + $emailBody + ); + } + catch (\Exception $exception) + { + try + { + Log::add(Text::_($exception->getMessage()), Log::WARNING, 'jerror'); + } + catch (\RuntimeException $exception) + { + Factory::getApplication()->enqueueMessage(Text::_($exception->errorMessage()), 'warning'); + } + } if ($res === false) { From dce551d6b5a4b04a521967a9dfcdbb8d5bac761d Mon Sep 17 00:00:00 2001 From: Jonas Gonka Date: Mon, 30 Jul 2018 10:53:58 +0200 Subject: [PATCH 07/16] Update DisplayController.php When you try to forward an article via email and it fails the exception os caught and handled --- .../Controller/DisplayController.php | 23 +++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/components/com_mailto/Controller/DisplayController.php b/components/com_mailto/Controller/DisplayController.php index 17e6abe51f325..b763a4392cf44 100644 --- a/components/com_mailto/Controller/DisplayController.php +++ b/components/com_mailto/Controller/DisplayController.php @@ -17,6 +17,7 @@ use Joomla\CMS\Uri\Uri; use Joomla\CMS\Language\Text; use Joomla\CMS\Factory; +use Joomla\CMS\Log\Log; /** * Mailer Component Controller. @@ -153,12 +154,26 @@ public function send() $from = MailHelper::cleanAddress($from); $email = PunycodeHelper::emailToPunycode($email); - // Send the email - if (Factory::getMailer()->sendMail($from, $sender, $email, $subject, $body) !== true) + // Try to send the email + try { - $this->setMessage(Text::_('COM_MAILTO_EMAIL_NOT_SENT'), 'notice'); + if (Factory::getMailer()->sendMail($from, $sender, $email, $subject, $body) !== true) + { + $this->setMessage(Text::_('COM_MAILTO_EMAIL_NOT_SENT'), 'notice'); - return $this->mailto(); + return $this->mailto(); + } + } + catch (\Exception $exception) + { + try + { + Log::add(Text::_($exception->getMessage()), Log::WARNING, 'jerror'); + } + catch (\RuntimeException $exception) + { + Factory::getApplication()->enqueueMessage(Text::_($exception->errorMessage()), 'warning'); + } } $this->input->set('view', 'sent'); From 0b53666954719fd4a01c6a82392b7dc3e3dd493d Mon Sep 17 00:00:00 2001 From: Jonas Gonka Date: Mon, 30 Jul 2018 10:55:41 +0200 Subject: [PATCH 08/16] Update RemindModel.php When you try to send a reminder email because you forgot your username and the mail can not be sent the exception is caught and handled. --- components/com_users/Model/RemindModel.php | 29 ++++++++++++++++------ 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/components/com_users/Model/RemindModel.php b/components/com_users/Model/RemindModel.php index eccb84c0fbc78..b3b8fa3bc8228 100644 --- a/components/com_users/Model/RemindModel.php +++ b/components/com_users/Model/RemindModel.php @@ -17,6 +17,7 @@ use Joomla\CMS\Form\Form; use Joomla\CMS\Language\Text; use Joomla\CMS\Factory; +use Joomla\CMS\Log\Log; /** * Remind model class for Users. @@ -190,15 +191,29 @@ public function processRemindRequest($data) $data['link_text'] ); - // Send the password reset request email. - $return = Factory::getMailer()->sendMail($data['mailfrom'], $data['fromname'], $user->email, $subject, $body); - - // Check for an error. - if ($return !== true) + // Try to send the password reset request email. + try { - $this->setError(Text::_('COM_USERS_MAIL_FAILED'), 500); + $return = Factory::getMailer()->sendMail($data['mailfrom'], $data['fromname'], $user->email, $subject, $body); - return false; + // Check for an error. + if ($return !== true) + { + $this->setError(Text::_('COM_USERS_MAIL_FAILED'), 500); + + return false; + } + } + catch (\Exception $exception) + { + try + { + Log::add(Text::_($exception->getMessage()), Log::WARNING, 'jerror'); + } + catch (\RuntimeException $exception) + { + Factory::getApplication()->enqueueMessage(Text::_($exception->errorMessage()), 'warning'); + } } return true; From 5839c8ea490cc3607b703a8ffcad501e4686ddae Mon Sep 17 00:00:00 2001 From: Jonas Gonka Date: Mon, 30 Jul 2018 10:56:25 +0200 Subject: [PATCH 09/16] Update ResetModel.php When you try to send a reset email because you forgot your password and the mail can not be sent the exception is caught and handled. --- components/com_users/Model/ResetModel.php | 25 ++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/components/com_users/Model/ResetModel.php b/components/com_users/Model/ResetModel.php index 03d19248b44b5..3b98fd6758368 100644 --- a/components/com_users/Model/ResetModel.php +++ b/components/com_users/Model/ResetModel.php @@ -19,6 +19,7 @@ use Joomla\CMS\Language\Text; use Joomla\CMS\Router\Route; use Joomla\CMS\User\UserHelper; +use Joomla\CMS\Log\Log; /** * Rest model class for Users. @@ -486,13 +487,27 @@ public function processResetRequest($data) $data['link_text'] ); - // Send the password reset request email. - $return = Factory::getMailer()->sendMail($data['mailfrom'], $data['fromname'], $user->email, $subject, $body); + // Try to send the password reset request email. + try + { + $return = Factory::getMailer()->sendMail($data['mailfrom'], $data['fromname'], $user->email, $subject, $body); - // Check for an error. - if ($return !== true) + // Check for an error. + if ($return !== true) + { + return new \Exception(Text::_('COM_USERS_MAIL_FAILED'), 500); + } + } + catch (\Exception $exception) { - return new \Exception(Text::_('COM_USERS_MAIL_FAILED'), 500); + try + { + Log::add(Text::_($exception->getMessage()), Log::WARNING, 'jerror'); + } + catch (\RuntimeException $exception) + { + Factory::getApplication()->enqueueMessage(Text::_($exception->errorMessage()), 'warning'); + } } return true; From 692e4493f565ab0a2c786f970c8b2b49ef3eb725 Mon Sep 17 00:00:00 2001 From: Jonas Gonka Date: Mon, 30 Jul 2018 15:39:52 +0200 Subject: [PATCH 10/16] Update RegistrationModel.php When you try to try to register a new User account in the frontend, and the registration-mail can not be sent the exception is caught and handled. --- .../com_users/Model/RegistrationModel.php | 85 +++++++++++++++++-- 1 file changed, 80 insertions(+), 5 deletions(-) diff --git a/components/com_users/Model/RegistrationModel.php b/components/com_users/Model/RegistrationModel.php index 2cac04fe013a4..cf1cacba5305e 100644 --- a/components/com_users/Model/RegistrationModel.php +++ b/components/com_users/Model/RegistrationModel.php @@ -26,6 +26,7 @@ use Joomla\CMS\String\PunycodeHelper; use Joomla\CMS\User\UserHelper; use Joomla\CMS\Form\Form; +use Joomla\CMS\Log\Log; /** * Registration model class for Users. @@ -177,7 +178,25 @@ public function activate($token) if ($usercreator->authorise('core.create', 'com_users')) { - $return = Factory::getMailer()->sendMail($data['mailfrom'], $data['fromname'], $row->email, $emailSubject, $emailBody); + try + { + $return = Factory::getMailer()->sendMail($data['mailfrom'], $data['fromname'], $row->email, $emailSubject, $emailBody); + } + catch (\Exception $exception) + { + try + { + Log::add(Text::_($exception->getMessage()), Log::WARNING, 'jerror'); + + $return = false; + } + catch (\RuntimeException $exception) + { + Factory::getApplication()->enqueueMessage(Text::_($exception->errorMessage()), 'warning'); + + $return = false; + } + } // Check for an error. if ($return !== true) @@ -215,7 +234,25 @@ public function activate($token) $data['username'] ); - $return = Factory::getMailer()->sendMail($data['mailfrom'], $data['fromname'], $data['email'], $emailSubject, $emailBody); + try + { + $return = Factory::getMailer()->sendMail($data['mailfrom'], $data['fromname'], $data['email'], $emailSubject, $emailBody); + } + catch (\Exception $exception) + { + try + { + Log::add(Text::_($exception->getMessage()), Log::WARNING, 'jerror'); + + $return = false; + } + catch (\RuntimeException $exception) + { + Factory::getApplication()->enqueueMessage(Text::_($exception->errorMessage()), 'warning'); + + $return = false; + } + } // Check for an error. if ($return !== true) @@ -594,8 +631,28 @@ public function register($temp) } } - // Send the registration email. - $return = Factory::getMailer()->sendMail($data['mailfrom'], $data['fromname'], $data['email'], $emailSubject, $emailBody); + // Try to send the registration email. + try + { + $return = Factory::getMailer()->sendMail($data['mailfrom'], $data['fromname'], $data['email'], $emailSubject, $emailBody); + } + catch (\Exception $exception) + { + try + { + Log::add(Text::_($exception->getMessage()), Log::WARNING, 'jerror'); + + $return = false; + } + catch (\RuntimeException $exception) + { + Factory::getApplication()->enqueueMessage(Text::_($exception->errorMessage()), 'warning'); + + $this->setError(Text::_('COM_MESSAGES_ERROR_MAIL_FAILED'), 500); + + $return = false; + } + } // Send Notification mail to administrators if (($params->get('useractivation') < 2) && ($params->get('mail_to_admin') == 1)) @@ -636,7 +693,25 @@ public function register($temp) // Send mail to all superadministrators id foreach ($rows as $row) { - $return = Factory::getMailer()->sendMail($data['mailfrom'], $data['fromname'], $row->email, $emailSubject, $emailBodyAdmin); + try + { + $return = Factory::getMailer()->sendMail($data['mailfrom'], $data['fromname'], $row->email, $emailSubject, $emailBodyAdmin); + } + catch (\Exception $exception) + { + try + { + Log::add(Text::_($exception->getMessage()), Log::WARNING, 'jerror'); + + $return = false; + } + catch (\RuntimeException $exception) + { + Factory::getApplication()->enqueueMessage(Text::_($exception->errorMessage()), 'warning'); + + $return = false; + } + } // Check for an error. if ($return !== true) From 0e056e72a1f6a3aa90a1b4a34c313d44ae0b200a Mon Sep 17 00:00:00 2001 From: Jonas Gonka Date: Mon, 30 Jul 2018 15:44:36 +0200 Subject: [PATCH 11/16] Updated multiple files to better handle the new exceptions thrown by the JMail class and still display the correct messages. --- .../components/com_users/Model/MailModel.php | 42 ++++++++++--------- .../Controller/ContactController.php | 9 ++-- .../Controller/DisplayController.php | 20 ++++++--- components/com_users/Model/RemindModel.php | 24 +++++++---- components/com_users/Model/ResetModel.php | 20 +++++---- 5 files changed, 71 insertions(+), 44 deletions(-) diff --git a/administrator/components/com_users/Model/MailModel.php b/administrator/components/com_users/Model/MailModel.php index 65f5f0b5fa746..9b574e6d67339 100644 --- a/administrator/components/com_users/Model/MailModel.php +++ b/administrator/components/com_users/Model/MailModel.php @@ -171,26 +171,26 @@ public function send() $mailer = Factory::getMailer(); $params = ComponentHelper::getParams('com_users'); - // Build email message format. - $mailer->setSender(array($app->get('mailfrom'), $app->get('fromname'))); - $mailer->setSubject($params->get('mailSubjectPrefix') . stripslashes($subject)); - $mailer->setBody($message_body . $params->get('mailBodySuffix')); - $mailer->IsHtml($mode); - - // Add recipients - if ($bcc) - { - $mailer->addBcc($rows); - $mailer->addRecipient($app->get('mailfrom')); - } - else - { - $mailer->addRecipient($rows); - } - - // Send the Mail try { + // Build email message format. + $mailer->setSender(array($app->get('mailfrom'), $app->get('fromname'))); + $mailer->setSubject($params->get('mailSubjectPrefix') . stripslashes($subject)); + $mailer->setBody($message_body . $params->get('mailBodySuffix')); + $mailer->IsHtml($mode); + + // Add recipients + if ($bcc) + { + $mailer->addBcc($rows); + $mailer->addRecipient($app->get('mailfrom')); + } + else + { + $mailer->addRecipient($rows); + } + + // Send the Mail $rs = $mailer->Send(); } catch (\Exception $exception) @@ -198,16 +198,20 @@ public function send() try { Log::add(Text::_($exception->getMessage()), Log::WARNING, 'jerror'); + + $rs = false; } catch (\RuntimeException $exception) { Factory::getApplication()->enqueueMessage(Text::_($exception->errorMessage()), 'warning'); + + $rs = false; } } // Check for an error - if ($rs instanceof \Exception) + if ($rs !== true) { $app->setUserState('com_users.display.mail.data', $data); $this->setError($rs->getError()); diff --git a/components/com_contact/Controller/ContactController.php b/components/com_contact/Controller/ContactController.php index c78c273a7f36c..230004e91de50 100644 --- a/components/com_contact/Controller/ContactController.php +++ b/components/com_contact/Controller/ContactController.php @@ -248,20 +248,23 @@ private function _sendEmail($data, $contact, $copy_email_activated) $mail->setBody($copytext); $sent = $mail->Send(); } - - return $sent; - } catch (\Exception $exception) { try { Log::add(Text::_($exception->getMessage()), Log::WARNING, 'jerror'); + + $sent = false; } catch (\RuntimeException $exception) { Factory::getApplication()->enqueueMessage(Text::_($exception->errorMessage()), 'warning'); + + $sent = false; } } + + return $sent; } } diff --git a/components/com_mailto/Controller/DisplayController.php b/components/com_mailto/Controller/DisplayController.php index b763a4392cf44..da12704656453 100644 --- a/components/com_mailto/Controller/DisplayController.php +++ b/components/com_mailto/Controller/DisplayController.php @@ -157,25 +157,33 @@ public function send() // Try to send the email try { - if (Factory::getMailer()->sendMail($from, $sender, $email, $subject, $body) !== true) - { - $this->setMessage(Text::_('COM_MAILTO_EMAIL_NOT_SENT'), 'notice'); - - return $this->mailto(); - } + $return = Factory::getMailer()->sendMail($from, $sender, $email, $subject, $body); } catch (\Exception $exception) { try { Log::add(Text::_($exception->getMessage()), Log::WARNING, 'jerror'); + + $return = false; } catch (\RuntimeException $exception) { Factory::getApplication()->enqueueMessage(Text::_($exception->errorMessage()), 'warning'); + + $return = false; } } + if ($return !== true) + { + $this->setMessage(Text::_('COM_MAILTO_EMAIL_NOT_SENT'), 'notice'); + + $this->setRedirect('index.php', 'COM_MAILTO_EMAIL_NOT_SENT'); + return $this->redirect(); + //return $this->mailto(); + } + $this->input->set('view', 'sent'); $this->display(); } diff --git a/components/com_users/Model/RemindModel.php b/components/com_users/Model/RemindModel.php index b3b8fa3bc8228..0a22a0ffab989 100644 --- a/components/com_users/Model/RemindModel.php +++ b/components/com_users/Model/RemindModel.php @@ -195,27 +195,33 @@ public function processRemindRequest($data) try { $return = Factory::getMailer()->sendMail($data['mailfrom'], $data['fromname'], $user->email, $subject, $body); - - // Check for an error. - if ($return !== true) - { - $this->setError(Text::_('COM_USERS_MAIL_FAILED'), 500); - - return false; - } } catch (\Exception $exception) { try { Log::add(Text::_($exception->getMessage()), Log::WARNING, 'jerror'); + + $return = false; } catch (\RuntimeException $exception) { Factory::getApplication()->enqueueMessage(Text::_($exception->errorMessage()), 'warning'); + + $return = false; } } - return true; + // Check for an error. + if ($return !== true) + { + $this->setError(Text::_('COM_USERS_MAIL_FAILED'), 500); + + return false; + } + else + { + return true; + } } } diff --git a/components/com_users/Model/ResetModel.php b/components/com_users/Model/ResetModel.php index 3b98fd6758368..9753407c417a9 100644 --- a/components/com_users/Model/ResetModel.php +++ b/components/com_users/Model/ResetModel.php @@ -491,26 +491,32 @@ public function processResetRequest($data) try { $return = Factory::getMailer()->sendMail($data['mailfrom'], $data['fromname'], $user->email, $subject, $body); - - // Check for an error. - if ($return !== true) - { - return new \Exception(Text::_('COM_USERS_MAIL_FAILED'), 500); - } } catch (\Exception $exception) { try { Log::add(Text::_($exception->getMessage()), Log::WARNING, 'jerror'); + + $return = false; } catch (\RuntimeException $exception) { Factory::getApplication()->enqueueMessage(Text::_($exception->errorMessage()), 'warning'); + + $return = false; } } - return true; + // Check for an error. + if ($return !== true) + { + return new \Exception(Text::_('COM_USERS_MAIL_FAILED'), 500); + } + else + { + return true; + } } /** From 061933ee5ed09a22a5657a88e46c1293c1ab1bc9 Mon Sep 17 00:00:00 2001 From: Jonas Gonka Date: Mon, 30 Jul 2018 15:46:03 +0200 Subject: [PATCH 12/16] Updated MessageModel.php to better handle the Exceptions thrown in the JMail class. Added new Error Message to translation file. --- .../components/com_messages/Model/MessageModel.php | 8 ++++++++ administrator/language/en-GB/en-GB.com_messages.ini | 1 + 2 files changed, 9 insertions(+) diff --git a/administrator/components/com_messages/Model/MessageModel.php b/administrator/components/com_messages/Model/MessageModel.php index 887f42381b72e..29a1287ac7c50 100644 --- a/administrator/components/com_messages/Model/MessageModel.php +++ b/administrator/components/com_messages/Model/MessageModel.php @@ -402,10 +402,18 @@ public function save($data) try { Log::add(Text::_($exception->getMessage()), Log::WARNING, 'jerror'); + + $this->setError(Text::_('COM_MESSAGES_ERROR_MAIL_FAILED'), 500); + + return false; } catch (\RuntimeException $exception) { Factory::getApplication()->enqueueMessage(Text::_($exception->errorMessage()), 'warning'); + + $this->setError(Text::_('COM_MESSAGES_ERROR_MAIL_FAILED'), 500); + + return false; } } } diff --git a/administrator/language/en-GB/en-GB.com_messages.ini b/administrator/language/en-GB/en-GB.com_messages.ini index 381321a924b9e..b482f36fa452c 100644 --- a/administrator/language/en-GB/en-GB.com_messages.ini +++ b/administrator/language/en-GB/en-GB.com_messages.ini @@ -15,6 +15,7 @@ COM_MESSAGES_ERROR_INVALID_FROM_USER="Invalid sender" COM_MESSAGES_ERROR_INVALID_MESSAGE="Invalid message content" COM_MESSAGES_ERROR_INVALID_SUBJECT="Invalid subject" COM_MESSAGES_ERROR_INVALID_TO_USER="Invalid recipient" +COM_MESSAGES_ERROR_MAIL_FAILED="The email message could not be sent." COM_MESSAGES_FIELD_AUTO_PURGE_LABEL="Auto-delete Messages (days)" COM_MESSAGES_FIELD_DATE_TIME_LABEL="Posted" COM_MESSAGES_FIELD_LOCK_LABEL="Lock Inbox" From 62d2508c2e9b68ddaac905515f49917d479eedda Mon Sep 17 00:00:00 2001 From: Jonas Gonka Date: Tue, 31 Jul 2018 08:41:37 +0200 Subject: [PATCH 13/16] Removed unnecessary redirect from DisplayController.php --- components/com_mailto/Controller/DisplayController.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/com_mailto/Controller/DisplayController.php b/components/com_mailto/Controller/DisplayController.php index da12704656453..c451e4e79ad49 100644 --- a/components/com_mailto/Controller/DisplayController.php +++ b/components/com_mailto/Controller/DisplayController.php @@ -180,8 +180,8 @@ public function send() $this->setMessage(Text::_('COM_MAILTO_EMAIL_NOT_SENT'), 'notice'); $this->setRedirect('index.php', 'COM_MAILTO_EMAIL_NOT_SENT'); - return $this->redirect(); - //return $this->mailto(); + + return $this->mailto(); } $this->input->set('view', 'sent'); From 198c7d03e3393084604efecbf124d6f5cf191cd6 Mon Sep 17 00:00:00 2001 From: Jonas Gonka Date: Tue, 31 Jul 2018 08:43:05 +0200 Subject: [PATCH 14/16] Improved Exception handling in the joomla.php that is used when creating users in the backend. --- plugins/user/joomla/joomla.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/plugins/user/joomla/joomla.php b/plugins/user/joomla/joomla.php index d7d9e395d23eb..95cacbb137e17 100644 --- a/plugins/user/joomla/joomla.php +++ b/plugins/user/joomla/joomla.php @@ -184,10 +184,14 @@ public function onUserAfterSave($user, $isnew, $success, $msg) try { Log::add(Text::_($exception->getMessage()), Log::WARNING, 'jerror'); + + $res = false; } catch (\RuntimeException $exception) { Factory::getApplication()->enqueueMessage(Text::_($exception->errorMessage()), 'warning'); + + $res = false; } } From 012279675a3c4ab385459a169bd4ca235de53a11 Mon Sep 17 00:00:00 2001 From: Jonas Gonka Date: Tue, 31 Jul 2018 10:04:35 +0200 Subject: [PATCH 15/16] Updated translation file --- administrator/language/en-GB/en-GB.com_messages.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/administrator/language/en-GB/en-GB.com_messages.ini b/administrator/language/en-GB/en-GB.com_messages.ini index b482f36fa452c..4b877469b5ea5 100644 --- a/administrator/language/en-GB/en-GB.com_messages.ini +++ b/administrator/language/en-GB/en-GB.com_messages.ini @@ -15,7 +15,7 @@ COM_MESSAGES_ERROR_INVALID_FROM_USER="Invalid sender" COM_MESSAGES_ERROR_INVALID_MESSAGE="Invalid message content" COM_MESSAGES_ERROR_INVALID_SUBJECT="Invalid subject" COM_MESSAGES_ERROR_INVALID_TO_USER="Invalid recipient" -COM_MESSAGES_ERROR_MAIL_FAILED="The email message could not be sent." +COM_MESSAGES_ERROR_MAIL_FAILED="The email could not be sent." COM_MESSAGES_FIELD_AUTO_PURGE_LABEL="Auto-delete Messages (days)" COM_MESSAGES_FIELD_DATE_TIME_LABEL="Posted" COM_MESSAGES_FIELD_LOCK_LABEL="Lock Inbox" From 6bdc62b6e1c99d78692ab446c89b221775e51ac5 Mon Sep 17 00:00:00 2001 From: Jonas Gonka Date: Tue, 31 Jul 2018 10:08:51 +0200 Subject: [PATCH 16/16] Fixed a code-style issue --- components/com_contact/Controller/ContactController.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/components/com_contact/Controller/ContactController.php b/components/com_contact/Controller/ContactController.php index 230004e91de50..75601b9aa3d1d 100644 --- a/components/com_contact/Controller/ContactController.php +++ b/components/com_contact/Controller/ContactController.php @@ -235,7 +235,8 @@ private function _sendEmail($data, $contact, $copy_email_activated) // If we are supposed to copy the sender, do so. // Check whether email copy function activated - if ($copy_email_activated == true && !empty($data['contact_email_copy'])) { + if ($copy_email_activated == true && !empty($data['contact_email_copy'])) + { $copytext = Text::sprintf('COM_CONTACT_COPYTEXT_OF', $contact->name, $sitename); $copytext .= "\r\n\r\n" . $body; $copysubject = Text::sprintf('COM_CONTACT_COPYSUBJECT_OF', $subject);