private void ProcessMailMessage(IMessage msg, MailMessage outMsg)
        {
            //Copy some of the more important headers
            outMsg.From = MailMessage.CreateEmailAddress(MapiUtils.GetStringProperty(msg, Tags.PR_SENDER_EMAIL_ADDRESS),
                MapiUtils.GetStringProperty(msg, Tags.PR_SENDER_NAME));
            if (MapiUtils.GetStringProperty(msg, Tags.ptagSentRepresentingName) != null) {
                outMsg.ReplyTo = MailMessage.CreateEmailAddress(MapiUtils.GetStringProperty(msg, Tags.ptagSentRepresentingEmailAddr),
                    MapiUtils.GetStringProperty(msg, Tags.ptagSentRepresentingName));
            }
            outMsg.Subject = MapiUtils.GetStringProperty(msg, Tags.PR_SUBJECT);

            IMAPITable recipientsTable = null;
            msg.GetRecipientTable(0, out recipientsTable);
            using (recipientsTable) {

                MAPI33.MapiTypes.Value[,] rows;
                recipientsTable.SetColumns(new Tags[] {Tags.PR_RECIPIENT_TYPE, Tags.PR_EMAIL_ADDRESS, Tags.PR_DISPLAY_NAME},
                    IMAPITable.FLAGS.Default);

                for( ;recipientsTable.QueryRows(1, 0, out rows) == Error.Success && rows.Length > 0; ) {
                    MAPI33.WellKnownValues.PR_RECIPIENT_TYPE recipType = (MAPI33.WellKnownValues.PR_RECIPIENT_TYPE)((MapiInt32)rows[0,0]).Value;
                    String emailAddr = null;
                    String emailName = null;

                    if (rows[0, 1] is MapiString) {
                        emailAddr = ((MapiString)rows[0, 1]).Value;
                    }

                    if (rows[0, 2] is MapiString) {
                        emailName = ((MapiString)rows[0, 2]).Value;
                    }

                    AddressType type = AddressType.To;

                    switch (recipType) {
                        case MAPI33.WellKnownValues.PR_RECIPIENT_TYPE.To:
                            type = AddressType.To;
                            break;

                        case MAPI33.WellKnownValues.PR_RECIPIENT_TYPE.Cc:
                            type = AddressType.Cc;
                            break;

                        case MAPI33.WellKnownValues.PR_RECIPIENT_TYPE.Bcc:
                            type = AddressType.Bcc;
                            break;
                    }

                    outMsg.AddRecipient(emailAddr, emailName, type);
                }
            }

            //Set the body.  There can be a plain Body, which is the plain text version of the message,
            //as well as an HtmlBody, which includes rich text formatting via HTML.
            //
            //This is complicated by the fact that, in MAPI, there are three possible sources
            //of the body: PR_BODY (plain text body), PR_BODY_HTML (HTML body), and PR_RTF_COMPRESSED
            //(RTF body).  Based on empirical observation, there is nearly always a PR_BODY, which is not surprising
            //as every HTML mail client I've ever encountered sends multi-part MIME messages with a plain text version
            //as well as HTML.  PR_BODY_HTML *seems* to be the HTML version of the message as specified by the sender,
            //and may not be present in plain text messages.
            //
            //It only gets complicated with PR_RTF_COMPRESSED (or just PR_RTF for short).  Often, HTML messages
            //don't have a PR_HTML at all, but rather a PR_RTF that has a bunch of RTF tags wrapped around the original
            //HTML of the message.  All messages I've seen have a PR_RTF, however only messages which were originally
            //received as HTML and subsequently transmogrified into RTF include the \@fromhtml RTF tag.
            //
            //Thus, the existence of this \@fromhtml tag is a roundabout way of determining if a message came from
            //the sender as HTML or text (ignoring for now the third possiblity; an older Exchange client using RTF).
            //
            //Therefore, when setting BodyHtml, we first check if PR_RTF includes this \@fromhtml (that's what
            //MapiUtils.BodyRtfToHtml does, among other things).  If it doesn't, BodyHtml is set to null.  If it
            //does, PR_BODY_HTML is checked first, and used to populate BodyHtml if it's non-null.  Failing that, the
            //unwrapped HTML from PR_RTF is used.  So:
            //
            // Body: Always PR_BODY
            // HtmlBody: PR_BODY_HTML if PR_BODY_HTML is non-null and PR_RTF includes the \@fromhtml tag
            //           The HTML embedded in PR_RTF if PR_BODY_HTML is null and PR_RTF includes \@fromhtml
            //           Else null.
            String propVal = null;
            if ((propVal = MapiUtils.GetLongStringProperty(msg, Tags.PR_BODY)) != null) {
                outMsg.Body = propVal;
            }

            //Check for HTML embedded in PR_RTF
            byte[] rtf = MapiUtils.GetBodyRtf(msg);
            if (rtf != null) {
                outMsg.HtmlBody = MapiUtils.BodyRtfToHtml(rtf);
                if (outMsg.HtmlBody != null) {
                    //There's HTML.  use PR_HTML if it's there, else stick w/ what we have
                    if ((propVal = MapiUtils.GetLongStringProperty(msg, Tags.PR_BODY_HTML)) != null) {
                        outMsg.HtmlBody = propVal;
                    }
                }
            }

            //Copy the attachments
            CopyAttachments(msg, outMsg);

            //Output all of the MAPI properties as extended headers, just in case they are needed later
            DumpMapiProperties(msg, outMsg);
        }