diff --git a/include/api.tickets.php b/include/api.tickets.php
index 9fbbd853658fdd7270d97726864f983f9c611dc5..fcb55d81b5b27cc62ee8b3cfb71d4128f0344fab 100644
--- a/include/api.tickets.php
+++ b/include/api.tickets.php
@@ -40,7 +40,7 @@ class TicketApiController extends ApiController {
             $supported = array_merge($supported, array('header', 'mid',
                 'emailId', 'to-email-id', 'ticketId', 'reply-to', 'reply-to-name',
                 'in-reply-to', 'references', 'thread-type',
-                'flags' => array('bounce', 'auto-reply'),
+                'flags' => array('bounce', 'auto-reply', 'spam', 'viral'),
                 'recipients' => array('*' => array('name', 'email', 'source'))
                 ));
 
diff --git a/include/class.mailfetch.php b/include/class.mailfetch.php
index 3ab0d891a84e15a14a7a7c2ccd0634d557776a6b..0958e8be1015065fbac6b369c474a1bb251661b8 100644
--- a/include/class.mailfetch.php
+++ b/include/class.mailfetch.php
@@ -269,13 +269,22 @@ class MailFetcher {
         if(!($headerinfo=imap_headerinfo($this->mbox, $mid)) || !$headerinfo->from)
             return null;
 
+        $raw_header = $this->getHeader($mid);
+        $info = array(
+            'raw_header' => &$raw_header,
+            'headers' => $headerinfo,
+            'decoder' => $this,
+            'type' => $this->getMimeType($headerinfo),
+        );
+        Signal::send('mail.decoded', $this, $info);
+
         $sender=$headerinfo->from[0];
         //Just what we need...
         $header=array('name'  => $this->mime_decode(@$sender->personal),
                       'email'  => trim(strtolower($sender->mailbox).'@'.$sender->host),
                       'subject'=> $this->mime_decode(@$headerinfo->subject),
                       'mid'    => trim(@$headerinfo->message_id),
-                      'header' => $this->getHeader($mid),
+                      'header' => $raw_header,
                       'in-reply-to' => $headerinfo->in_reply_to,
                       'references' => $headerinfo->references,
                       );
@@ -624,6 +633,7 @@ class MailFetcher {
         $vars['subject'] = $mailinfo['subject'] ?: '[No Subject]';
         $vars['emailId'] = $mailinfo['emailId'] ?: $this->getEmailId();
         $vars['to-email-id'] = $mailinfo['emailId'] ?: 0;
+        $vars['flags'] = new ArrayObject();
 
         if ($this->isBounceNotice($mid)) {
             // Fetch the original References and assign to 'references'
@@ -694,6 +704,9 @@ class MailFetcher {
             }
         }
 
+        // Allow signal handlers to interact with the message decoding
+        Signal::send('mail.processed', $this, $vars);
+
         $seen = false;
         if (($thread = ThreadEntry::lookupByEmailHeaders($vars, $seen))
                 && ($message = $thread->postEmail($vars))) {
@@ -715,11 +728,18 @@ class MailFetcher {
                 return true;
             }
 
-            //TODO: Log error..
+            // Log an error to the system logs
+            $mailbox = Email::lookup($vars['emailId']);
+            $ost->logError('Mail Processing Exception', sprintf(
+                "Mailbox: %s\nError(s): %s",
+                $mailbox->getEmail(),
+                print_r($errors, true)
+            ), false);
+
+            // Indicate failure of mail processing
             return null;
         }
 
-
         return $ticket;
     }
 
diff --git a/include/class.mailparse.php b/include/class.mailparse.php
index 48a402dfb013e724f1b8eb9c1d683007fa5d896e..9e3623a3812124982cf79390a06197ff36d1b813 100644
--- a/include/class.mailparse.php
+++ b/include/class.mailparse.php
@@ -58,6 +58,9 @@ class Mail_Parse {
                         'decode_headers'=> $this->decode_headers,
                         'decode_bodies' => $this->decode_bodies);
 
+        $info = array('raw' => &$this->mime_message);
+        Signal::send('mail.received', $this, $info);
+
         $this->splitBodyHeader();
 
         $decoder = new Mail_mimeDecode($this->mime_message);
@@ -66,6 +69,18 @@ class Mail_Parse {
         if (PEAR::isError($this->struct))
             return false;
 
+        $info = array(
+            'raw_header' => &$this->header,
+            'headers' => &$this->struct->headers,
+            'body' => &$this->struct->parts,
+            'type' => $this->struct->ctype_primary.'/'.$this->struct->ctype_secondary,
+            'mail' => $this->struct,
+            'decoder' => $decoder,
+        );
+
+        // Allow signal handlers to interact with the processing
+        Signal::send('mail.decoded', $decoder, $info);
+
         // Handle wrapped emails when forwarded
         if ($this->struct && $this->struct->parts) {
             $outer = $this->struct;
@@ -533,6 +548,7 @@ class EmailDataParser {
         $data['header'] = $parser->getHeader();
         $data['mid'] = $parser->getMessageId();
         $data['priorityId'] = $parser->getPriority();
+        $data['flags'] = new ArrayObject();
 
         //FROM address: who sent the email.
         if(($fromlist = $parser->getFromAddressList())) {
diff --git a/include/class.osticket.php b/include/class.osticket.php
index ce5d6354498dbb022ec66213f756eb49ffb1c69b..284eebff2dc7d692e3f2df86e4d65a7582486b26 100644
--- a/include/class.osticket.php
+++ b/include/class.osticket.php
@@ -305,6 +305,14 @@ class osTicket {
                 $level=3; //Debug
         }
 
+        $info = array(
+            'title' => &$title,
+            'level' => $loglevel[$level],
+            'level_id' => $level,
+            'body' => &$message,
+        );
+        Signal::send('syslog', null, $info);
+
         //Logging everything during upgrade.
         if($this->getConfig()->getLogLevel()<$level && !$force)
             return false;
diff --git a/include/class.thread.php b/include/class.thread.php
index 24016f02d3305ca0d82701f4a5d27bc5d4287d36..3b773bfda402c0633e5aab07a96e5e7ab840e469 100644
--- a/include/class.thread.php
+++ b/include/class.thread.php
@@ -1361,6 +1361,11 @@ class ThreadBody /* extends SplString */ {
         throw new Exception('display: Abstract dispplay() method not implemented');
     }
 
+    function getSearchable() {
+        return $this->body;
+        // TODO: Normalize Unicode string
+    }
+
     static function fromFormattedText($text, $format=false) {
         switch ($format) {
         case 'text':
@@ -1428,6 +1433,13 @@ class HtmlThreadBody extends ThreadBody {
         return trim($this->body, " <>br/\t\n\r") ? Format::sanitize($this->body) : '';
     }
 
+    function getSearchable() {
+        // <br> -> \n
+        $body = preg_replace('/\<br(\s*)?\/?\>/i', "\n", $this->body);
+        return Format::striptags($body);
+        // TODO: Normalize Unicode string
+    }
+
     function display($output=false) {
         if ($this->isEmpty())
             return '(empty)';
diff --git a/include/class.ticket.php b/include/class.ticket.php
index 63dde20fa9e247ca48643e82d1b407347ce7e2f1..7b41282aed91167d827c1b8a93f005510873e99c 100644
--- a/include/class.ticket.php
+++ b/include/class.ticket.php
@@ -1595,7 +1595,9 @@ class Ticket {
         if(!$alerts) return $message; //Our work is done...
 
         // Do not auto-respond to bounces and other auto-replies
-        $autorespond = isset($vars['flags']) ? !$vars['flags']['bounce'] : true;
+        $autorespond = isset($vars['flags'])
+            ? !$vars['flags']['bounce'] && !$vars['flags']['auto-reply']
+            : true;
         if ($autorespond && $message->isAutoReply())
             $autorespond = false;
 
@@ -1849,9 +1851,12 @@ 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;
+        $alert = $alert && (
+            isset($vars['flags'])
+            // No alerts for bounce and auto-reply emails
+            ? !$vars['flags']['bounce'] && !$vars['flags']['auto-reply']
+            : true
+        );
 
         // Get assigned staff just in case the ticket is closed.
         $assignee = $this->getStaff();