I understand that user can not move messages cross EAS account boundaries. Moving messages inside the same EAS account is perfectly fine when done manually from Outlook windows, but fails when done through automation objects. What's wrong here?
Outlook.MailItem item = Outlook.Namespace.GetItemFromID(MailItemEntryEid, MailItemStoreEid);
Outlook.MAPIFolder folder = Outlook.Namespace.GetFolderFromID(MAPIFolderEntryEid, MailItemStoreEid);
Outlook.MailItem newItem = item.Move(folder);
both item and folder objects constructed correctly, and belong to the same EAS store, however .Move on the last line is failing with this error:
(0x80040102): Sorry, Exchange ActiveSync doesn't support what you're trying to do.
If I do item.Delete() that moved the item to the Deleted Items folder
The "0x80004005" or "0x80040102" error message when you access a mailbox on an Exchange Server 2010 server by using a MAPI client article describes a similar issue. Do you work with public folders?
Anyway, you can use the Copy method instead and then Delete the source item.
Try to use MailItem.Copy followed by MailItem.Move before calling Save:
set Item = Application.ActiveExplorer.Selection(1)
set Target = Application.Session.GetDefaultFolder(olFolderDrafts)
set newItem = Item.Copy
set newItem = newItem.Move(Target)
Related
I am performing custom action on all incoming replies through VSTO add-in. The add-in will compare ConversationID of incoming reply with existing email. It works fine if I have to search inside one folder but my problem is email can be in any folder in store. Here is my code.
void items_ItemAdd(object Item)
{
Outlook.Application application = new Outlook.Application();
string filter = "RE: ";
Outlook.MailItem mail = (Outlook.MailItem)Item;
Outlook.Folder folder = mail.Parent as Outlook.Folder;
if (Item != null)
{
if (mail.MessageClass == "IPM.Note" && mail.Subject.ToUpper().Contains(filter.ToUpper()))
{
var RequiredMail = (from e in folder.Items.Cast<Outlook.MailItem>().OrderBy(X => X.ReceivedTime).Where(C => C.ConversationID == mail.ConversationID) select mail).FirstOrDefault();
// Perform custom action
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}
}
Also, I have read that searching for an email using Linq is not very efficient. Is there any other more efficient way to get RequiredMail?
Any help will be highly appreciated.
Thank you.
First of all, you must be aware that ItemAdd event may not be fired if more than sixteen items are added to the collection. This is a known issue in Outlook. The following series of articles describes possible workarounds for that:
Outlook NewMail event unleashed: the challenge (NewMail, NewMailEx, ItemAdd)
Outlook NewMail event: solution options
Outlook NewMail event and Extended MAPI: C# example
Outlook NewMail unleashed: writing a working solution (C# example)
Mixing LINQ and COM objects is not a really good idea. You should release underlying COM objects instantly to prevent any known issues.
If you need to search for items in all folders you may use the AdvancedSearch method of the Application class which allows to perform a search based on a specified DAV Searching and Locating (DASL) search string.
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.
Read more about that in the Advanced search in Outlook programmatically: C#, VB.NET article.
I am writing an application that creates an overview of peoples Outlook calendars, i.e it will show the amount of unplanned time per week for the coming [n] weeks.
The basics are working, but there's one thing that I am having trouble with. Some users have shared their Outlook calendar in a way so that other users can only see availability information (the time and description of the appointments), but not any details.
I verified this by opening Outlook manually and opening a shared calendar; hovering the mouse over an appointment will show a popup with begin and end time, description and location, but double clicking it gives an error: "You are not authorized to display the calendar, do you want to ask [person] to share it?".
The relevant lines from my code are:
var outlook = new Application();
var mapiNamespace = outlook.GetNamespace("MAPI");
var recipient = mapiNamespace.CreateRecipient("Scott");
recipient.Resolve();
var calendarFolder = mapiNamespace.GetSharedDefaultFolder(recipient, OlDefaultFolders.olFolderCalendar);
var calendarItems = calendarFolder.Items;
Everything I now try to do with calendarItems will raise an exception. For instance, getting Count will raise a TargetInvocationException (The client process failed, but I'm not quite sure about the exact English translation). Calling Sort("[Start]") will raise a COMException with message Unknown property: Start. Both do work for fully shared calendars.
Now, for the overview, all I need is begin and end times, so I don't really want to ask everyone to change their sharing settings, especially when that shouldn't be necessary.
My questions are:
Most important: Is there another way to get availability info that I'm overlooking?
And related: Is Interop still the way to go these days, or are there alternatives? Maybe an Office365 webservice?
Instead of using GetSharedDefaultFolder and accessing the items in that folder, you can use Recipient.FreeBusy method.
I'm intercepting Outlook 2013's Application.ItemSend event in order to manipulate the categories assigned to a MailItem right before it's sent. Here's the event handler:
void Application_ItemSend(object Item, ref bool Cancel)
{
var mail = (Outlook.MailItem)Item;
mail.Categories = string.Join(";", "Foo", "Bar"); // Yes, the delimiter is ';' on my system.
mail.Save(); // Do I need this?
}
The problem is that the changes to the Categories property don't seem to be properly persisted. When I view the message in the Sent folder, it appears uncategorized.
Curiously, if I call mail.ShowCategoriesDialog() after changing the categories they appear checked as expected. This makes me suspect that I'm operating on a copy of the message.
What am I doing wrong?
It seems the issue was one of server configuration rather than my code. After connecting Outlook to GMail instead it worked as I expected.
It worked for me on Outlook 2013 ( 64-bit ) with a Gmail account configured. i.e. I can see the categories applied at all the steps - viz., while applying the categories in Visual Studio 2013, in the Outbox and also in the Sent Items folder.
Possible reason -
Some addin might be removing the categories in the Sent Item folder. try to disable other addin(s).
I’m trying to write a C# application that opens up a outlook custom mail item and fill in multiple user properties. I was able to do so by using the Microsoft Outlook Interop. But I had the annoying security warning each time I tried to change some user property. I found out that Redemption is the perfect tool to avoid this. But when I try to change a user property, Redemption creates a new one instead of using the already existing one.
This is the code I used to change the property with Outlook Interop (Pops up a security warning) :
string customPropertyNamespace = "http://schemas.microsoft.com/mapi/string/{00020329-0000-0000-C000-000000000046}/";
Outlook._Items oItems = oPublicFolder.Folders["Babillards"].Folders["SYSOTI"].Folders["MEP"].Items;
Outlook._MailItem oMep = oItems.Add("ipm.note.mep");
oMep.PropertyAccessor.SetProperty(customPropertyNamespace + "prop1", "SomeText");
oMep.Display(false);
This all works fine, except for the security warning...
This is the redemption code I'm trying to use :
string customPropertyGUID = "{00020329-0000-0000-C000-000000000046}";
Outlook._Items oItems = oPublicFolder.Folders["Babillards"].Folders["SYSOTI"].Folders["MEP"].Items;
Outlook._MailItem oMep = oItems.Add("ipm.note.mep");
Redemption.SafeMailItem Mep = new Redemption.SafeMailItem();
Mep.Item = oMep;
Mep.set_Fields(Mep.GetIDsFromNames(customPropertyGUID, "prop1"), "SomeText");
oMep.Display(false);
From what I understood this should work. But instead, my mail page opens with all my fields empty. By using OutlookSpy I found out that Redemption creates a new property with this DASL :
http://schemas.microsoft.com/mapi/string/{00020329-0000-0000-C000-000000000046}/prop1/0x0000001F
instead of :
http://schemas.microsoft.com/mapi/string/{00020329-0000-0000-C000-000000000046}/prop1
Can somebody help me? I also tried using the Redemption.MAPIUtils but I ended up with exactly the same result. Is there a way to change a user property by passing the DASL instead of a GUID and ID ?
The two property names are exactly the same - the last part (0x0000001F) is simply property type (= PT_UNICODE). What exactly do you mean by "my mail page opens with all my fields empty"? Do you have a custom form with controls bound to user fields?
Also keep in mind that Outlook might not see all the latest changes made with MAPI until the item is completely dereferenced and reopened. Do o use the data after you restart Outlook and reopen the existing item?
To avoid Outlook caching problem, try to create the message using Redemption, set the property, and only then open the message using Outlook. Somethiong like the following (off the top of my head):
string customPropertyNamespace = "http://schemas.microsoft.com/mapi/string/{00020329-0000-0000-C000-000000000046}/";
Outlook.Forlder oFolder = oPublicFolder.Folders["Babillards"].Folders["SYSOTI"].Folders["MEP"];
Redemption.RDOSession session = new RDOSesssion();
session.MAPUIOBJECT = Application.Session.MAPIOBJECT;
Redemption.RDOFolder rFolder = session.(RDOFolder)session.GetRDOObjectfromOutlookObject(oFolder);
Redemption.RDOMail rMsg = rFolder.Items.Add("ipm.note.mep");
rMsg.Fields[customPropertyNamespace + "prop1"] = "SomeText";
rMsg.Save();
//reopen in Outlook and display. Or you can use rMsg.Display()
Outlook._MailItem oMep = Application.Session.GetItemFromID(rMsg.EntryID);
oMep.Display(false);
Is it possible to obtain Outlook Mail Item details by dragging and dropping a single attachment from a .MSG file onto a C# application? My application currently separates the contents of a .MSG when this is dropped onto my application, however I want to go a step further and obtain sender, date/time received etc from a single attachment that is part of the .msg. This is what I'm trying at the moment:
Outlook.Application myApp = new Outlook.Application();
object selectedItem = myApp.ActiveExplorer().Selection[1];
Outlook.MailItem item = selectedItem as Outlook.MailItem;
string sender = item.SenderName;
When I try to cast selectedItem as an Outlook.Mail Item nothing happens. Any help with this would be appreciated
Thanks
Chris
Since my initial post I have been looking at other ways in which to obtain the information that Im looking for as I have not been successful with the method above..
I have looked at the following article http://msdn.microsoft.com/en-us/library/aa219397(v=office.11).aspx and implented the code in a test project. I know initially I asked if I could obtain the msg details from the attachement, however if a user drags an attachment from the current open message then I was wondering if it were possible to obtain the message details from the ActiveExplorer method.
At the point where:
myOlSel.Item(x).SenderName & ";"
Outlook prompts me with " A program is trying to access email address..." but at this the message box hangs and I cannot select one of the options. After doing some further reading I understand why this is in place but is there anyway around it?
Thanks
Chris
Maybe the selectedItem is null because there actually is no selected item at index 1?
I have the follwowing at is is working (althou it's with an Appointment item)
Inspector activeInspector = this.OutlookApp.ActiveInspector() as Inspector;
object currentItem = activeInspector.CurrentItem;
if (currentItem != null && currentItem is AppointmentItem)
{
AppointmentItem appItem = currentItem as AppointmentItem;
}
Perhaps you should use Selection[0]?