diff --git a/include/class.mailfetch.php b/include/class.mailfetch.php
index 7fee6868a50a70cb1681f05ae8e2c7604510234f..82a5182b2b4b9b3ed559e7843994377a7c89f68d 100644
--- a/include/class.mailfetch.php
+++ b/include/class.mailfetch.php
@@ -423,19 +423,27 @@ class MailFetcher {
         $newticket=true;
 
         $errors=array();
+        $seen = false;
 
-        if (($thread = ThreadEntry::lookupByEmailHeaders($vars))
+        if (($thread = ThreadEntry::lookupByEmailHeaders($vars, $seen))
                 && ($message = $thread->postEmail($vars))) {
             if (!$message instanceof ThreadEntry)
                 // Email has been processed previously
                 return $message;
             $ticket = $message->getTicket();
+        } elseif ($seen) {
+            // Already processed, but for some reason (like rejection), no
+            // thread item was created. Ignore the email
+            return true;
         } elseif (($ticket=Ticket::create($vars, $errors, 'Email'))) {
             $message = $ticket->getLastMessage();
         } else {
             //Report success if the email was absolutely rejected.
-            if(isset($errors['errno']) && $errors['errno'] == 403)
+            if(isset($errors['errno']) && $errors['errno'] == 403) {
+                // Never process this email again!
+                ThreadEntry::logEmailInfo(0, $vars['mid']);
                 return true;
+            }
 
             # check if it's a bounce!
             if($vars['header'] && TicketFilter::isAutoBounce($vars['header'])) {
diff --git a/include/class.thread.php b/include/class.thread.php
index ba9332ae487d638107b7fdef31d824e5bbb16ef9..2074a6b08756482567d1b237bab04ba1c615c26d 100644
--- a/include/class.thread.php
+++ b/include/class.thread.php
@@ -579,17 +579,23 @@ Class ThreadEntry {
         if(!$vars || !$vars['mid'])
             return 0;
 
-        $sql='INSERT INTO '.TICKET_EMAIL_INFO_TABLE
-            .' SET message_id='.db_input($this->getId()) //TODO: change it to thread_id
-            .', email_mid='.db_input($vars['mid']); //TODO: change it to mid.
-        if (isset($vars['header']))
-            $sql .= ', headers='.db_input($vars['header']);
-
         $this->ht['email_mid'] = $vars['mid'];
 
-        return db_query($sql)?db_insert_id():0;
+        $header = false;
+        if (isset($vars['header']))
+            $header = $vars['header'];
+        self::logEmailHeaders($this->getId(), $vars['mid'], $header);
     }
 
+    /* static */
+    function logEmailHeaders($id, $mid, $header=false) {
+        $sql='INSERT INTO '.TICKET_EMAIL_INFO_TABLE
+            .' SET message_id='.db_input($id) //TODO: change it to thread_id
+            .', email_mid='.db_input($mid); //TODO: change it to message_id.
+        if ($header)
+            $sql .= ', headers='.db_input($header);
+        return db_query($sql)?db_insert_id():0;
+    }
 
     /* variables */
 
@@ -640,28 +646,39 @@ Class ThreadEntry {
      *  - "in-reply-to" => Message-Id the email is a direct response to
      *  - "references" => List of Message-Id's the email is in response
      *  - "subject" => Find external ticket number in the subject line
+     *
+     *  seen (by-ref:bool) a flag that will be set if the message-id was
+     *      positively found, indicating that the message-id has been
+     *      previously seen. This is useful if no thread-id is associated
+     *      with the email (if it was rejected for instance).
      */
-    function lookupByEmailHeaders($mailinfo) {
+    function lookupByEmailHeaders($mailinfo, &$seen=false) {
         // Search for messages using the References header, then the
         // in-reply-to header
-        $search = 'SELECT message_id FROM '.TICKET_EMAIL_INFO_TABLE
+        $search = 'SELECT message_id, email_mid FROM '.TICKET_EMAIL_INFO_TABLE
                . ' WHERE email_mid=%s ORDER BY message_id DESC';
 
-        if ($id = db_result(db_query(
-                sprintf($search, db_input($mailinfo['mid'])))))
+        if (list($id, $mid) = db_fetch_row(db_query(
+                sprintf($search, db_input($mailinfo['mid']))))) {
+            $seen = true;
             return ThreadEntry::lookup($id);
+        }
 
         foreach (array('mid', 'in-reply-to', 'references') as $header) {
             $matches = array();
             if (!isset($mailinfo[$header]) || !$mailinfo[$header])
                 continue;
             // Header may have multiple entries (usually separated by
-            // semi-colons (;))
+            // spaces ( )
             elseif (!preg_match_all('/<[^>@]+@[^>]+>/', $mailinfo[$header],
                         $matches))
                 continue;
 
-            foreach ($matches[0] as $mid) {
+            // The References header will have the most recent message-id
+            // (parent) on the far right.
+            // @see rfc 1036, section 2.2.5
+            // @see http://www.jwz.org/doc/threading.html
+            foreach (array_reverse($matches[0]) as $mid) {
                 $res = db_query(sprintf($search, db_input($mid)));
                 while (list($id) = db_fetch_row($res)) {
                     if ($t = ThreadEntry::lookup($id))