VSTO:在已发送项目中创建虚假电子邮件时出现问题

VSTO: Problem during creation of a fake email in sent items

  1. 我想在已发送邮件文件夹中创建一个假邮件。为了实现这个目标:

    a) 我正在复制未发送状态的邮件

    b) 将 GUID 分配为 UserProperty

    c) 更改 MessageClass = IPM.Post 并保存

    d) 信息:UserProperty 在这里仍然存在

    e) 发送 PostItem

  2. 在已发送项目文件夹的 ItemAdd 事件处理程序中:

    a) 我正在检查 Item 是否为 PostItem

    b) 尝试用设置的 UserProperty 识别当前对象(这已经失败了,没有可用的 UserProperties -> 问题 1)

    c) 想要通过更改 MessageClass = IPM.Note 并保存

  3. 将当前 PostItem 转换为 MailItem

即使我在发送后使用主题而不是 UserProperty(因为主题存在)将 2b 替换为标识,我仍然将对象视为 PostItem (IPM.Post) 而不是 MailItem (IPM.Note)在已发送的项目中 -> 问题 2.

当我在已发送项目中查找时,查找特定项目,更改 MessageClass = IPM.Note 并保存,PostItem 已成功更改为 MailItem。

关于问题1: 为什么 PostItem 的 UserProperties 在此事件期间不可用?

关于问题2: 为什么在此事件期间我不能 "convert" 将 PostItem 发送到 MailItem?

我该如何本地解决这个问题?

这是我的代码:

在此加载项中:

                // ItemSend Event
                Outlook.Application application = this.Application;
                application.ItemSend += new Outlook.ApplicationEvents_11_ItemSendEventHandler(ItemSend_BeforeSend);


...

// ItemAdd event
                outlookNameSpace = this.Application.GetNamespace("MAPI");
                Sent_items = outlookNameSpace.GetDefaultFolder(Microsoft.Office.Interop.Outlook.OlDefaultFolders.olFolderSentMail);

                items = Sent_items.Items;
                items.ItemAdd += new Outlook.ItemsEvents_ItemAddEventHandler(items_ItemAdd);

...

// ItemAdd event action
                void items_ItemAdd(object Item)
                {
...
                            Outlook.PostItem postItem = Item as Outlook.PostItem;

                            Outlook.UserProperties postUserProperties = null;
                            Outlook.UserProperty postUserProperty = null;

                            // for debug only
                            MessageBox.Show(null ?? postItem.Subject, "TestApp: Info", MessageBoxButtons.OK);


                            try
                            {
                                // start of test part

                                postUserProperties = postItem.UserProperties;
                                StringBuilder builder = new StringBuilder();

                                for (int i = 1; i <= postUserProperties.Count; i++) // count is 0 here so no UserProperties !!!
                                {
                                    postUserProperty = postUserProperties[i];
                                    if (postUserProperty != null)
                                    {
                                        builder.AppendFormat("Name: {0} \tValue: {1} \n\r",
                                            postUserProperty.Name, postUserProperty.Value);
                                        Marshal.ReleaseComObject(postUserProperty);
                                        postUserProperty = null;
                                    }
                                }
                                if (builder.Length > 0)
                                {
                                    System.Windows.Forms.MessageBox.Show(builder.ToString(),
                                        "The UserProperties collection");
                                }
                                // end of test part
...
}

// ItemSend_BeforeSend event action
                void ItemSend_BeforeSend(object item, ref bool cancel)
                {
...

 Outlook.Application objOutlook = new Outlook.Application();
                Outlook.MailItem email = (Outlook.MailItem)objOutlook.Session.OpenSharedItem(MjFileMsg);

                // add we item guid to object in order to identify afterwards
                var mailUserProperty = email.UserProperties.Add("WeItemGuid", Outlook.OlUserPropertyType.olText, false, 1);

                createdWeItemGuid = Guid.NewGuid().ToString().ToLower();
                mailUserProperty.Value = createdWeItemGuid;

                email.MessageClass = "IPM.Post";
                email.Save();

                // debug only: check if value is present after changing messageclass (yes, it is present!)
                Outlook.UserProperty testProp = email.UserProperties["WeItemGuid"];
                var testVal = testProp.Value;

                email.Send();
...
}



[更新 1]:

这是 ItemSend 事件操作中的更新代码:


                Outlook.Application objOutlook = new Outlook.Application();
                Outlook.MailItem email = (Outlook.MailItem)objOutlook.Session.OpenSharedItem(MjFileMsg);

                // remove recipients otherwise PostItem will be sent really to recipients (but obviously causing the PostItem not to be sent !!!)
                email.To = null;
                email.CC = null;
                email.BCC = null;

// This has the same effect like setting To/Cc/Bcc to null:
/*
                foreach (Outlook.Recipient Recip in email.Recipients)
                {
                    Recip.Delete();
                }
*/

                email.MessageClass = "IPM.Post";
                email.Save();
                email.Send();

重置消息后是否保存消息class?请记住,您还需要清除 PR_ICON_INDEX 属性.

您不能即时将 PostItem 转换为 MailItem,因为 Outlook 仍然引用原始的 PostItem 对象。只有在您的代码和 Outlook 取消引用该对象并稍后重新打开它之后,它才会看到您的更改。

如果使用 Redemption 是一个选项(我是它的作者),它就像下面这样简单(超出我的头脑):

RDOSession session = new RDOSession();
session.MAPIOBJECT = outlookNameSpace.MAPIOBJECT;
RDOFolder folder = session.GetDefaultFolder(rdoDefaultFolders.olFolderSentMail);
RDOMail msg = folder.Items.Add("IPM.Note");
msg.Sent = true;
msg.ReceivedTime = DateRime.Now;
RDOMail originalMsg = (RDOMail)session.GetRDOObjectFromOUtlookObject(Item);
originalMsg.CopyTo(msg);
msg.Sender = session.CurrentUser;
msg.SentOnBehalfOf = session.CurrentUser;
msg.Save();