Perform search query in Outlook - c#

Hello I am wondering if it is possible to send a search query to Outlook 2010 from my WinForms app. That is, not search the .PST file as I've been searching around and finding, I'm trying to display a list of results in Outlook as if I typed in the search box myself.
If it is possible, any example code would be helpful. Additionally, is it possible to directly perform a search in All Mail Items versus, usually when you do a search it combs the current folder. Thanks.

If you want to access the Outlook data (mail for example) you have to add a COM reference to the Microsoft Outlook X.X Object library.
For Outlook you can use COM interop. Open the Add Reference dialog and select the .NET tab, then add a reference to the Microsoft.Office.Interop.Outlook assembly.
Afterwards don't forget to add the namespace "Microsoft.Office.Interop.Outlook" to your using clauses.
Now you can create an instance of the Outlook application object:
Microsoft.Office.Interop.Outlook.Application outlook;
outlook = new Microsoft.Office.Interop.Outlook.Application();
Let's perform a query on your inbox:
MAPIFolder folder =
outlook.GetNamespace("MAPI").GetDefaultFolder(OlDefaultFolders.olFolderInbox);
IEnumerable<MailItem> mail =
folder.Items.OfType<MailItem>().Where(m => m.Subject == "Test").Select(m => m);
You specify the folder you want to search as a parameter for the GetDefaultFolder(...) method. You can specify other folder besides the inbox.
olFolderSentMail
olFolderOutbox
olFolderJunk
...
Check out each possible value on MSDN:
OlDefaultFolders Enumeration
Stefan Cruysbergs created an OutlookProvider component which acts as a wrapper for the Outlook application object. You can use LINQ to query this provider and retrieve data such as the contacts, mail...etc.. Just download his code and check it out. This should be enough to get you started.

Related

VSTO - When get Outlook accounts list from NameSpace.Accounts it returns cached data

I'm working on a plugin for Outlook. I need to always have an up-to-date list of Outlook accounts (File->Add Account), but when I take this data from NameSpace.Accounts, they are relevant only at the time Outlook starts. If I add another account or delete the old one, these changes will not be reflected in NameSpace.Accounts. Is there any way to refresh this data?
I am using the following code to get accounts
var outlookObj = new Outlook.Application();
var accounts = outlookObj.Application.Session.Accounts;
foreach (Outlook.Account account in accounts)
{
//do something
}
Firstly, do not use new Outlook.Application() in an addin - an instance of the Application object is provided to your addin on startup, and it is not handicapped by the security prompts..
Also try to avoid caching/keeping a reference to the Accounts or Account object.
If using Redemption is an option (I am its author), it exposes RDOAccounts collection (which is never cached) and, unlike the Accounts collection in OOM, also exposes events when accounts are added/deleted/modified/rearranged.
The Outlook object model doesn't provide such events for accounts. But you may try to handle the Stores.StoreAdd event which is fired when a Store has been added to the current session either programmatically or through user action.
Note, as a possible workaround you may consider using a third-party library such as Redemption which can monitor changes to Accounts in Outlook.
There is no need to create a new Application instance in the code:
var outlookObj = new Outlook.Application();
Instead, in VSTO based add-ins you need to use the ThisAddin class where the Application property is provided out of the box.

C# - Outlook VSTO - Exchange - "GetFolderFromID" The message interfaces returned an unknown error

I have a problem with my Outlook addin.
First of all, a very very simple overview of the workflow:
The addin is supposed to get a folder list from the exchange server (public folders).
The user can select one of this folders.
The folderid of the selected public folder will be converted from the IdFormat EwsId to HexEntryId to get the mapifolder afterwards.
Then the user can open the folder in Outlook. This is done by setting the this.Application.ActiveExplorer().CurrentFolder.
The complete code:
// _service is an instance of ExchangeService (Microsoft.Exchange.WebServices.Data)
// The publicFolder is the selected public folder (type of Microsoft.Exchange.WebServices.Data.Folder)
var objAltPublicFoldId = new AlternatePublicFolderId(IdFormat.EwsId, publicFolder.Id.UniqueId);
var objId = (AlternatePublicFolderId)_service.ConvertId(objAltPublicFoldId, IdFormat.HexEntryId);
var outlookFolder = Application.Session.GetFolderFromID(objId.FolderId);
this.Application.ActiveExplorer().CurrentFolder = outlookFolder;
Most of the time this works good. But some users are getting an error while trying to open the folder.
The exception is always thrown by the method to get the mapifolder object ( Application.Session.GetFolderFromID(objId.FolderId);).
The error message is:
the message interface returned an unknown error if the problem persists restart outlook
But again, this only happens for a few users, but once a user goets this error there is a great chance that this problem will persist until the complete Office installation has been reinstalled. I haven't found any other way to fix this issue so far and the problem seems to come out of nowhere.
All I've found out so far is that the objId.FolderId always contains the correct value, and that this affects all folders, not only a specific one. But the user can manually open the folder in Outlook.
The Outlook versions of the affected people are 2016 and 365.
The affected assembly is the Microsoft.Office.Interop.Outlook.
The reference to this assembly has following properties:
Description: Microsoft Outlook 16.0 Object Library
Filetype: ActiveX
Identity: {00062FFF-0000-0000-C000-000000000046}\9.6\0\primary
Path: C:\WINDOWS\assembly\GAC_MSIL\Microsoft.Office.Interop.Outlook\15.0.0.0__71e9bce111e9429c\Microsoft.Office.Interop.Outlook.dll
Version: 9.6.0.0
I really hope that there is someone who's had the same issue and found a solution for that.
Right now, anything could be the source of the error. The Exchange Server, the network, outlook, the Microsoft.Office.Interop.Outlook assembly, the enabled cached mode.

Outlook API GetItemFromID() fails with error "Could not open the item.Try again." when using multiple outlook accounts

I am using two outlook accounts from the same exchange server (i.e. same domain). We have an outlook add-in which we use to archive some emails from outlook to an external web application. While composing a new mail, it's possible to attach some files from external application to the mail being composed using the add-in.
Now things work perfectly when I have a single account on outlook. But after configuring another account and trying to do the same from secondary account, outlook gives error:
Outlook Initiator exception:
System.Runtime.InteropServices.COMException (0x80040107): Could not
open the item. Try again. at
Microsoft.Office.Interop.Outlook.NameSpaceClass.GetItemFromID(String
EntryIDItem, Object EntryIDStore)
I tried to dig into the code and found that the call to GetItemFromID() gives the exception shown above.
object item = ns.GetItemFromID(objectID, storeId);
The first parameter objectID (which is EntryIDItem) is different for different accounts but second parameter storeId is same.
I also tried to see the body of the method GetItemFromID() using disassembler but the method is defined as an extern method that means it's defined outside of the current assembly as un-managed code.
Tried to search for anything similar to that on stackoverflow but no luck. Can anybody please help me on this?
Try to leave only the first parameter. The EntryIDStore parameter is optional. See NameSpace.GetItemFromID for more information.
Note, 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.

Closing an Outlook Contact window created and opened from code shuts down Outlook itself (bad)?

I have an C# WPF application that reads in a bunch of local Outlook contacts and stores them in memory. When a search is conducted in the app, a list of ResultObjects is generated and bound to a ListBox which is show onscreen in my app. A property of a ResultObject is the Outlook Contact it was derived from (Outlook.ContactItem), and I use that to bind to a buttons Tag property (which can be anything you want to assign to it), so that when a user click on the button beside a result they want, the Outlook contact window itself will open to display the contact.
When I pull the list of contacts initially an instance of Outlook is required and created, and the running process is there.
public Outlook.Application usersOutlook = new Outlook.Application();
The problem is, after my code opens an Outlook contact window for the object associated with the clicked button:
buttonContact = (Outlook.ContactItem) ((Button)sender).Tag;
buttonContact.Display();
and then the user closes that window, my running Outlook.Application (and it's process/PID) closes with it - which is not what I want. I need Outlook to stay running for the next contact the user wants to see. With no Outlook still running, the button to show the contact fails. If I brute force a new instance of Outlook, thus creating a new process, clicking the button to show a contact raises an nasty "RPC Server is Unavailable" error which I've yet been able to get around / figure out.
The only way for my app to work properly is if the user starts up Outlook them selves, so the whole app is running on their machine, and then they leave it running while my app is running. That way when they close a contact opened by Outlook via my code, Outlook itself keeps chugging along, and then next contact the user wants to see will work . That is not an acceptable compramise for my customer - they demand Outlook running not be a requirement for the user. The app needs to create a hidden instance in code-behind and maintain it for the lifetime of my running app.
I'd suggest keeping the id of Outlook items in the Tag property of your controls instead. So, you will be able to recover them back with any Outlook instance (even if it is gone). The GetItemFromID method of the Namespace class returns a Microsoft Outlook item identified by the specified entry ID (if valid). For more information about Entry IDs, see the EntryID property:
A MAPI store provider assigns a unique ID string when an item is created in its store. Therefore, the EntryID property is not set for an Outlook item until it is saved or sent. 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. The EntryID property returns a MAPI long-term Entry ID.
That's what Outlook does - closes itself when the last window (Explorer or Inspector) is closed, even if there are still references to Outlook Object Model objects. The only exceptions are the Explorer and Inspector objects, even if they are not visible.
Try to retrieve an Explorer object from an instance of the MAPIFolder object (MAPIFolder.GetExplorer) and keep it referenced until you are done. You don't have to do anything with it, just keep it referenced in a global/class variable. MAPIFolder can be any Outlook folder, e.g. the default Contacts folder returned by Namespace.GetDefaultFolder(olFolderContacts).

Setting Outlook signature for multiple accounts

I am in the process of writing an application that sets a signature based on pre-acquired data for each Microsoft Outlook account(a user may have multiple Outlook accounts for various purposes).
I am able to set a signature for the default account, but I have yet to find how to set a signature for each Outlook account individually. I have done a lot of my own research and poked around the Microsoft.Office.Interop objects without much luck.
Is there a way to achieve this?
To choose the Outlook profile programmatically, you just use
Microsoft.Office.Interop.Outlook.Application App =
new Microsoft.Office.Interop.Outlook.Application();
NameSpace mapi = App.GetNamespace("MAPI");
mapi.Logon(profileName);
obviously setting the profileName to what is shown in the dropdown list upon starting Outlook (if you do not set a default profile in the control panel email settings).
This however is problematic in a number of ways since Outlook does not support multiple sessions even though the MAPI logon does:
http://msdn.microsoft.com/en-us/library/bb219914(v=office.12).aspx
Meaning: if Outlook is already running, you can even set NewSession to true, but it won't help. It will give you the currently-logged-in profile regardless of what name you set. If you have an Outlook zombie (I got that while testing, check with task manager), i.e. an Outlook without an UI showing up, the problem is the same.
If you can ensure Outlook does not run while doing stuff with signatures, you should be fine though.

Categories

Resources