I'm bedeviled by this. I have a c# application that I need to have a backup before I modify my main contact. But it seems that the copy, sticks around no matter what. I'm verifying this by visual check at the contents of my contents folder in Outlook.
I have a simple test case like so...
Application outlookApplication = new Application();
NameSpace outlookNamespace = outlookApplication.GetNamespace("mapi");
outlookNamespace.Logon("", "", true, true);
MAPIFolder Folder = outlookNamespace.GetDefaultFolder(OlDefaultFolders.olFolderContacts);
MAPIFolder Folder2 = Folder.Folders["Test1"];
Items ContactItems = Folder2.Items;
foreach (ContactItem Contact in ContactItems)
{
ContactItem Backup = (ContactItem)Contact.Copy();
Backup.Delete();
break;
}
outlookNamespace.Logoff();
outlookNamespace = null;
If I try to delete it twice, it causes an error.
Even tried moving it to the deleted items folder, but no luck. Outlook 2010. What is going on?
EDIT: WORKAROUND: If I create a new contact and populate from the original, I can delete it just fine.
I'm not familiar with C# syntax, but I suspect it's because you are adding to the Items collection when you create the copy. I would do this:
Before the start of the foreach loop, check the count of ContactItems:
Items ContactItems = Folder2.Items;
' display ContactItems.Count here, is it Console.WriteLine(ContactItems.Count) ??
After creating the copy, check the ContactItems.Count again. If it has increased, then you need to change your loop to a "For i = ContactItems.Count to 1 Step -1" type of loop instead of a foreach loop (sorry, I only know the VB syntax, I don't know the equivalent C# syntax). It has to be a backwards loop.
If that doesn't work, then create a copy and add it to another Contacts folder, that way it won't interfere with the Items collection of the folder you are working with. That is similar to what you are already doing.
Related
I am developing an outlook add in that retrieves a TaskItem from outlook desktop and opens it. Here is my code.
private static Microsoft.Office.Interop.Outlook.TaskItem GetLatestTask(string entryId)
{
Microsoft.Office.Interop.Outlook.MAPIFolder taskFolder = Application.Session.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderTasks);
List<Microsoft.Office.Interop.Outlook.TaskItem> liTask = new List<Microsoft.Office.Interop.Outlook.TaskItem>();
foreach (Microsoft.Office.Interop.Outlook.TaskItem taskItem in taskFolder.Items)
{
if (taskItem.EntryID == entryId)
return taskItem;
}
}
This works fine usually. However if i update the task from outlook web/Office online, then try to get the task using the code, the task i get is not updated and still contains the old values.
So for example i have a task with a subject named "Test" then i update this in outlook web to "Test Updated", I would still get a task with a subject named "Test".
If I check the task list in outlook desktop, I can see that the task's subject has already been updated in the Task list. However opening it would still display the old item.
Once I restart Outlook, The add in gets the updated item.
Can anyone point me in the right direction? Thank you.
First of all, iterating over all items in the folder is not really a good idea:
foreach (Microsoft.Office.Interop.Outlook.TaskItem taskItem in taskFolder.Items)
{
if (taskItem.EntryID == entryId)
return taskItem;
}
Instead, you may consider using the Find/FindNext or Restrict methods of the Items class. Read more about them in the following articles with code sample:
How To: Use Find and FindNext methods to retrieve Outlook mail items from a folder (C#, VB.NET)
How To: Use Restrict method to retrieve Outlook mail items from a folder
Also relying on the EntryID property for identifying items in Outlook is not the best way. 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. Instead, you may introduce your own custom property for identifying items.
If you use cached data most probably you need to sync your data with the server side. SyncObjects is a set of SyncObject objects representing the Send/Receive groups for a user. Use the SyncObjects property to return the SyncObjects object from a NameSpace object.
Set mySyncObjects = Application.GetNameSpace("MAPI").SyncObjects
The SyncObject.Start method begins synchronizing a user's folders using the specified Send\Receive group.
Public Sub Sync()
Dim nsp As Outlook.NameSpace
Dim sycs As Outlook.SyncObjects
Dim syc As Outlook.SyncObject
Dim i As Integer
Dim strPrompt As Integer
Set nsp = Application.GetNamespace("MAPI")
Set sycs = nsp.SyncObjects
For i = 1 To sycs.Count
Set syc = sycs.Item(i)
strPrompt = MsgBox( _
"Do you wish to synchronize " & syc.Name &"?", vbYesNo)
If strPrompt = vbYes Then
syc.Start
End If
Next
End Sub
Hopefully, after that, your items will be updated with a new data.
I would like to make a search folder for unread emails in the inbox which does not look into subfolders in the inbox.
Right now I have 5-10 subfolders which are automatically filled with news emails from different sources( using ordinary rules), and then I use the top level of the inbox folder as a kind of important email folder. I would like to make a search folder which finds the unread emails in the top level of the inbox folder but ignores everything in the subfolders.
Outlook version: 1808 (I think). It is part of MS office 365 but it does run locally.
You need to use the Application.AdvancedSearch method which performs a search based on a specified DAV Searching and Locating (DASL) search string. The AdvancedSearch method and related features in the Outlook object model do not create a Search Folder that will appear in the Outlook user interface. However, you can use the Save method of the Search object that is returned to create a Search Folder that will appear in the Search Folders list in the Outlook user interface.
The key benefits of using the AdvancedSearch method in Outlook are:
The search is performed in another thread. You don’t need to run another thread manually since the AdvancedSearch method runs it automatically in the background.
Possibility to search for any item types: mail, appointment, calendar, notes etc. in any location, i.e. beyond the scope of a certain folder. The Restrict and Find/FindNext methods can be applied to a particular Items collection (see the Items property of the Folder class in Outlook).
Full support for DASL queries (custom properties can be used for searching too). You can read more about this in the Filtering article in MSDN. To improve the search performance, Instant Search keywords can be used if Instant Search is enabled for the store (see the IsInstantSearchEnabled property of the Store class).
You can stop the search process at any moment using the Stop method of the Search class.
string scope = "Inbox";
string filter = "[UnRead] = true";
Outlook.Search advancedSearch = null;
Outlook.MAPIFolder folderInbox = null;
Outlook.MAPIFolder folderSentMail = null;
Outlook.NameSpace ns = null;
try
{
ns = OutlookApp.GetNamespace("MAPI");
folderInbox = ns.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox);
scope = "\'" + folderInbox.FolderPath "\'";
advancedSearch = OutlookApp.AdvancedSearch(
scope, filter, false, advancedSearchTag );
advancedSearch.Save();
}
catch(Exception ex)
{
MessageBox.Show(ex.Message, "An eexception is thrown");
}
finally
{
if(advancedSearch!=null) Marshal.ReleaseComObject(advancedSearch);
if (folderSentMail != null) Marshal.ReleaseComObject(folderSentMail);
if (folderInbox != null) Marshal.ReleaseComObject(folderInbox);
if (ns != null) Marshal.ReleaseComObject(ns);
}
In the search box type "Read:unread" without quotes
Once located in the folder where you want to search, in the App Outlook Office 365 you can find the filter of unread emails, like this in the following image.
I know this wasn't an issue before but suddenly when i look at the folders that are under the RDOPstStore or RDOStore IPMRootFolder now i only get the standard folder names of Inbox, Deleted Items, Outbox, and Sent.
There is an additional custom named folder called "whalley-g" that i need to recursively iterate through.
This was working fine at one point for a year, but now i only get the four folders.
Redemption.RDOSession mySession = new Redemption.RDOSession();
Redemption.RDOPstStore pst = mySession.LogonPstStore(pstToProcess.PSTFullPathAndName, 1, "Outlook", 1, 1);
int numFolders = pst.IPMRootFolder.Folders.Count;
numFolders should be 5 but is only 4. I didn't bother with the recursive code since i just need to get by the fact that it isn't including the custom folder at all.
I'm trying to make my add-on save bookmarks in it's own bookmark folder.
This function created the desired folder, but I want it to return the id of the existing folder instead of forever making millions of new ones if it can find it by name:
function special_bookmark_folder()
{
menuFolder = bmsvc_service().bookmarksMenuFolder;
// <Try and find the bookmark folder here!>
return bmsvc_service().createFolder(menuFolder, ":: Bookmarkr ::", bmsvc_service().DEFAULT_INDEX);
// else return id of existing folder if it's found here
}
You have to use the Places query APIs, which isn't the most straightforward task. Thankfully there is an example with exactly what you want
I know that when an item is restored from the recycle bin, the ItemAdded event is fired.
However, how can I detect if the item added comes from the recycle bin or if it is a new file.
This is a very old thread, but it comes up in the top results for searches on the topic.
From my experiments with SP2010, it looks like properties.AfterProperties is empty when the item is coming from the Recycle Bin, whereas it is fully populated on an actual new item.
So, a simple block such as this would do the trick:
if (!properties.AfterProperties.Cast<DictionaryEntry>().Any())
{
// From Recycle Bin!
}
else
{
// This item is really new.
}
I have not tested MOSS or SP2013 yet.
You could check the Created Date of the item. Items from the Recycle bin should have a previous created date.
Items in the recycle bin have a DeletedDate that may be available in the properties.BeforeProperties
If you want detect it manually, then check the property of the document: there created data is different. For a document even if it was thrown into recycle bin the created data is the same.
If you want do it through kind of workflow then you can set property as a benchmark. more detail please find it yourself.
Check the value of the SPItemEventProperties.ListItemId property:
If it is 0, then it is a new item;
If it is not 0, then it is an item
that is restored from the Recycle Bin.