VSTO:在已发送项目中创建虚假电子邮件时出现问题
VSTO: Problem during creation of a fake email in sent items
我想在已发送邮件文件夹中创建一个假邮件。为了实现这个目标:
a) 我正在复制未发送状态的邮件
b) 将 GUID 分配为 UserProperty
c) 更改 MessageClass = IPM.Post 并保存
d) 信息:UserProperty 在这里仍然存在
e) 发送 PostItem
在已发送项目文件夹的 ItemAdd 事件处理程序中:
a) 我正在检查 Item 是否为 PostItem
b) 尝试用设置的 UserProperty 识别当前对象(这已经失败了,没有可用的 UserProperties -> 问题 1)
c) 想要通过更改 MessageClass = IPM.Note 并保存
将当前 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();
我想在已发送邮件文件夹中创建一个假邮件。为了实现这个目标:
a) 我正在复制未发送状态的邮件
b) 将 GUID 分配为 UserProperty
c) 更改 MessageClass = IPM.Post 并保存
d) 信息:UserProperty 在这里仍然存在
e) 发送 PostItem
在已发送项目文件夹的 ItemAdd 事件处理程序中:
a) 我正在检查 Item 是否为 PostItem
b) 尝试用设置的 UserProperty 识别当前对象(这已经失败了,没有可用的 UserProperties -> 问题 1)
c) 想要通过更改 MessageClass = IPM.Note 并保存
将当前 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();