Uniquely identify Mailitem - outlook

I need to store a model for every used MailItem. For this I've written following Method
private readonly static Dictionary<string, PermitCustomPaneViewmodel> ViewmodelLookup = new Dictionary<string, PermitCustomPaneViewmodel>();
public static PermitCustomPaneViewmodel CreateOrGet(MailItem c)
{
if (c.EntryID == null)
c.Save();
if (!ViewmodelLookup.ContainsKey(c.EntryID))
{
var vm = new PermitCustomPaneViewmodel(c);
c.Unload += () => ViewmodelLookup.Remove(c.EntryID);
ViewmodelLookup.Add(c.EntryID, vm);
}
return ViewmodelLookup[c.EntryID];
}
When the Model already exists, I look it up and return it. If it was not created, I create it and remove the entry after the MailItem will be unloaded.
However I have observed that the MailItem object will not be vailid all the time untill unload is called. In order to reliable identify the MailItem I used the EntryID. The problem now is this only works if the Item is saved.
So currently I save the Item if no EntryID was found. But this automaticly saves the item under draft.
Is there a way to distingush MailItem's that is not saved in a way so it can be used in a Dictionary<,>.

New created items don't have the EntryID property set. Get the ID assigned by the store provider you must save it. If you need to identify a new MailItem object you may consider adding a user property to the item by using the UserProperties.Add method which reates a new user property in the UserProperties collection. For example:
Sub AddUserProperty()
Dim myItem As Outlook.ContactItem
Dim myUserProperty As Outlook.UserProperty
Set myItem = Application.CreateItem(olContactItem)
Set myUserProperty = myItem.UserProperties _
.Add("LastDateSpokenWith", olDateTime)
myItem.Display
End Sub
Be aware, the Entry ID changes when an item is moved into another store, for example, from your Inbox to a Microsoft Exchange Server public folder, or from one Personal Folders (.pst) file to another .pst file. Solutions should not depend on the EntryID property to be unique unless items will not be moved. Basically it works fine as long as the message is staying in its parent folder or it may be changed if the Outlook item is moved to a different folder (depends on the store provider).
You may also consider using the message id from the message MIME header (PR_INTERNET_MESSAGE_ID and PR_TRANSPORT_MESSAGE_HEADERS). But they are not set on newly created items. These properties are available on the message received from an SMTP server or through the SMTP connector.

Related

Outlook error in inbox folder / MAPIFolder C# (Microsoft.Office.Interop)

i always have the following errors in my inbox:
Native View To inspect the native object, enable native code debugging.
I have the following code:
public void CheckForEmails()
{
Outlook._Application _app = new Outlook.Application();
Outlook._NameSpace _ns = _app.GetNamespace("MAPI");
Outlook.MAPIFolder inbox = _ns.GetDefaultFolder(Microsoft.Office.Interop.Outlook.OlDefaultFolders.olFolderInbox);
_ns.SendAndReceive(true);
List<Outlook.MailItem> ReceivedEmail = new List<Outlook.MailItem>();
Outlook.Items items = inbox.Items;
foreach (Outlook.MailItem mail in inbox.Items)
ReceivedEmail.Add(mail);
}
I have two mail addresses set up in Outlook.
IMAP and Exchange.
Perhaps relevant to mention.
First of all, don't use the foreach loop with COM objects. You will not be able to release COM objects in a timely manner and can reach the limit of COM references hold with the Exchange server.
The Items class from the Outlook object model is a collection of items that can represent your managed list of emails.

MailItem.GetConversation() on shared mailbox

I am using following code to display properties from original email in conversation.
void DemoConversation()
{
object selectedItem =
Application.ActiveExplorer().Selection[1];
// For this example, you will work only with
//MailItem. Other item types such as
//MeetingItem and PostItem can participate
//in Conversation.
if (selectedItem is Outlook.MailItem)
{
// Cast selectedItem to MailItem.
Outlook.MailItem mailItem =
selectedItem as Outlook.MailItem; ;
// Determine store of mailItem.
Outlook.Folder folder = mailItem.Parent
as Outlook.Folder;
Outlook.Store store = folder.Store;
if (store.IsConversationEnabled == true)
{
// Obtain a Conversation object.
Outlook.Conversation conv =
mailItem.GetConversation();
// Check for null Conversation.
if (conv != null)
{
// Obtain Table that contains rows
// for each item in Conversation.
Outlook.Table table = conv.GetTable();
Debug.WriteLine("Conversation Items Count: " +
table.GetRowCount().ToString());
Debug.WriteLine("Conversation Items from Table:");
while (!table.EndOfTable)
{
Outlook.Row nextRow = table.GetNextRow();
Debug.WriteLine(nextRow["Subject"]
+ " Modified: "
+ nextRow["LastModificationTime"]);
}
Debug.WriteLine("Conversation Items from Root:");
// Obtain root items and enumerate Conversation.
Outlook.SimpleItems simpleItems
= conv.GetRootItems();
foreach (object item in simpleItems)
{
// In this example, enumerate only MailItem type.
// Other types such as PostItem or MeetingItem
// can appear in Conversation.
if (item is Outlook.MailItem)
{
Outlook.MailItem mail = item
as Outlook.MailItem;
Outlook.Folder inFolder =
mail.Parent as Outlook.Folder;
string msg = mail.Subject
+ " in folder " + inFolder.Name;
Debug.WriteLine(msg);
}
// Call EnumerateConversation
// to access child nodes of root items.
EnumerateConversation(item, conv);
}
}
}
}
}
void EnumerateConversation(object item,
Outlook.Conversation conversation)
{
Outlook.SimpleItems items =
conversation.GetChildren(item);
if (items.Count > 0)
{
foreach (object myItem in items)
{
// In this example, enumerate only MailItem type.
// Other types such as PostItem or MeetingItem
// can appear in Conversation.
if (myItem is Outlook.MailItem)
{
Outlook.MailItem mailItem =
myItem as Outlook.MailItem;
Outlook.Folder inFolder =
mailItem.Parent as Outlook.Folder;
string msg = mailItem.Subject
+ " in folder " + inFolder.Name;
Debug.WriteLine(msg);
}
// Continue recursion.
EnumerateConversation(myItem, conversation);
}
}
}
It works fine on my personal inbox and shared mailbox added as additional inbox.
But all other shared mailboxes which I have full access but have auto-mapped in my Outlook client doesn't work.
Does anyone know if mailItem.GetConversation() supposed to work with shared mailboxes which are not added as additional account but are auto-mapped?
Because on these shared mailboxes, I get Conversation Items Count: 0even if there are other emails in the same conversation.
Thank you.
It works fine on my personal inbox and shared mailbox added as additional inbox.
It seems you just added a second account to the profile, not a shared mailbox.
GetConversation returns Null (Nothing in Visual Basic) if no conversation exists for the item. No conversation exists for an item if the store does not support Conversation view (for example, Outlook is running in classic online mode against a version of Microsoft Exchange earlier than Microsoft Exchange Server 2010).
Use the IsConversationEnabled property of the Store object to determine whether the store supports Conversation view and GetConversation is supposed to work.
Indeed, GetRootItems() return 0 for shared mailbox which is frustrating because Outlooks shows the mails as Conversations. What I have noticed is, that each email in Inbox of that shared mailbox has ConversationID assigned correctly, so solution is to iterated the folder and build own conversation collection based on ConversationID value. It contains not only incoming messages but also sent items, so really all elements of conversations. It works as charm at least for my purpose which was to calculate response time for that shared mailbox and average length of conversations.

EWS Managed API 2.2 Read\Write extended properties of attachments

Currently I'm working on migration of one big project from MAPI CDO to EWS (Managed API 2.2) to support Ex2016. All things were migrated well except one: I can't find the way how to read\write Attachments Extended Properties. Does anybody know how to do that or may be some workaround? This is very critical for me and I would be very appreciate for any help.
---Update:
Also tried to use native EWS to get property of attachment but without success too:
var ret = esb.GetAttachment(new GetAttachmentType()
{
AttachmentIds = new []{new AttachmentIdType()
{
Id = "AAMkADVhNjUzMzMyLTRiMDYtNDc4OS1hYjJjLWI1ZDA4ZWFhYTJkZQBGAAAAAADqFaOFYZSeQI5UObwGbjIJBwAOgaos6ORVS5+o5bQovn/kAAAAeN2cAAAOgaos6ORVS5+o5bQovn/kAAAeCoIuAAABEgAQAJPAuRg2gipPmEKfgW26mFU=",
}},
AttachmentShape = new AttachmentResponseShapeType()
{
BodyType = BodyTypeResponseType.Best,
BodyTypeSpecified = true,
IncludeMimeContent = false,
IncludeMimeContentSpecified = true,
AdditionalProperties = new []
{
new PathToExtendedFieldType() { PropertyType = MapiPropertyTypeType.Integer, PropertyTag = "0x3705"},
new PathToExtendedFieldType() { PropertyType = MapiPropertyTypeType.Integer, PropertyTag = "0x0E21"},
}
}
});
The response doesn't contain any of requested properties.
--- Update 2:
In project we use next properties of attachments:
PR_RECORD_KEY, PR_DISPLAY_NAME, PR_RENDERING_POSITION
PR_ATTACH_ENCODING, PR_ATTACH_NUM, PR_ATTACH_METHOD, PR_ATTACH_LONG_FILENAME, PR_ATTACHMENT_HIDDEN, PR_ATTACH_CONTENT_ID, PR_ATTACH_FLAGS, PR_ATTACH_MIME_TAG, PR_ATTACH_CONTENT_LOCATION, PR_ATTACH_SIZE
Also we create a couple of Custom Extended Properties with custom Property Set and tag some attachments with that props.
Some of Properties can be found in object model of EWS/ManagedApi like PR_ATTACH_SIZE but the problem with others and with custom props.
So we need to read/write standard attachment properties as well as custom.
In project we mark attachment itself, not embedded Item.
You can't access extended properties on Attachments or the Recipients collection in EWS outside of those properties that are made accessible as strongly typed properties by the API. The only place you can use Extended properties are at the message level.
That said can you explain more as to how your using Extended properties eg are these extended properties on embeded items. If that is the case then you could access those extended properties via the Item Attachment.
Looking at your code 0x3705 is the PR_ATTACH_METHOD property on an attachment there is no equivalent to this in EWS, rather EWS will return a different Attachment Class based on the Attachment type. Eg ItemAttachment, FileAttachment or ReferanceAttachment (eg for OneDrive Attachments). 0x0E21 is that Attachment number EWS is going to return the Attachments in the order of that number in GetItem request so you can compute that yourself. But the property is useless in EWS because to get an Attachment you need the EWSId unlike MAPI.
Cheers
Glen

How to cache in sharepoint 2010 based on login user

I need to store dynamically created xmldatasource for menu in cache based on the login user. The below code is returning the same data for all the users since i did not mentioned the login user. where do I need to mention the login name while add a cache? also i want to reset or remove the cache while add a new site from event receiver since sitemap has to recreate.
private static object _lock = new object();
public XmlDocument CacheData()
{
XmlDocument item;
lock (_lock)
{
item = (XmlDocument)Cache["SiteMapCache"];
if (item == null)
{
using (SPSite site = new SPSite(SPContext.Current.Site.Url))
{
SPWebApplication webapp = site.WebApplication;
item = GenerateMenu(webapp);
}
Cache.Add("SiteMapCache",
item, null,
DateTime.Now.AddMinutes(1),
System.Web.Caching.Cache.NoSlidingExpiration,
System.Web.Caching.CacheItemPriority.Default,
null);
}
return item;
}
}
one Not sure why you would be doing this. As if you built a Sharepoint OOTB publishing site, additional sub site's which a user had access to would appear. If you went down the root of caching each you could end up with loads of entries in the cache, as each one would need to be different.
Else add the USERName to the CacheKey name.
Then change your code so it first checks to see if the "SiteMapCache"+Spcontext.Current.Web.CurrentUser.name is null, if it is fetch it and store it as cache.
You will need another cached item, to store a list of users who have been added to the cache.
Then if a new site is created, loop through each one and set cached item to null.

Reading ALL custom properties on Exchange Server with EWS

I would like to read all "Custom properties" from EWS-Items. I do have the names of the properties (e.g. "duration" oder "distance") but I did not create them (my clients did).
I guess I will have to use "ExtendedProperties" of the "Item" class. But when I use Item.Bind() with a Property-set I need to know a GUID which I don't have! Microsoft says (http://msdn.microsoft.com/en-us/library/exchange/dd633697%28v=exchg.80%29.aspx):
"Create a GUID identifier from the GUID that was used when the extended property was created."
I don't have these GUIDs because I did not create the properties.
I guess the only chance is to use Item.Bind() without a specific property set. Would that slow down the process (I need to call this for every item in the mailbox)?
I basically would like to iterate with a clause like this:
if (extendedProperty.PropertyDefinition.Name == "duration")
Any ideas how to do this?
Thanks
Martin
try to recover it by name using the PropertyDefinition and property type (MapiPropertyType):
//Search for "duration" property
Microsoft.Exchange.WebServices.Data.ExtendedPropertyDefinition extendedPropertyDefinition =
new Microsoft.Exchange.WebServices.Data.ExtendedPropertyDefinition
(DefaultExtendedPropertySet.Common, "duration", MapiPropertyType.String);
EmailMessage msgMod = EmailMessage.Bind(service, msgComplete.Id,
new PropertySet(extendedPropertyDefinition));
ExtendedPropertyCollection colProp = msgMod.ExtendedProperties;
foreach (ExtendedProperty prop in colProp)
{
//Iterate properties
}

Resources