diff --git a/include/class.format.php b/include/class.format.php
index 3377b4fe4938ac9d1be98c3ad592bab39bdd3647..e3f7b415a7553f6f77e6da85b31aff4d2c2f9ba5 100644
--- a/include/class.format.php
+++ b/include/class.format.php
@@ -202,7 +202,7 @@ class Format {
     function safe_html($html) {
         // Remove HEAD and STYLE sections
         $html = preg_replace(
-            array(':<(head|style|script).+</\1>:is',   # <head> and <style> sections
+            array(':<(head|style|script).+?</\1>:is', # <head> and <style> sections
                   ':<!\[[^]<]+\]>:',            # <![if !mso]> and friends
                   ':<!DOCTYPE[^>]+>:',          # <!DOCTYPE ... >
                   ':<\?[^>]+>:',                # <?xml version="1.0" ... >
diff --git a/include/class.mailfetch.php b/include/class.mailfetch.php
index 510de3e8354c64e767a860bfea11bb038891f10b..f1ea77d74ac9979bdffccfd195ca76eabd98c3a9 100644
--- a/include/class.mailfetch.php
+++ b/include/class.mailfetch.php
@@ -617,9 +617,11 @@ class MailFetcher {
             // Fetch deliver status report
             $vars['message'] = $this->getDeliveryStatusMessage($mid);
             $vars['thread-type'] = 'N';
+            $vars['flags']['bounce'] = true;
         }
         else {
             $vars['message'] = $this->getBody($mid);
+            $vars['flags']['bounce'] = TicketFilter::isBounce($info);
         }
 
 
diff --git a/include/class.mailparse.php b/include/class.mailparse.php
index 33999522ed0a63e307b46aeec9356388a15b0637..92b275bbec2efa9fc2cc571ccc0e12bb1edbe011 100644
--- a/include/class.mailparse.php
+++ b/include/class.mailparse.php
@@ -584,12 +584,14 @@ class EmailDataParser {
             // Fetch deliver status report
             $data['message'] = $parser->getDeliveryStatusMessage();
             $data['thread-type'] = 'N';
+            $data['flags']['bounce'] = true;
         }
         else {
             // Typical email
             $data['message'] = $parser->getBody();
             $data['in-reply-to'] = @$parser->struct->headers['in-reply-to'];
             $data['references'] = @$parser->struct->headers['references'];
+            $data['flags']['bounce'] = TicketFilter::isBounce($data['header']);
         }
 
         $data['subject'] = $parser->getSubject();
diff --git a/include/class.thread.php b/include/class.thread.php
index b4c10305d09372d91c28ed74094840aa1b0eee14..0722c80d2027ca5691afe4dc37e805911f86658b 100644
--- a/include/class.thread.php
+++ b/include/class.thread.php
@@ -246,7 +246,7 @@ Class ThreadEntry {
         if(!$id && !($id=$this->getId()))
             return false;
 
-        $sql='SELECT thread.*, info.email_mid '
+        $sql='SELECT thread.*, info.email_mid, info.headers '
             .' ,count(DISTINCT attach.attach_id) as attachments '
             .' FROM '.TICKET_THREAD_TABLE.' thread '
             .' LEFT JOIN '.TICKET_EMAIL_INFO_TABLE.' info
@@ -338,18 +338,18 @@ Class ThreadEntry {
         return $this->ht['email_mid'];
     }
 
-    function getEmailHeaders() {
+    function getEmailHeaderArray() {
         require_once(INCLUDE_DIR.'class.mailparse.php');
 
-        $sql = 'SELECT headers FROM '.TICKET_EMAIL_INFO_TABLE
-            .' WHERE thread_id='.$this->getId();
-        $headers = db_result(db_query($sql));
-        return Mail_Parse::splitHeaders($headers);
+        if (!isset($this->ht['@headers']))
+            $this->ht['@headers'] = Mail_Parse::splitHeaders($this->ht['headers']);
+
+        return $this->ht['@headers'];
     }
 
     function getEmailReferences() {
         if (!isset($this->_references)) {
-            $headers = self::getEmailHeaders();
+            $headers = self::getEmailHeaderArray();
             if (isset($headers['References']) && $headers['References'])
                 $this->_references = $headers['References']." ";
             $this->_references .= $this->getEmailMessageId();
@@ -427,8 +427,8 @@ Class ThreadEntry {
     function isAutoReply() {
 
         if (!isset($this->is_autoreply))
-            $this->is_autoreply = $this->getEmailHeader()
-                ?  TicketFilter::isAutoReply($this->getEmailHeader()) : false;
+            $this->is_autoreply = $this->getEmailHeaderArray()
+                ?  TicketFilter::isAutoReply($this->getEmailHeaderArray()) : false;
 
         return $this->is_autoreply;
     }
@@ -436,8 +436,8 @@ Class ThreadEntry {
     function isBounce() {
 
         if (!isset($this->is_bounce))
-            $this->is_bounce = $this->getEmailHeader()
-                ? TicketFilter::isBounce($this->getEmailHeader()) : false;
+            $this->is_bounce = $this->getEmailHeaderArray()
+                ? TicketFilter::isBounce($this->getEmailHeaderArray()) : false;
 
         return $this->is_bounce;
     }
@@ -523,10 +523,10 @@ Class ThreadEntry {
             return 0;
 
         // TODO: Add a unique index to TICKET_ATTACHMENT_TABLE (file_id,
-        // ticket_id), and remove this block
+        // ref_id), and remove this block
         if ($id = db_result(db_query('SELECT attach_id FROM '.TICKET_ATTACHMENT_TABLE
-                .' WHERE file_id='.db_input($fileId).' AND ticket_id='
-                .db_input($this->getTicketId()))))
+                .' WHERE file_id='.db_input($fileId).' AND ref_id='
+                .db_input($this->getId()))))
             return $id;
 
         $sql ='INSERT IGNORE INTO '.TICKET_ATTACHMENT_TABLE.' SET created=NOW() '
diff --git a/include/class.ticket.php b/include/class.ticket.php
index 57d8ff42bdcf5a63268dfff5eda0c1ae2b4f753d..27908b5fe2ecb7a65d86282b421cb2d082e2e68d 100644
--- a/include/class.ticket.php
+++ b/include/class.ticket.php
@@ -1577,9 +1577,10 @@ class Ticket {
 
         if(!$alerts) return $message; //Our work is done...
 
-        $autorespond = true;
-        if ($autorespond && $message->isBounceOrAutoReply())
-            $autorespond=false;
+        // Do not auto-respond to bounces and other auto-replies
+        $autorespond = isset($vars['flags']) ? !$vars['flags']['bounce'] : true;
+        if ($autorespond && $message->isAutoReply())
+            $autorespond = false;
 
         $this->onMessage($message, $autorespond); //must be called b4 sending alerts to staff.
 
@@ -1813,6 +1814,10 @@ class Ticket {
         if(!($note=$this->getThread()->addNote($vars, $errors)))
             return null;
 
+        if (isset($vars['flags']) && $vars['flags']['bounce'])
+            // No alerts for bounce emails
+            $alert = false;
+
         //Set state: Error on state change not critical!
         if(isset($vars['state']) && $vars['state']) {
             if($this->setState($vars['state']))
@@ -2391,6 +2396,8 @@ class Ticket {
 
         # Messages that are clearly auto-responses from email systems should
         # not have a return 'ping' message
+        if (isset($vars['flags']) && $vars['flags']['bounce'])
+            $autorespond = false;
         if ($autorespond && $message->isAutoReply())
             $autorespond = false;
 
@@ -2455,6 +2462,11 @@ class Ticket {
         // post response - if any
         $response = null;
         if($vars['response'] && $thisstaff->canPostReply()) {
+
+            // unpack any uploaded files into vars.
+            if ($_FILES['attachments'])
+                $vars['files'] = AttachmentFile::format($_FILES['attachments']);
+
             $vars['response'] = $ticket->replaceVars($vars['response']);
             if(($response=$ticket->postReply($vars, $errors, false))) {
                 //Only state supported is closed on response
diff --git a/include/class.validator.php b/include/class.validator.php
index a09f9738ac22fdb384e91346cdd2fe08956e40bc..bb6745e7fdbee59f07bd8788018463befc486c2a 100644
--- a/include/class.validator.php
+++ b/include/class.validator.php
@@ -141,7 +141,8 @@ class Validator {
     /*** Functions below can be called directly without class instance.
          Validator::func(var..);  (nolint) ***/
     function is_email($email) {
-        return preg_match('/^([*+!.&#$|\'\\%\/0-9a-z^_`{}=?~:-]+)@(([0-9a-z-]+\.)+[0-9a-z]{2,})$/i',$email);
+        require_once PEAR_DIR.'Mail/RFC822.php';
+        return !PEAR::isError(Mail_RFC822::parseAddressList($email));
     }
     function is_phone($phone) {
         /* We're not really validating the phone number but just making sure it doesn't contain illegal chars and of acceptable len */
diff --git a/include/upgrader/streams/core/f8856d56-abe9c0cb.patch.sql b/include/upgrader/streams/core/f8856d56-abe9c0cb.patch.sql
index 09b593a16a1abe2e546ec88ede4bf0ceb1caff9c..30a00eb8ca45bbfd7ca844e3e27f3e444c4962de 100644
--- a/include/upgrader/streams/core/f8856d56-abe9c0cb.patch.sql
+++ b/include/upgrader/streams/core/f8856d56-abe9c0cb.patch.sql
@@ -93,6 +93,11 @@ INSERT INTO `%TABLE_PREFIX%ticket_email_info`
     FROM `%TABLE_PREFIX%ticket_message`
     WHERE `messageId` IS NOT NULL AND `messageId` <>'';
 
+-- Change collation to utf8_general_ci - to avoid Illegal mix of collations error
+ALTER TABLE `%TABLE_PREFIX%ticket_attachment`
+    CHANGE `ref_type` `ref_type` ENUM('M','R','N') CHARACTER
+    SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT 'M';
+
 -- Update attachment table
 UPDATE `%TABLE_PREFIX%ticket_attachment`
     SET `ref_id` = ( SELECT T2.`id` FROM `%TABLE_PREFIX%ticket_thread` T2
diff --git a/scp/tickets.php b/scp/tickets.php
index 901e4a9402bc47f17a58f8dee9386a90683abace..f679f5035a2355ef80482f4a8084f09975c25427 100644
--- a/scp/tickets.php
+++ b/scp/tickets.php
@@ -484,9 +484,6 @@ if($_POST && !$errors):
                     $vars = $_POST;
                     $vars['uid'] = $user? $user->getId() : 0;
 
-                    if($_FILES['attachments'])
-                        $vars['files'] = AttachmentFile::format($_FILES['attachments']);
-
                     if(($ticket=Ticket::open($vars, $errors))) {
                         $msg='Ticket created successfully';
                         $_REQUEST['a']=null;
diff --git a/setup/test/tests/test.validation.php b/setup/test/tests/test.validation.php
index 942767329642101c1f6db4a483ff23798936c118..20b1eae9aa85cf36a9355de41c468feb74e5e6a1 100644
--- a/setup/test/tests/test.validation.php
+++ b/setup/test/tests/test.validation.php
@@ -15,6 +15,39 @@ class TestValidation extends Test {
         $this->assert(Validator::is_username('中国期刊全文数据'));
         // Non-letters
         $this->assert(!Validator::is_username('j®red'));
+        // Special chars
+        $this->assert(Validator::is_username('jar.ed'));
+        $this->assert(Validator::is_username('jar_ed'));
+        $this->assert(Validator::is_username('jar-ed'));
+        // Illegals
+        $this->assert(!Validator::is_username('j red'));
+        $this->assert(!Validator::is_username('jared '));
+        $this->assert(!Validator::is_username(' jared'));
+    }
+
+    function testValidEmail() {
+        // Common emails
+        $this->assert(Validator::is_email('jared@domain.tld'));
+        $this->assert(Validator::is_email('jared12@domain.tld'));
+        $this->assert(Validator::is_email('jared.12@domain.tld'));
+        $this->assert(Validator::is_email('jared_12@domain.tld'));
+        $this->assert(Validator::is_email('jared-12@domain.tld'));
+
+        // Very likely illegal
+        $this->assert(!Validator::is_email('jared r@domain.tld'));
+        $this->assert(Validator::is_email('jared@host'));
+
+        // Odd cases, but legal
+        $this->assert(Validator::is_email('jared@[127.0.0.1]'));
+        $this->assert(Validator::is_email('jared@[ipv6:::1]'));
+        $this->assert(Validator::is_email('*@domain.tld'));
+        $this->assert(Validator::is_email("'@domain.tld"));
+        $this->assert(Validator::is_email('"jared r"@domain.tld'));
+
+        // RFC 6530
+        #$this->assert(Validator::is_email('Pelé@example.com'));
+        #$this->assert(Validator::is_email('δοκιμή@παράδειγμα.δοκιμή'));
+        #$this->assert(Validator::is_email('甲斐@黒川.日本'));
     }
 }
 return 'TestValidation';