Index: t3lib/class.t3lib_beuserauth.php =================================================================== --- t3lib/class.t3lib_beuserauth.php (revision 10197) +++ t3lib/class.t3lib_beuserauth.php (working copy) @@ -74,7 +74,6 @@ var $userident_column = 'password'; // Column for password var $userid_column = 'uid'; // Column for user-id var $lastLogin_column = 'lastlogin'; - var $notifyHeader = 'From: TYPO3 Login notify '; var $enablecolumns = Array( 'rootLevel' => 1, @@ -348,21 +347,27 @@ $prefix = '[AdminLoginWarning]'; } if ($warn) { - t3lib_utility_Mail::mail($GLOBALS['TYPO3_CONF_VARS']['BE']['warning_email_addr'], - $prefix . ' ' . $subject, - $msg, - $this->notifyHeader - ); + $from = t3lib_utility_Mail::getSystemFromAddress(); + /** @var $mail t3lib_mail_Message */ + $mail = t3lib_div::makeInstance('t3lib_mail_Message'); + $mail->addTo($GLOBALS['TYPO3_CONF_VARS']['BE']['warning_email_addr']) + ->addFrom($from) + ->setSubject($prefix . ' ' . $subject) + ->setBody($msg); + $mail->send(); } } // If An email should be sent to the current user, do that: if ($this->uc['emailMeAtLogin'] && strstr($this->user['email'], '@')) { - t3lib_utility_Mail::mail($this->user['email'], - $subject, - $msg, - $this->notifyHeader - ); + $from = t3lib_utility_Mail::getSystemFromAddress(); + /** @var $mail t3lib_mail_Message */ + $mail = t3lib_div::makeInstance('t3lib_mail_Message'); + $mail->addTo($this->user['email']) + ->addFrom($from) + ->setSubject($subject) + ->setBody($msg); + $mail->send(); } } } Index: t3lib/class.t3lib_div.php =================================================================== --- t3lib/class.t3lib_div.php (revision 10197) +++ t3lib/class.t3lib_div.php (working copy) @@ -6038,13 +6038,20 @@ // send message per mail elseif ($type == 'mail') { list($to, $from) = explode('/', $destination); - t3lib_utility_Mail::mail($to, 'Warning - error in TYPO3 installation', - 'Host: ' . $TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_div.php']['systemLogHost'] . LF . + if (!t3lib_div::validEmail($from)) { + $from = t3lib_utility_Mail::getSystemFromAddress(); + } + /** @var $mail t3lib_mail_Message */ + $mail = t3lib_div::makeInstance('t3lib_mail_Message'); + $mail->addTo($to) + ->addFrom($from) + ->setSubject('Warning - error in TYPO3 installation') + ->setBody('Host: ' . $TYPO3_CONF_VARS['SC_OPTIONS']['t3lib/class.t3lib_div.php']['systemLogHost'] . LF . 'Extension: ' . $extKey . LF . 'Severity: ' . $severity . LF . - LF . $msg, - ($from ? 'From: ' . $from : '') + LF . $msg ); + $mail->send(); } // use the PHP error log elseif ($type == 'error_log') { Index: t3lib/class.t3lib_formmail.php =================================================================== --- t3lib/class.t3lib_formmail.php (revision 10197) +++ t3lib/class.t3lib_formmail.php (working copy) @@ -55,11 +55,28 @@ * @subpackage t3lib * @see tslib_fe::sendFormmail(), t3lib/formmail.php */ -class t3lib_formmail extends t3lib_htmlmail { +class t3lib_formmail { protected $reserved_names = 'recipient,recipient_copy,auto_respond_msg,auto_respond_checksum,redirect,subject,attachment,from_email,from_name,replyto_email,replyto_name,organisation,priority,html_enabled,quoted_printable,submit_x,submit_y'; var $dirtyHeaders = array(); // collection of suspicious header data, used for logging + protected $characterSet; + protected $subject; + protected $fromName; + protected $replyToName; + protected $organisation; + protected $fromAddress; + protected $replyToAddress; + protected $priority; + protected $autoRespondMessage; + protected $encoding = 'quoted-printable'; + /** @var t3lib_mail_Message */ + protected $mailMessage; + protected $recipient; + protected $returnPath; + protected $plainContent = ''; + + /** * Start function * This class is able to generate a mail in formmail-style from the data in $V @@ -82,116 +99,153 @@ * @param boolean Whether to base64 encode the mail content * @return void */ - function start($V, $base64 = false) { - $convCharset = FALSE; // do we need to convert form data? + function start($valueList, $base64 = false) { - if ($GLOBALS['TSFE']->config['config']['formMailCharset']) { // Respect formMailCharset if it was set - $this->charset = $GLOBALS['TSFE']->csConvObj->parse_charset($GLOBALS['TSFE']->config['config']['formMailCharset']); - $convCharset = TRUE; + $this->mailMessage = t3lib_div::makeInstance('t3lib_mail_Message'); - } elseif ($GLOBALS['TSFE']->metaCharset != $GLOBALS['TSFE']->renderCharset) { // Use metaCharset for mail if different from renderCharset - $this->charset = $GLOBALS['TSFE']->metaCharset; - $convCharset = TRUE; + if ($GLOBALS['TYPO3_CONF_VARS']['SYS']['forceReturnPath']) { + $this->returnPath = $GLOBALS['TYPO3_CONF_VARS']['SYS']['forceReturnPath']; + $this->mailMessage->setReturnPath($this->returnPath); } + $this->mailMessage->getHeaders()->addTextHeader('X-Mailer', 'TYPO3'); - parent::start(); + if ($GLOBALS['TSFE']->config['config']['formMailCharset']) { + // Respect formMailCharset if it was set + $this->characterSet = $GLOBALS['TSFE']->csConvObj->parse_charset($GLOBALS['TSFE']->config['config']['formMailCharset']); + } elseif ($GLOBALS['TSFE']->metaCharset != $GLOBALS['TSFE']->renderCharset) { + // Use metaCharset for mail if different from renderCharset + $this->characterSet = $GLOBALS['TSFE']->metaCharset; + } - if ($base64 || $V['use_base64']) { - $this->useBase64(); + if ($base64 || $valueList['use_base64']) { + $this->encoding = 'base64'; } - if (isset($V['recipient'])) { + if (isset($valueList['recipient'])) { // convert form data from renderCharset to mail charset - $val = ($V['subject']) ? $V['subject'] : 'Formmail on ' . t3lib_div::getIndpEnv('HTTP_HOST'); - $this->subject = ($convCharset && strlen($val)) ? $GLOBALS['TSFE']->csConvObj->conv($val, $GLOBALS['TSFE']->renderCharset, $this->charset) : $val; + $this->subject = ($valueList['subject']) + ? $valueList['subject'] + : 'Formmail on ' . t3lib_div::getIndpEnv('HTTP_HOST'); $this->subject = $this->sanitizeHeaderString($this->subject); - $val = ($V['from_name']) ? $V['from_name'] : (($V['name']) ? $V['name'] : ''); // Be careful when changing $val! It is used again as the fallback value for replyto_name - $this->from_name = ($convCharset && strlen($val)) ? $GLOBALS['TSFE']->csConvObj->conv($val, $GLOBALS['TSFE']->renderCharset, $this->charset) : $val; - $this->from_name = $this->sanitizeHeaderString($this->from_name); - $this->from_name = preg_match('/\s|,/', $this->from_name) >= 1 ? '"' . $this->from_name . '"' : $this->from_name; - $val = ($V['replyto_name']) ? $V['replyto_name'] : $val; - $this->replyto_name = ($convCharset && strlen($val)) ? $GLOBALS['TSFE']->csConvObj->conv($val, $GLOBALS['TSFE']->renderCharset, $this->charset) : $val; - $this->replyto_name = $this->sanitizeHeaderString($this->replyto_name); - $this->replyto_name = preg_match('/\s|,/', $this->replyto_name) >= 1 ? '"' . $this->replyto_name . '"' : $this->replyto_name; - $val = ($V['organisation']) ? $V['organisation'] : ''; - $this->organisation = ($convCharset && strlen($val)) ? $GLOBALS['TSFE']->csConvObj->conv($val, $GLOBALS['TSFE']->renderCharset, $this->charset) : $val; + + $this->fromName = ($valueList['from_name']) + ? $valueList['from_name'] + : (($valueList['name']) ? $valueList['name'] : ''); + $this->fromName = $this->sanitizeHeaderString($this->fromName); + $this->fromName = preg_match('/\s|,/', $this->fromName) >= 1 ? '"' . $this->fromName . '"' : $this->fromName; + + $this->replyToName = ($valueList['replyto_name']) ? $valueList['replyto_name'] : $this->fromName; + $this->replyToName = $this->sanitizeHeaderString($this->replyToName); + $this->replyToName = preg_match('/\s|,/', $this->replyToName) >= 1 ? '"' . $this->replyToName . '"' : $this->replyToName; + + $this->organisation = ($valueList['organisation']) ? $valueList['organisation'] : ''; $this->organisation = $this->sanitizeHeaderString($this->organisation); - $this->from_email = ($V['from_email']) ? $V['from_email'] : (($V['email']) ? $V['email'] : ''); - $this->from_email = t3lib_div::validEmail($this->from_email) ? $this->from_email : ''; - $this->replyto_email = ($V['replyto_email']) ? $V['replyto_email'] : $this->from_email; - $this->replyto_email = t3lib_div::validEmail($this->replyto_email) ? $this->replyto_email : ''; - $this->priority = ($V['priority']) ? t3lib_div::intInRange($V['priority'], 1, 5) : 3; + $this->fromAddress = ($valueList['from_email']) ? $valueList['from_email'] : ( + ($valueList['email']) ? $valueList['email'] : '' + ); + $this->fromAddress = t3lib_div::validEmail($this->fromAddress) + ? $this->fromAddress + : t3lib_utility_Mail::getSystemFromAddress(); + $this->replyToAddress = ($valueList['replyto_email']) ? $valueList['replyto_email'] : $this->fromAddress; + $this->replyToAddress = t3lib_div::validEmail($this->replyToAddress) + ? $this->replyToAddress + : t3lib_utility_Mail::getSystemFromAddress(); + + $this->priority = ($valueList['priority']) ? t3lib_div::intInRange($valueList['priority'], 1, 5) : 3; + // auto responder - $this->auto_respond_msg = (trim($V['auto_respond_msg']) && $this->from_email) ? trim($V['auto_respond_msg']) : ''; + $this->autoRespondMessage = (trim($valueList['auto_respond_msg']) && $this->fromAddress) + ? trim($valueList['auto_respond_msg']) + : ''; - if ($this->auto_respond_msg !== '') { + if ($this->autoRespondMessage !== '') { // Check if the value of the auto responder message has been modified with evil intentions - $autoRespondChecksum = $V['auto_respond_checksum']; - $correctHmacChecksum = t3lib_div::hmac($this->auto_respond_msg); + $autoRespondChecksum = $valueList['auto_respond_checksum']; + $correctHmacChecksum = t3lib_div::hmac($this->autoRespondMessage); if ($autoRespondChecksum !== $correctHmacChecksum) { - t3lib_div::sysLog('Possible misuse of t3lib_formmail auto respond method. Subject: ' . $V['subject'], 'Core', 3); + t3lib_div::sysLog('Possible misuse of t3lib_formmail auto respond method. Subject: ' . $valueList['subject'], + 'Core', + 3); return; } else { - $this->auto_respond_msg = $this->sanitizeHeaderString($this->auto_respond_msg); + $this->autoRespondMessage = $this->sanitizeHeaderString($this->autoRespondMessage); } } - $Plain_content = ''; - $HTML_content = ''; + $plainTextContent = ''; + $htmlContent = '
'; // Runs through $V and generates the mail - if (is_array($V)) { - foreach ($V as $key => $val) { + if (is_array($valueList)) { + foreach ($valueList as $key => $val) { if (!t3lib_div::inList($this->reserved_names, $key)) { $space = (strlen($val) > 60) ? LF : ''; $val = (is_array($val) ? implode($val, LF) : $val); // convert form data from renderCharset to mail charset (HTML may use entities) - $Plain_val = ($convCharset && strlen($val)) ? $GLOBALS['TSFE']->csConvObj->conv($val, $GLOBALS['TSFE']->renderCharset, $this->charset, 0) : $val; - $HTML_val = ($convCharset && strlen($val)) ? $GLOBALS['TSFE']->csConvObj->conv(htmlspecialchars($val), $GLOBALS['TSFE']->renderCharset, $this->charset, 1) : htmlspecialchars($val); + $plainTextValue = $val; + $HtmlValue = htmlspecialchars($val); - $Plain_content .= strtoupper($key) . ': ' . $space . $Plain_val . LF . $space; - $HTML_content .= ''; + $plainTextContent .= strtoupper($key) . ': ' . $space . $plainTextValue . LF . $space; + $htmlContent .= ''; } } } - $HTML_content .= '
' . strtoupper($key) . '' . nl2br($HTML_val) . ' 
' . strtoupper($key) + . '' . nl2br($HtmlValue) + . ' 
'; + $htmlContent .= ''; - if ($V['html_enabled']) { - $this->setHTML($this->encodeMsg($HTML_content)); + $this->plainContent = $plainTextContent; + + if ($valueList['html_enabled']) { + $this->mailMessage->setBody($htmlContent, 'text/html'); + $this->mailMessage->addPart($plainTextContent, 'text/plain'); + } else { + $this->mailMessage->setBody($plainTextContent, 'text/plain'); } - $this->addPlain($Plain_content); for ($a = 0; $a < 10; $a++) { - $varname = 'attachment' . (($a) ? $a : ''); - if (!isset($_FILES[$varname])) { + $variableName = 'attachment' . (($a) ? $a : ''); + if (!isset($_FILES[$variableName])) { continue; } - if (!is_uploaded_file($_FILES[$varname]['tmp_name'])) { - t3lib_div::sysLog('Possible abuse of t3lib_formmail: temporary file "' . $_FILES[$varname]['tmp_name'] . '" ("' . $_FILES[$varname]['name'] . '") was not an uploaded file.', 'Core', 3); + if (!is_uploaded_file($_FILES[$variableName]['tmp_name'])) { + t3lib_div::sysLog('Possible abuse of t3lib_formmail: temporary file "' . $_FILES[$variableName]['tmp_name'] + . '" ("' . $_FILES[$variableName]['name'] . '") was not an uploaded file.', 'Core', 3); } - if ($_FILES[$varname]['tmp_name']['error'] !== UPLOAD_ERR_OK) { - t3lib_div::sysLog('Error in uploaded file in t3lib_formmail: temporary file "' . $_FILES[$varname]['tmp_name'] . '" ("' . $_FILES[$varname]['name'] . '") Error code: ' . $_FILES[$varname]['tmp_name']['error'], 'Core', 3); + if ($_FILES[$variableName]['tmp_name']['error'] !== UPLOAD_ERR_OK) { + t3lib_div::sysLog('Error in uploaded file in t3lib_formmail: temporary file "' + . $_FILES[$variableName]['tmp_name'] . '" ("' . $_FILES[$variableName]['name'] . '") Error code: ' + . $_FILES[$variableName]['tmp_name']['error'], 'Core', 3); } - $theFile = t3lib_div::upload_to_tempfile($_FILES[$varname]['tmp_name']); - $theName = $_FILES[$varname]['name']; + $theFile = t3lib_div::upload_to_tempfile($_FILES[$variableName]['tmp_name']); + $theName = $_FILES[$variableName]['name']; if ($theFile && file_exists($theFile)) { if (filesize($theFile) < $GLOBALS['TYPO3_CONF_VARS']['FE']['formmailMaxAttachmentSize']) { - $this->addAttachment($theFile, $theName); + $this->mailMessage->attach(Swift_Attachment::fromPath($theFile)->setFilename($theName)); } } t3lib_div::unlink_tempfile($theFile); } - $this->setHeaders(); - $this->setContent(); - $this->setRecipient($V['recipient']); - if ($V['recipient_copy']) { - $this->recipient_copy = trim($V['recipient_copy']); + $this->recipient = $valueList['recipient']; + $this->mailMessage->setSubject($this->subject) + ->setFrom(array($this->fromAddress => $this->fromName)) + ->setTo($this->recipient) + ->setPriority($this->priority); + $this->mailMessage->getHeaders()->addTextHeader('Organization', $this->organisation); + if ($valueList['recipient_copy']) { + $this->mailMessage->addCc(trim($valueList['recipient_copy'])); } + if ($this->characterSet) { + $this->mailMessage->setCharset($this->characterSet); + } + // Ignore target encoding. This is handled automatically by Swift Mailer and overriding the defaults + // is not worth the trouble + // log dirty header lines if ($this->dirtyHeaders) { t3lib_div::sysLog('Possible misuse of t3lib_formmail: see TYPO3 devLog', 'Core', 3); @@ -203,51 +257,12 @@ } /** - * Adds an attachment to the mail - * - * @param string The absolute path to the file to add as attachment - * @param string The files original filename (not necessarily the same as the current since this could be uploaded files...) - * @return boolean True if the file existed and was added. - * @access private - */ - function addAttachment($file, $filename) { - $content = $this->getURL($file); // We fetch the content and the mime-type - $fileInfo = $this->split_fileref($filename); - if ($fileInfo['fileext'] == 'gif') { - $content_type = 'image/gif'; - } - if ($fileInfo['fileext'] == 'bmp') { - $content_type = 'image/bmp'; - } - if ($fileInfo['fileext'] == 'jpg' || $fileInfo['fileext'] == 'jpeg') { - $content_type = 'image/jpeg'; - } - if ($fileInfo['fileext'] == 'html' || $fileInfo['fileext'] == 'htm') { - $content_type = 'text/html'; - } - if (!$content_type) { - $content_type = 'application/octet-stream'; - } - - if ($content) { - $theArr['content_type'] = $content_type; - $theArr['content'] = $content; - $theArr['filename'] = $filename; - $this->theParts['attach'][] = $theArr; - return TRUE; - } else { - return FALSE; - } - } - - - /** * Checks string for suspicious characters * * @param string String to check * @return string Valid or empty string */ - function sanitizeHeaderString($string) { + protected function sanitizeHeaderString($string) { $pattern = '/[\r\n\f\e]/'; if (preg_match($pattern, $string) > 0) { $this->dirtyHeaders[] = $string; @@ -255,6 +270,41 @@ } return $string; } + + /** + * Sends the actual mail and handles autorespond message + * + * @return boolean + */ + public function sendTheMail() { + + // Sending the mail requires the recipient and message to be set. + if (!$this->mailMessage->getTo() || !trim($this->mailMessage->getBody())) { + return FALSE; + } + + $this->mailMessage->send(); + + // Auto response + if ($this->autoRespondMessage) { + $theParts = explode('/', $this->autoRespondMessage, 2); + $theParts[0] = str_replace('###SUBJECT###', $this->subject, $theParts[0]); + $theParts[1] = str_replace("/", LF, $theParts[1]); + $theParts[1] = str_replace("###MESSAGE###", $this->plainContent, $theParts[1]); + + /** @var $autoRespondMail t3lib_mail_Message */ + $autoRespondMail = t3lib_div::makeInstance('t3lib_mail_Message'); + $autoRespondMail->setTo($this->fromAddress) + ->setSubject($theParts[0]) + ->setFrom($this->recipient) + ->setBody($theParts[1]); + if ($this->returnPath) { + $autoRespondMail->setReturnPath($this->returnPath); + } + $autoRespondMail->send(); + } + return $this->mailMessage->isSent(); + } } Index: t3lib/class.t3lib_userauthgroup.php =================================================================== --- t3lib/class.t3lib_userauthgroup.php (revision 10197) +++ t3lib/class.t3lib_userauthgroup.php (working copy) @@ -1902,11 +1902,14 @@ $email_body .= date($GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy'] . ' ' . $GLOBALS['TYPO3_CONF_VARS']['SYS']['hhmm'], $testRows['tstamp']) . ': ' . @sprintf($testRows['details'], '' . $theData[0], '' . $theData[1], '' . $theData[2]); $email_body .= LF; } - t3lib_utility_Mail::mail($email, - $subject, - $email_body, - 'From: TYPO3 Login WARNING<>' - ); + $from = t3lib_utility_Mail::getSystemFromAddress(); + /** @var $mail t3lib_mail_Message */ + $mail = t3lib_div::makeInstance('t3lib_mail_Message'); + $mail->addTo($email) + ->addFrom($from) + ->setSubject($subject) + ->setBody($email_body); + $mail->send(); $this->writelog(255, 4, 0, 3, 'Failure warning (%s failures within %s seconds) sent by email to %s', array($GLOBALS['TYPO3_DB']->sql_num_rows($res), $secondsBack, $email)); // Logout written to log } } Index: t3lib/mail/class.t3lib_mail_swiftmaileradapter.php =================================================================== --- t3lib/mail/class.t3lib_mail_swiftmaileradapter.php (revision 10197) +++ t3lib/mail/class.t3lib_mail_swiftmaileradapter.php (working copy) @@ -256,7 +256,7 @@ // The headers have already been set, so use header information $contentType = $this->message->getContentType(); $charset = $this->message->getCharset(); - $encoding = $this->message->getEncoder(); + $encoding = $this->message->getEncoder()->getName(); // reverse encoding and set body $rawBody = $this->decode($body, $encoding); $this->message->setBody($rawBody, $contentType, $charset); Index: t3lib/utility/class.t3lib_utility_mail.php =================================================================== --- t3lib/utility/class.t3lib_utility_mail.php (revision 10197) +++ t3lib/utility/class.t3lib_utility_mail.php (working copy) @@ -111,6 +111,49 @@ } return $success; } + + /** + * Create a valid email address for the sender of mail messages + * + * @return string Valid email address which can be used as sender + */ + public static function getSystemFromAddress() { + + // first check the localconf setting + $address = $GLOBALS['TYPO3_CONF_VARS']['SYS']['defaultMailFromAddress']; + if (!t3lib_div::validEmail($address)) { + // just get us a domain record we can use + $domainRecord = $GLOBALS['TYPO3_DB']->exec_SELECTgetSingleRow( + 'domainName', + 'sys_domain', + 'hidden = 0', + '', + 'pid ASC, sorting ASC' + ); + if (!empty($domainRecord['domainName'])) { + $tempUrl = $domainRecord['domainName']; + + if (!t3lib_div::isFirstPartOfStr($tempUrl, 'http')) { + // shouldn't be the case anyways, but you never know + // ... there're crazy people out there + $tempUrl = 'http://' .$tempUrl; + } + $host = parse_url($tempUrl, PHP_URL_HOST); + } + $address = 'no-reply@' . $host; + if (!t3lib_div::validEmail($address)) { + // get host name from server + $host = php_uname('n'); + $address = 'no-reply@' . $host; + if (!t3lib_div::validEmail($address)) { + // if everything fails use a dummy address + $address = 'no-reply@example.org'; + } + } + + } + return $address; + } } ?> \ No newline at end of file Index: typo3/sysext/install/mod/class.tx_install.php =================================================================== --- typo3/sysext/install/mod/class.tx_install.php (revision 10197) +++ typo3/sysext/install/mod/class.tx_install.php (working copy) @@ -2689,7 +2689,7 @@ 'message' => $this->mailMessage, 'enterEmail' => 'Enter the email address', 'actionUrl' => $this->action . '#checkMailForm', - 'useHtmlMailLabel' => 'Test t3lib_htmlmail', + 'useHtmlMailLabel' => 'Test t3lib_mail_mailer', 'submit' => 'Send test mail' ); // Fill the markers @@ -2707,16 +2707,14 @@ $email = trim($this->INSTALL['check_mail']); if($this->INSTALL['use_htmlmail']) { - $emailObj = t3lib_div::makeInstance('t3lib_htmlmail'); - /* @var $emailObj t3lib_htmlmail */ - $emailObj->start(); - $emailObj->subject = $subject; - $emailObj->from_email = 'test@test.test'; - $emailObj->from_name = 'TYPO3 Install Tool'; - $emailObj->returnPath = 'null@'.t3lib_div::getIndpEnv('HTTP_HOST'); - $emailObj->addPlain('TEST CONTENT'); - $emailObj->setHTML($emailObj->encodeMsg('HTML TEST CONTENT')); - $emailObj->send($email); + /** @var $mailMessage t3lib_mail_Message */ + $mailMessage = t3lib_div::makeInstance('t3lib_mail_Message'); + $mailMessage->addTo($email) + ->addFrom('typo3installtool@example.org', 'TYPO3 Install Tool') + ->setSubject($subject) + ->setBody('HTML TEST CONTENT'); + $mailMessage->addPart('TEST CONTENT'); + $mailMessage->send(); } else { t3lib_div::plainMailEncoded($email,$subject,'TEST CONTENT','From: test@test.test'); }