You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tika.apache.org by ta...@apache.org on 2017/03/08 01:42:18 UTC

[tika] branch master updated: TIKA-1879 -- improve recipient email address extraction; revert the X400/500/Exchange processing for the "from" field from TIKA-1865

This is an automated email from the ASF dual-hosted git repository.

tallison pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/tika.git

The following commit(s) were added to refs/heads/master by this push:
       new  b2f3eaf   TIKA-1879 -- improve recipient email address extraction; revert the X400/500/Exchange processing for the "from" field from TIKA-1865
b2f3eaf is described below

commit b2f3eafc49221cd099f0ad9126cf90ad5535bdaf
Author: tballison <ta...@mitre.org>
AuthorDate: Tue Mar 7 20:42:07 2017 -0500

    TIKA-1879 -- improve recipient email address extraction; revert the X400/500/Exchange processing for the "from" field from TIKA-1865
---
 .../java/org/apache/tika/metadata/Message.java     |  61 +++++--
 .../main/java/org/apache/tika/metadata/Office.java |  18 --
 .../apache/tika/parser/mbox/OutlookPSTParser.java  |  58 ++++---
 .../tika/parser/microsoft/OutlookExtractor.java    | 189 ++++++++++++++-------
 .../apache/tika/parser/mail/RFC822ParserTest.java  |   1 +
 .../tika/parser/mbox/OutlookPSTParserTest.java     |   9 +
 .../tika/parser/microsoft/OutlookParserTest.java   |  32 +++-
 7 files changed, 247 insertions(+), 121 deletions(-)

diff --git a/tika-core/src/main/java/org/apache/tika/metadata/Message.java b/tika-core/src/main/java/org/apache/tika/metadata/Message.java
index af853c6..0a8fb80 100644
--- a/tika-core/src/main/java/org/apache/tika/metadata/Message.java
+++ b/tika-core/src/main/java/org/apache/tika/metadata/Message.java
@@ -37,30 +37,69 @@ public interface Message {
     String MESSAGE_BCC = "Message-Bcc";
 
     /**
-     * Where possible, we try to separate the name from the email address
-     * in Message files.  This is multivalued for cases where an email is sent
-     * "on behalf of" someone...this is still to be implemented, though.
-     * The name may be an organization name.
+     * Where possible, this records the value from the name field.
+     * Even in MAPI messages, though, this can be an email address.
      */
     Property MESSAGE_FROM_NAME = Property.internalTextBag(MESSAGE_PREFIX+"From-Name");
 
     /**
-     * Where possible, we try to separate the name from the email address
-     * in Message files.  This is multivalued for cases where an email is sent
-     * "on behalf of" someone...this is still to be implemented, though.
+     * Where possible, this records the value from the name field.
+     * Even in MAPI messages, though, this can be a name.
+     * <p/>
+     * Note that the value may also be an X400/x500 Exchange format:
+     * /o=ExchangeLabs/ou=Exchange Administrative Group/cn=Recipients/cn=someone.or.other
      */
     Property MESSAGE_FROM_EMAIL = Property.internalTextBag(MESSAGE_PREFIX+"From-Email");
 
+    /**
+     * In Outlook messages, there are sometimes separate fields for "to-name" and
+     * "to-display-name" name.
+     */
     Property MESSAGE_TO_NAME = Property.internalTextBag(MESSAGE_PREFIX+"To-Name");
 
-    Property MESSAGE_TO_EMAIL = Property.internalTextBag(MESSAGE_PREFIX+"To-Name");
+    Property MESSAGE_TO_DISPLAY_NAME = Property.internalTextBag(MESSAGE_PREFIX+"To-Display-Name");
+
+    /**
+     * Where possible, this records the email value in the to field.
+     * Even in MAPI messages, though, this can be a name.
+     * <p/>
+     * Note that the value may also be an X400/x500 Exchange format:
+     * /o=ExchangeLabs/ou=Exchange Administrative Group/cn=Recipients/cn=someone.or.other
+     */
+    Property MESSAGE_TO_EMAIL = Property.internalTextBag(MESSAGE_PREFIX+"To-Email");
 
+    /**
+     * In Outlook messages, there are sometimes separate fields for "cc-name" and
+     * "cc-display-name" name.
+     */
     Property MESSAGE_CC_NAME = Property.internalTextBag(MESSAGE_PREFIX+"CC-Name");
 
-    Property MESSAGE_CC_EMAIL = Property.internalTextBag(MESSAGE_PREFIX+"CC-Name");
+    Property MESSAGE_CC_DISPLAY_NAME = Property.internalTextBag(MESSAGE_PREFIX+"CC-Display-Name");
 
-    Property MESSAGE_BCC_NAME = Property.internalTextBag(MESSAGE_PREFIX+"CC-Name");
+    /**
+     * Where possible, this records the email value in the cc field.
+     * Even in MAPI messages, though, this can be a name.
+     * <p/>
+     * Note that the value may also be an X400/x500 Exchange format:
+     * /o=ExchangeLabs/ou=Exchange Administrative Group/cn=Recipients/cn=someone.or.other
+     */
+    Property MESSAGE_CC_EMAIL = Property.internalTextBag(MESSAGE_PREFIX+"CC-Email");
+
+    /**
+     * In Outlook messages, there are sometimes separate fields for "bcc-name" and
+     * "bcc-display-name" name.
+     */
+    Property MESSAGE_BCC_NAME = Property.internalTextBag(MESSAGE_PREFIX+"BCC-Name");
 
-    Property MESSAGE_BCC_EMAIL = Property.internalTextBag(MESSAGE_PREFIX+"CC-Name");
+    Property MESSAGE_BCC_DISPLAY_NAME = Property.internalTextBag(MESSAGE_PREFIX+"BCC-Display-Name");
+
+    /**
+     * Where possible, this records the email value in the bcc field.
+     * Even in MAPI messages, though, this can be a name.
+     * <p/>
+     * Note that the value may also be an X400/x500 Exchange format:
+     * /o=ExchangeLabs/ou=Exchange Administrative Group/cn=Recipients/cn=someone.or.other
+     */
+    Property MESSAGE_BCC_EMAIL = Property.internalTextBag(MESSAGE_PREFIX+"BCC-Email");
 
 }
diff --git a/tika-core/src/main/java/org/apache/tika/metadata/Office.java b/tika-core/src/main/java/org/apache/tika/metadata/Office.java
index 86a22d8..a02db76 100644
--- a/tika-core/src/main/java/org/apache/tika/metadata/Office.java
+++ b/tika-core/src/main/java/org/apache/tika/metadata/Office.java
@@ -130,24 +130,6 @@ public interface Office {
         PREFIX_DOC_META + Metadata.NAMESPACE_PREFIX_DELIMITER + "mapi-message-class",
             "APPOINTMENT", "CONTACT", "NOTE", "STICKY_NOTE", "POST", "TASK", "UNKNOWN", "UNSPECIFIED" );
 
-    Property MAPI_EXCHANGE_FROM_O = Property.internalText(
-            PREFIX_DOC_META+Metadata.NAMESPACE_PREFIX_DELIMITER+"mapi-exchange-from-o");
-
-    Property MAPI_EXCHANGE_FROM_OU = Property.internalText(
-            PREFIX_DOC_META+Metadata.NAMESPACE_PREFIX_DELIMITER+"mapi-exchange-from-ou");
-
-    Property MAPI_EXCHANGE_FROM_CN = Property.internalTextBag(
-            PREFIX_DOC_META+Metadata.NAMESPACE_PREFIX_DELIMITER+"mapi-exchange-from-cn");
-
-    Property MAPI_EXCHANGE_FROM_REPRESENTING_O = Property.internalText(
-            PREFIX_DOC_META+Metadata.NAMESPACE_PREFIX_DELIMITER+"mapi-exchange-from-representing-o");
-
-    Property MAPI_EXCHANGE_FROM_REPRESENTING_OU = Property.internalText(
-            PREFIX_DOC_META+Metadata.NAMESPACE_PREFIX_DELIMITER+"mapi-exchange-from-representing-ou");
-
-    Property MAPI_EXCHANGE_FROM_REPRESENTING_CN = Property.internalTextBag(
-            PREFIX_DOC_META+Metadata.NAMESPACE_PREFIX_DELIMITER+"mapi-exchange-from-representing-cn");
-
     Property MAPI_SENT_BY_SERVER_TYPE = Property.internalText(
             PREFIX_DOC_META+Metadata.NAMESPACE_PREFIX_DELIMITER+"mapi-sent-by-server-type");
 
diff --git a/tika-parsers/src/main/java/org/apache/tika/parser/mbox/OutlookPSTParser.java b/tika-parsers/src/main/java/org/apache/tika/parser/mbox/OutlookPSTParser.java
index dd55466..3caa53e 100644
--- a/tika-parsers/src/main/java/org/apache/tika/parser/mbox/OutlookPSTParser.java
+++ b/tika-parsers/src/main/java/org/apache/tika/parser/mbox/OutlookPSTParser.java
@@ -27,9 +27,11 @@ import java.io.InputStream;
 import java.util.Set;
 
 import com.pff.PSTAttachment;
+import com.pff.PSTException;
 import com.pff.PSTFile;
 import com.pff.PSTFolder;
 import com.pff.PSTMessage;
+import com.pff.PSTRecipient;
 import org.apache.tika.exception.TikaException;
 import org.apache.tika.extractor.EmbeddedDocumentExtractor;
 import org.apache.tika.extractor.EmbeddedDocumentUtil;
@@ -157,29 +159,45 @@ public class OutlookPSTParser extends AbstractParser {
         mailMetadata.set(Office.MAPI_MESSAGE_CLASS,
                 OutlookExtractor.getMessageClass(pstMail.getMessageClass()));
 
-        if (pstMail.getSenderAddrtype().equalsIgnoreCase("ex")) {
-            OutlookExtractor.addExchange(pstMail.getSenderEmailAddress(),
-                    Office.MAPI_EXCHANGE_FROM_O,
-                    Office.MAPI_EXCHANGE_FROM_OU,
-                    Office.MAPI_EXCHANGE_FROM_CN, mailMetadata);
-        } {
-            OutlookExtractor.addChunks(pstMail.getSenderEmailAddress(), Message.MESSAGE_FROM_EMAIL,
-                    true, mailMetadata);
-        }
-        if (pstMail.getSentRepresentingAddressType().equalsIgnoreCase("ex")) {
-            OutlookExtractor.addExchange(pstMail.getSentRepresentingEmailAddress(),
-                    Office.MAPI_EXCHANGE_FROM_REPRESENTING_O,
-                    Office.MAPI_EXCHANGE_FROM_REPRESENTING_OU,
-                    Office.MAPI_EXCHANGE_FROM_REPRESENTING_CN, mailMetadata);
-
-        } else {
-            OutlookExtractor.addChunks(pstMail.getSentRepresentingEmailAddress(),
-                    Office.MAPI_FROM_REPRESENTING_EMAIL,
-                    true, mailMetadata);
-        }
+        mailMetadata.set(Message.MESSAGE_FROM_EMAIL, pstMail.getSenderEmailAddress());
+
+        mailMetadata.set(Office.MAPI_FROM_REPRESENTING_EMAIL,
+                pstMail.getSentRepresentingEmailAddress());
+
         mailMetadata.set(Message.MESSAGE_FROM_NAME, pstMail.getSenderName());
         mailMetadata.set(Office.MAPI_FROM_REPRESENTING_NAME, pstMail.getSentRepresentingName());
 
+        //add recipient details
+        try {
+            for (int i = 0; i < pstMail.getNumberOfRecipients(); i++) {
+                PSTRecipient recipient = pstMail.getRecipient(i);
+                switch (OutlookExtractor.RECIPIENT_TYPE.getTypeFromVal(recipient.getRecipientType())) {
+                    case TO:
+                        OutlookExtractor.addEvenIfNull(Message.MESSAGE_TO_DISPLAY_NAME,
+                                recipient.getDisplayName(), mailMetadata);
+                        OutlookExtractor.addEvenIfNull(Message.MESSAGE_TO_EMAIL,
+                                recipient.getEmailAddress(), mailMetadata);
+                        break;
+                    case CC:
+                        OutlookExtractor.addEvenIfNull(Message.MESSAGE_CC_DISPLAY_NAME,
+                                recipient.getDisplayName(), mailMetadata);
+                        OutlookExtractor.addEvenIfNull(Message.MESSAGE_CC_EMAIL,
+                                recipient.getEmailAddress(), mailMetadata);
+                        break;
+                    case BCC:
+                        OutlookExtractor.addEvenIfNull(Message.MESSAGE_BCC_DISPLAY_NAME,
+                                recipient.getDisplayName(), mailMetadata);
+                        OutlookExtractor.addEvenIfNull(Message.MESSAGE_BCC_EMAIL,
+                                recipient.getEmailAddress(), mailMetadata);
+                        break;
+                    default:
+                        //do we want to handle unspecified or unknown?
+                        break;
+                }
+            }
+        } catch (PSTException e) {
+            //swallow
+        }
 
         byte[] mailContent = pstMail.getBody().getBytes(UTF_8);
         embeddedExtractor.parseEmbedded(new ByteArrayInputStream(mailContent), handler, mailMetadata, true);
diff --git a/tika-parsers/src/main/java/org/apache/tika/parser/microsoft/OutlookExtractor.java b/tika-parsers/src/main/java/org/apache/tika/parser/microsoft/OutlookExtractor.java
index 08290f7..e4b5385 100644
--- a/tika-parsers/src/main/java/org/apache/tika/parser/microsoft/OutlookExtractor.java
+++ b/tika-parsers/src/main/java/org/apache/tika/parser/microsoft/OutlookExtractor.java
@@ -26,8 +26,10 @@ import java.nio.charset.IllegalCharsetNameException;
 import java.nio.charset.UnsupportedCharsetException;
 import java.text.ParseException;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.Date;
 import java.util.LinkedHashMap;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
@@ -44,6 +46,7 @@ import org.apache.poi.hsmf.datatypes.Chunk;
 import org.apache.poi.hsmf.datatypes.Chunks;
 import org.apache.poi.hsmf.datatypes.MAPIProperty;
 import org.apache.poi.hsmf.datatypes.PropertyValue;
+import org.apache.poi.hsmf.datatypes.RecipientChunks;
 import org.apache.poi.hsmf.datatypes.StringChunk;
 import org.apache.poi.hsmf.datatypes.Types;
 import org.apache.poi.hsmf.exceptions.ChunkNotFoundException;
@@ -62,7 +65,6 @@ import org.apache.tika.parser.ParseContext;
 import org.apache.tika.parser.Parser;
 import org.apache.tika.parser.html.HtmlEncodingDetector;
 import org.apache.tika.parser.html.HtmlParser;
-import org.apache.tika.parser.mail.MailUtil;
 import org.apache.tika.parser.mbox.MboxParser;
 import org.apache.tika.parser.rtf.RTFParser;
 import org.apache.tika.parser.txt.CharsetDetector;
@@ -77,11 +79,32 @@ import org.xml.sax.SAXException;
  */
 public class OutlookExtractor extends AbstractPOIFSExtractor {
 
+    public enum RECIPIENT_TYPE {
+        TO(1),
+        CC(2),
+        BCC(3),
+        UNRECOGNIZED(-1),
+        UNSPECIFIED(-1);
 
-    private final static String RECIPIENTS = "recipients";
-    private final static Pattern EXCHANGE_O = Pattern.compile("(?i)/o=([^/]+)");
-    private final static Pattern EXCHANGE_OU = Pattern.compile("(?i)/ou=([^/]+)");
-    private final static Pattern EXCHANGE_CN = Pattern.compile("(?i)/cn=([^/]+)");
+        private final int val;
+
+        RECIPIENT_TYPE(int val) {
+            this.val = val;
+        }
+
+        public static RECIPIENT_TYPE getTypeFromVal(int val) {
+            //mild hackery, clean up
+            if (val > 0 && val < 4) {
+                return RECIPIENT_TYPE.values()[val - 1];
+            }
+            return UNRECOGNIZED;
+        }
+    };
+
+    private enum ADDRESS_TYPE {
+        EX,
+        SMTP
+    }
 
 
     private static Pattern HEADER_KEY_PAT =
@@ -328,79 +351,66 @@ public class OutlookExtractor extends AbstractPOIFSExtractor {
             senderAddressTypeString = senderAddresType.get(0).toString();
         }
 
-        //sometimes in SMTP .msg files there is an email in the sender name field
-        //make sure to rule those out.
-        addChunks(
-                mainChunks.get(MAPIProperty.SENDER_NAME), Message.MESSAGE_FROM_NAME,
-                    false, metadata);
-        addChunks(
+        //sometimes in SMTP .msg files there is an email in the sender name field.
+
+        setFirstChunk(
+                mainChunks.get(MAPIProperty.SENDER_NAME), Message.MESSAGE_FROM_NAME, metadata);
+        setFirstChunk(
                 mainChunks.get(MAPIProperty.SENT_REPRESENTING_NAME),
-                    Office.MAPI_FROM_REPRESENTING_NAME, false, metadata);
-
-        if (senderAddressTypeString.equalsIgnoreCase("ex")) {
-            addExchange(mainChunks.get(MAPIProperty.SENDER_EMAIL_ADDRESS),
-                    Office.MAPI_EXCHANGE_FROM_O, Office.MAPI_EXCHANGE_FROM_OU,
-                    Office.MAPI_EXCHANGE_FROM_CN, metadata);
-            addExchange(mainChunks.get(MAPIProperty.SENT_REPRESENTING_EMAIL_ADDRESS),
-                    Office.MAPI_EXCHANGE_FROM_REPRESENTING_O, Office.MAPI_EXCHANGE_FROM_REPRESENTING_OU,
-                    Office.MAPI_EXCHANGE_FROM_REPRESENTING_CN, metadata);
-        } else {
-            addChunks(mainChunks.get(MAPIProperty.SENDER_EMAIL_ADDRESS),
-                    Message.MESSAGE_FROM_EMAIL, true, metadata);
-            addChunks(mainChunks.get(MAPIProperty.SENT_REPRESENTING_EMAIL_ADDRESS),
-                    Office.MAPI_FROM_REPRESENTING_EMAIL, true, metadata);
+                Office.MAPI_FROM_REPRESENTING_NAME, metadata);
+
+        setFirstChunk(mainChunks.get(MAPIProperty.SENDER_EMAIL_ADDRESS),
+                Message.MESSAGE_FROM_EMAIL, metadata);
+        setFirstChunk(mainChunks.get(MAPIProperty.SENT_REPRESENTING_EMAIL_ADDRESS),
+                Office.MAPI_FROM_REPRESENTING_EMAIL, metadata);
+
+        for (Recipient recipient : buildRecipients()) {
+            switch(recipient.recipientType) {
+                case TO:
+                    addEvenIfNull(Message.MESSAGE_TO_NAME, recipient.name, metadata);
+                    addEvenIfNull(Message.MESSAGE_TO_DISPLAY_NAME, recipient.displayName, metadata);
+                    addEvenIfNull(Message.MESSAGE_TO_EMAIL, recipient.emailAddress, metadata);
+                    break;
+                case CC:
+                    addEvenIfNull(Message.MESSAGE_CC_NAME, recipient.name, metadata);
+                    addEvenIfNull(Message.MESSAGE_CC_DISPLAY_NAME, recipient.displayName, metadata);
+                    addEvenIfNull(Message.MESSAGE_CC_EMAIL, recipient.emailAddress, metadata);
+                    break;
+                case BCC:
+                    addEvenIfNull(Message.MESSAGE_BCC_NAME, recipient.name, metadata);
+                    addEvenIfNull(Message.MESSAGE_BCC_DISPLAY_NAME, recipient.displayName, metadata);
+                    addEvenIfNull(Message.MESSAGE_BCC_EMAIL, recipient.emailAddress, metadata);
+                    break;
+                default:
+                    //log unknown or undefined?
+                    break;
+            }
         }
     }
 
-
-    private static void addExchange(List<Chunk> chunks,
-                                    Property propertyO,
-                                    Property propertyOU, Property propertyCN, Metadata metadata ) {
-        if (chunks == null || chunks.size() == 0) {
-            return;
+    //need to add empty string to ensure that parallel arrays are parallel
+    //even if one value is null.
+    public static void addEvenIfNull(Property property, String value, Metadata metadata) {
+        if (value == null) {
+            value = "";
         }
-        addExchange(chunks.get(0).toString(), propertyO, propertyOU, propertyCN, metadata);
+        metadata.add(property, value);
     }
 
-    public static void addExchange(String exchange,Property propertyO,
-                             Property propertyOU, Property propertyCN, Metadata metadata) {
-        if (exchange == null || exchange.length() < 1) {
-            return;
-        }
-        Matcher matcherO = EXCHANGE_O.matcher(exchange);
-        if (matcherO.find()) {
-            metadata.set(propertyO, matcherO.group(1));
-        }
-        Matcher matcherOU = EXCHANGE_OU.matcher(exchange);
-        if (matcherOU.find()) {
-            metadata.set(propertyOU, matcherOU.group(1));
-        }
-
-        Matcher matcherCN = EXCHANGE_CN.matcher(exchange);
-        while (matcherCN.find()) {
-            String cn = matcherCN.group(1);
-            if (!cn.equalsIgnoreCase(RECIPIENTS)) {
-                metadata.add(propertyCN, cn);
-            }
-        }
-    }
-
-    private static void addChunks(List<Chunk> chunks, Property property, boolean mustContainEmail,
+    private static void setFirstChunk(List<Chunk> chunks, Property property,
                                  Metadata metadata) {
-        if (chunks == null || chunks.size() < 1) {
+        if (chunks == null || chunks.size() < 1 || chunks.get(0) == null) {
             return;
         }
-        addChunks(chunks.get(0).toString(), property, mustContainEmail, metadata);
+        metadata.set(property, chunks.get(0).toString());
     }
 
-    public static void addChunks(String chunk, Property property, boolean mustContainEmail,
-                           Metadata metadata) {
-        if (chunk == null || chunk.length() == 0) {
+    private static void addFirstChunk(List<Chunk> chunks, Property property,
+                                      Metadata metadata) {
+        if (chunks == null || chunks.size() < 1 || chunks.get(0) == null) {
             return;
         }
-        if (mustContainEmail == MailUtil.containsEmail(chunk)) {
-                metadata.set(property, chunk);
-        }
+        metadata.add(property, chunks.get(0).toString());
     }
 
     //TODO: replace this with getMessageClassEnum when we upgrade POI
@@ -606,4 +616,55 @@ public class OutlookExtractor extends AbstractPOIFSExtractor {
         }
         return false;
     }
+
+
+    private List<Recipient> buildRecipients() {
+        RecipientChunks[] recipientChunks = msg.getRecipientDetailsChunks();
+        if (recipientChunks == null) {
+            return Collections.EMPTY_LIST;
+        }
+        List<Recipient> recipients = new LinkedList<>();
+
+        for (RecipientChunks chunks : recipientChunks) {
+            Recipient r = new Recipient();
+            r.displayName = (chunks.recipientDisplayNameChunk != null) ? chunks.recipientDisplayNameChunk.toString() : null;
+            r.name = (chunks.recipientNameChunk != null) ? chunks.recipientNameChunk.toString() : null;
+            r.emailAddress = chunks.getRecipientEmailAddress();
+            List<PropertyValue> vals = chunks.getProperties().get(MAPIProperty.RECIPIENT_TYPE);
+
+            RECIPIENT_TYPE recipientType = RECIPIENT_TYPE.UNSPECIFIED;
+            if (vals != null && vals.size() > 0) {
+                Object val = vals.get(0).getValue();
+                if (val instanceof Integer) {
+                    recipientType = RECIPIENT_TYPE.getTypeFromVal((int)val);
+                }
+            }
+            r.recipientType = recipientType;
+
+            vals = chunks.getProperties().get(MAPIProperty.ADDRTYPE);
+            if (vals != null && vals.size() > 0) {
+                String val = vals.get(0).toString();
+                if (val != null) {
+                    val = val.toLowerCase(Locale.US);
+                    //need to find example of this for testing
+                    if (val.equals("ex")) {
+                        r.addressType = ADDRESS_TYPE.EX;
+                    } else if (val.equals("smtp")) {
+                        r.addressType = ADDRESS_TYPE.SMTP;
+                    }
+                }
+            }
+            recipients.add(r);
+        }
+        return recipients;
+    }
+
+
+    private static class Recipient {
+        String name;
+        String displayName;
+        RECIPIENT_TYPE recipientType;
+        String emailAddress;
+        ADDRESS_TYPE addressType;
+    }
 }
diff --git a/tika-parsers/src/test/java/org/apache/tika/parser/mail/RFC822ParserTest.java b/tika-parsers/src/test/java/org/apache/tika/parser/mail/RFC822ParserTest.java
index 0d7a9d0..1c87acb 100644
--- a/tika-parsers/src/test/java/org/apache/tika/parser/mail/RFC822ParserTest.java
+++ b/tika-parsers/src/test/java/org/apache/tika/parser/mail/RFC822ParserTest.java
@@ -112,6 +112,7 @@ public class RFC822ParserTest extends TikaTest {
         Metadata m = getXML("testRFC822").metadata;
         assertEquals("Julien Nioche (JIRA)", m.get(Message.MESSAGE_FROM_NAME));
         assertEquals("jira@apache.org", m.get(Message.MESSAGE_FROM_EMAIL));
+        debug(m);
 
         m = getXML("testRFC822-multipart").metadata;
         assertEquals("DigitalPebble", m.get(Message.MESSAGE_FROM_NAME));
diff --git a/tika-parsers/src/test/java/org/apache/tika/parser/mbox/OutlookPSTParserTest.java b/tika-parsers/src/test/java/org/apache/tika/parser/mbox/OutlookPSTParserTest.java
index 86b81c2..26597a3 100644
--- a/tika-parsers/src/test/java/org/apache/tika/parser/mbox/OutlookPSTParserTest.java
+++ b/tika-parsers/src/test/java/org/apache/tika/parser/mbox/OutlookPSTParserTest.java
@@ -87,6 +87,7 @@ public class OutlookPSTParserTest extends TikaTest {
         assertEquals("users@opennlp.apache.org", firstMail.get("displayTo"));
         assertEquals("", firstMail.get("displayCC"));
         assertEquals("", firstMail.get("displayBCC"));
+
     }
 
 
@@ -125,6 +126,14 @@ public class OutlookPSTParserTest extends TikaTest {
         assertEquals("Couchbase", m6.get(Office.MAPI_FROM_REPRESENTING_NAME));
         assertEquals("couchbase@couchbase.com", m6.get(Office.MAPI_FROM_REPRESENTING_EMAIL));
         assertEquals("NOTE", m1.get(Office.MAPI_MESSAGE_CLASS));
+        //test full EX email
+        assertEquals("/o=ExchangeLabs/ou=Exchange Administrative Group (FYDIBOHF23SPDLT)/cn=Recipients/cn=polyspot1.onmicrosoft.com-50609-Hong-Thai.Ng",
+                m6.get(Message.MESSAGE_TO_EMAIL));
+        assertEquals("Hong-Thai Nguyen",
+                m6.get(Message.MESSAGE_TO_DISPLAY_NAME));
+
+        assertEquals("Couchbase",m6.get(Message.MESSAGE_FROM_NAME));
+        assertEquals("couchbase@couchbase.com", m6.get(Message.MESSAGE_FROM_EMAIL));
 
     }
 }
diff --git a/tika-parsers/src/test/java/org/apache/tika/parser/microsoft/OutlookParserTest.java b/tika-parsers/src/test/java/org/apache/tika/parser/microsoft/OutlookParserTest.java
index 11cf820..f9c253b 100644
--- a/tika-parsers/src/test/java/org/apache/tika/parser/microsoft/OutlookParserTest.java
+++ b/tika-parsers/src/test/java/org/apache/tika/parser/microsoft/OutlookParserTest.java
@@ -78,6 +78,14 @@ public class OutlookParserTest extends TikaTest {
                 "L'\u00C9quipe Microsoft Outlook Express <ms...@microsoft.com>",
                 metadata.get(Metadata.MESSAGE_RAW_HEADER_PREFIX+"From"));
 
+        assertEquals("Nouvel utilisateur de Outlook Express",
+                metadata.get(Message.MESSAGE_TO_EMAIL));
+
+        assertEquals("",
+                metadata.get(Message.MESSAGE_TO_NAME));
+
+        assertEquals("Nouvel utilisateur de Outlook Express",
+                metadata.get(Message.MESSAGE_TO_DISPLAY_NAME));
 
         // Stored as Thu, 5 Apr 2007 09:26:06 -0700
         assertEquals(
@@ -130,6 +138,11 @@ public class OutlookParserTest extends TikaTest {
         assertEquals("jukka.zitting@gmail.com", metadata.get(Message.MESSAGE_FROM_EMAIL));
         assertEquals("Jukka Zitting", metadata.get(Office.MAPI_FROM_REPRESENTING_NAME));
         assertEquals("jukka.zitting@gmail.com", metadata.get(Office.MAPI_FROM_REPRESENTING_EMAIL));
+
+        //to-name is empty, make sure that we get an empty string.
+        assertEquals("tika-dev@lucene.apache.org", metadata.get(Message.MESSAGE_TO_EMAIL));
+        assertEquals("tika-dev@lucene.apache.org", metadata.get(Message.MESSAGE_TO_DISPLAY_NAME));
+        assertEquals("", metadata.get(Message.MESSAGE_TO_NAME));
     }
 
     /**
@@ -158,6 +171,12 @@ public class OutlookParserTest extends TikaTest {
         assertContains("Outlook 2003", content);
         assertContains("Streamlined Mail Experience", content);
         assertContains("Navigation Pane", content);
+
+        //make sure these are parallel
+        assertEquals("", metadata.get(Message.MESSAGE_TO_EMAIL));
+        assertEquals("New Outlook User", metadata.get(Message.MESSAGE_TO_NAME));
+        assertEquals("New Outlook User", metadata.get(Message.MESSAGE_TO_DISPLAY_NAME));
+
     }
 
     @Test
@@ -195,14 +214,11 @@ public class OutlookParserTest extends TikaTest {
         assertContains("\u5F35\u6BD3\u502B", metadata.get(TikaCoreProperties.CREATOR));
         assertContains("\u9673\u60E0\u73CD", content);
 
-        assertEquals("FT GROUP", metadata.get(Office.MAPI_EXCHANGE_FROM_O));
-        assertEquals("FT", metadata.get(Office.MAPI_EXCHANGE_FROM_OU));
-        assertEquals("LYDIACHANG", metadata.get(Office.MAPI_EXCHANGE_FROM_CN));
-        //this no longer works because we forbid email like contents...do we want to do this?
-        //assertEquals("Tests Chang@FT (\u5f35\u6bd3\u502b)", metadata.get(Office.MAPI_FROM_REPRESENTING_NAME));
-        assertEquals("FT GROUP", metadata.get(Office.MAPI_EXCHANGE_FROM_REPRESENTING_O));
-        assertEquals("FT", metadata.get(Office.MAPI_EXCHANGE_FROM_REPRESENTING_OU));
-        assertEquals("LYDIACHANG", metadata.get(Office.MAPI_EXCHANGE_FROM_REPRESENTING_CN));
+        assertEquals("tests.chang@fengttt.com", metadata.get(Message.MESSAGE_TO_EMAIL));
+
+        assertEquals("Tests Chang@FT (\u5f35\u6bd3\u502b)", metadata.get(Office.MAPI_FROM_REPRESENTING_NAME));
+        assertEquals("/O=FT GROUP/OU=FT/CN=RECIPIENTS/CN=LYDIACHANG",
+                metadata.get(Office.MAPI_FROM_REPRESENTING_EMAIL));
     }
 
     @Test

-- 
To stop receiving notification emails like this one, please contact
['"commits@tika.apache.org" <co...@tika.apache.org>'].