Search folder for unread emails in inbox not including subfolders - outlook

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.

Related

Outlook flickering on adding too much recipients to "To" field when composing a new e-mail

I have an VSTO Outlook Add-in. In compose windows, every time a recipient is added to the "To" field, I iterate over all the recipients to search for some recipients not satisfying a particular condition. I add the ones that do not comply some rules to a List of strings. This list contains the displays names or e-mail addresses of the recipients that didn't comply the rules (I am not creating a list of Outlook COM objects).
I have noticed that the more recipients I add to the "To" field, the more slow Outlook it is by processing all them. I don't know what is Outlook internally doing for each recipient but I can see each of them are underlined maybe because they are resolved fine for Outlook, I don't know. During this process I can see that the "To" field is flickering too much.
Why is it happening? The culprit is my VSTO Add-in or the Outlook itself that it is not able to process well too much recipients and it has difficulties.
I simply do this:
List<string> recipientsNotSatisfyingCondition = new List<string>();
Outlook.Recipients recipients = this.MyMailItem?.Recipients;
try
{
for (int i = 1; i <= recipients.Count; i++)
{
Outlook.Recipient recipient = recipients[i];
if (recipient_does_not_complains_some_rules)
{
recipientsNotSatisfyingCondition.Add(recipient.Name ?? recipient.Address);
}
if (recipient != null)
{
Marshall.ReleaseComObject(recipient);
recipient = null;
}
}
}
catch (Exception ex)
{
// Log error
}
finally
{
if (recipients != null)
{
Marshall.ReleaseComObject(recipients);
recipients = null;
}
}
The code looks good. But I'd suggest calling the Recipients.ResolveAll method which attempts to resolve all the Recipient objects in the Recipients collection against the Address Book before iterating over all recipients in the collection and getting the Address property.
On the Extended MAPI level, there is no "recipient" object - recipients are stored in an IMAPITable object (IMessage::GetRecipientTable) that stores all recipients, and the whole table can be retrieved in a single call using IMAPITable::QueryRows or HrQueryAllRows. That would require Extended MAPI (C++ or Delphi), but the bigger problem is that you are working with a new message that might not be saved yet and the changes made on the OOM or Outlook UI level are not yet committed to the underlying MAPI object (IMessage). You can call MailItem.Save before retrieving IMessage object from MailItem.MAPIOBJECT and recipients using IMessage::GetRecipientTable / HrQueryAllRows, but saving the message might be undesirable.
If using Redemption (any language, I am its author) is an option, you can bypass OOM (and thus eliminate the flickering) using SafeMailItem object. It also exposes Commit method that forces Outlook to commit the data to the IMessage object without saving it in the Drafts folder and preserves the item's dirty state.
As a quick test, does the following script cause flickering? You can run it in OutlookSpy (I am also its author) - open a draft message with a large number of recipients, click Script button on the OutlookSpy ribbon, paste the script, click Run:
set sItem = CreateObject("Redemption.SafeMailItem")
sItem.Item = Application.ActiveInspector.CurrentItem
sItem.Commit 'commit changes to MAPI without saving the message
for each recip in sItem.Recipients
Debug.Print recip.Address
next

Office interop is unable to get the updated TaskItem from outlook when task is updated from Outlook Web/Office Online

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.

How to enumerate values of custom user property in Outlook C#

I have created custom user property in Outlook called "Ownership". When someone from the team claim ownership of an email, person's name is saved as its value.
My question, is there any way to enumerate all the values of this custom property into combo box.
In simple words, get a list of all team members names (whoever has claimed ownership of an email in inbox folder).
I want to do something like this.
Outlook.UserDefinedProperties userDefinedProperties = null;
Outlook.UserDefinedProperty userDefinedProperty = null;
Outlook.MAPIFolder currentFolder = application.ActiveExplorer().CurrentFolder;
mailUserProperties = currentFolder.UserDefinedProperties;
mailUserProperty = mailUserProperties["Ownership"];
// Filling up the combo box
PersonCombo.Items.Add(userDefinedProperty.Value);
I want to use current folder because folder will have all the values while an email can only have one value of the custom property.
If this is not possible, is there any other way to get it done?
Thank you in advance.
There isn't a single query that will return all unique values of a particular named property. The best you can do is search for all items where the property exists (not null), and then build a list of unique values.
I do not think, however, this is a good of storing possible values - it really must be a single source, such as a particular GAL distribution list, or a hidden (associated) message in the folder that stores all possible values in a single property.
Thanks everyone for your input.
At the end, I ended up creating GAL distribution list as Dmitry suggested and used it for my purpose.

Open a shared calendar that is not a Default Calendar in Outlook 2013

I know this question has been sort of asked, but I have a specific issue which I haven't found the answer for. I am trying to open a shared calendar from another user and his/her calendar is NOT their default calendar.
I have tried the following:
var ns = Globals.ThisAddIn.Application.Session;
var recip = ns.CreateRecipient("me#me.com");
if (recip.Resolve())
{
var sharedCal = ns.GetSharedDefaultFolder(recip, Outlook.OlDefaultFolders.olFolderCalendar);
}
This just does not work.
I can see the shared calendar by doing the following
private void GetCalendars()
{
Outlook.CalendarModule calModule = (Outlook.CalendarModule)this.Application.ActiveExplorer().NavigationPane.Modules.GetNavigationModule(Outlook.OlNavigationModuleType.olModuleCalendar);
foreach (Outlook.NavigationGroup group in calModule.NavigationGroups)
{
Debug.WriteLine("Calandar Folders Group >>>>" + group.Name);
foreach (Outlook.NavigationFolder folder in group.NavigationFolders)
{
Debug.WriteLine("Calandar Folders: >>>>" + folder.DisplayName);
}
}
}
I just don't know how to open the calendar once I have the name. There is no way to get the ID using the steps above
In outlook, the calendar exists in the "Shared Calendars" navigation tree.
I am looking for a way to get the names of the Shared Calendars and then having the user select the shared calendar (E.g. From a dropdown box) and then opening that calendar.
I have found code on how to do everything else but not that specifically!
Can someone point me in the right direction??
Thanks!!
You cannot access that folder using the Outlook Object Model.
For a cached Exchange mailbox, the folders are cached n the primary mailbox's OST file. On the Extended MAPI level (C++ or Delphi), the folders are stored outside of the IPM tree visible to the end user. You can see the data in OutlookSpy (I am its author) - click IMsgStore | Open Root Folder | GetHierarchyTable | double click on the "Shared Data" folder | GetHierarchyTable | etc.
You can open that folder using Redemption (I am also its author - start with RDOStore.RootFolder). You can also open the online mailbox of another user using RDOSession.GetSharedMailbox and navigate to the folder in question starting with RDOStore.IPMRootFolder (returns top level folders visible to the user in that mailbox).

Access original subject of meeting in Resource calendar

I'm trying to set up a system that displays calendar items from a resource calendar on a web page using Exchange 2007 and EWS (Exchange Web Services).
I've managed to get access to the calendars of the resources, but when getting the items in the calendars, the subject of each calendar item is not the original subject used when someone created the meeting request and invited the resource, but rather the Username on the account that created the the meeting request eg. if I do something like:
List<CalendarItemType> items =
Calendar.GetCalendarItems("mr1#litwareinc.com",
Calendar.GetNextWeekView(),
binding);
if (items.Count > 0)
{
Console.WriteLine(string.Format("Calendar opened - fetched {0} items",
items.Count));
Console.WriteLine("===================================");
foreach (var item in items)
{
Console.WriteLine();
Console.WriteLine(item.Subject);
Console.WriteLine("----------------------------------------");
Console.WriteLine("\tOrganizer: " + item.Organizer.Item.Name);
Console.WriteLine();
Console.WriteLine("\tStart: " + item.Start.ToString("dd-MM-yyyy HH:mm"));
Console.WriteLine("\tSlut: " + item.Start.ToString("dd-MM-yyyy HH:mm"));
}
}
Where Calendar.GetCalendarItems, is a method that fetches the calendar items of the resource denoted by the first argument, the Calendar.GetNextWeekView() is a static method that creates a CalendarView spanning the next week from today's date, and the binding is set up to use an account with delegate access to the resource mailbox.
The item.Subject comes out as Administrator if the Administrator account was used to book the resource.
Does anyone know how to remedy this - do I need to make some kind of special property access, or fetch another type of item or what?
Regards
Jesper Hauge
Figured this one out - when I started looking outside the code.
Answer lies in resource configuration rather than access code.
If you want to have the subject of the meeting reflect the original subject. Make sure the resource has set the setting properties DeleteSubject and AddOrganizerToSubject to false. It can be achieved with the following shell command:
Set-MailboxCalendarSettings resourcename -DeleteSubject 0 -AddOrganizerToSubject 0
Regards
Jesper Hauge

Resources