I am developing a calendar for my firm that synchronizes with Outlook Calendar.
Atm I can:
import appointments from Outlook and show them in my calendar
update my appointments when Outlook appointments get updated
create Outlook appointments when appointments get created in my calendar
The only issue I have is updating/deleting Outlook appointments when my appointments update/delete.
I have the GlobalAppointmentID of the corresponding appointments but I can't seem to search on that ID.
I tried:
using Microsoft.Office.Interop;
private void GetAppointment(string myGlobalAppointmentID)
{
Outlook.Application oApp = new Outlook.Application();
Outlook.NameSpace mapiNamespace = oApp.GetNamespace("MAPI");
Outlook.MAPIFolder calendarFolder = mapiNamespace.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderCalendar);
Outlook.Items outlookCalendarItems = calendarFolder.Items;
Outlook.AppointmentItem appointmentItem = (Outlook.AppointmentItem)outlookCalendarItems.Find("[GlobalAppointmentID] = '{0}'", myGlobalAppointmentID));
//update or delete appointmentItem here (which I know how to do)
}
I keep getting 'Condition is not valid' Exception.
Apparently Outlook does not allow to search on binary properties (such as GlobalAppointmentID).
I use the same outlookCalendarItems.Find() and calendarFolder.Items.Restrict() without problems in other instances.
I tried using Redemption but I couldn't get it to work either.
Does anybody have experience or a suggestion?
Yes, OOM won't let you search on binary properties (as well as recipients or attachments), but Redemption (I am its author) should work. The following script (VBA) worked just fine for me:
set Session = CreateObject("Redemption.RDOSession")
Session.MAPIOBJECT = Application.Session.MAPIOBJECT
set Folder = Session.GetDefaultFolder(olFolderCalendar)
set appt = Folder.Items.Find("GlobalAppointmentID = '040000008200E00074C5B7101A82E00800000000D0FECEE58FEAD70100000000000000001000000041C887A3FA12694F8A0402FEFFAD0BBB'")
MsgBox appt.Subject
The Outlook object model doesn't support searching for binary properties such as GlobalAppointmentId (any other PT_BINARY property) with Items.Find/Items.FindNext/Items.Restrict.
The only workaround is to loop through all item in the Calendar folder (which is inefficient) or search using Extended MAPI (or using third-party wrappers such as Redemption.
What I ended up doing after looking further:
I added a text UserProperty where I put the GlobalAppointmentID("GAID") in.
You can Filter on those.
And it seems to do the trick.
private void AddGAIDIfNeeded(Outlook.AppointmentItem app)
{
bool GAIDexists = false;
if (app.UserProperties.Count != 0)
{
foreach (UserProperty item in app.UserProperties)
{
if (item.Name == "GAID")
{
GAIDexists = true;
break;
}
}
}
if (GAIDexists == false)
{
app.UserProperties.Add("GAID", Outlook.OlUserPropertyType.olText);
app.UserProperties["GAID"].Value = app.GlobalAppointmentID;
app.Save();
}
}
And to find a specific AppointmentItem:
private void DeleteOutlookAppointmentByGAID(string globalAppointmentID)
{
Outlook.Application oApp = new Outlook.Application();
Outlook.NameSpace mapiNamespace = oApp.GetNamespace("MAPI");
Outlook.MAPIFolder calendarFolder = mapiNamespace.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderCalendar);
Outlook.Items outlookCalendarItems = calendarFolder.Items;
try
{
Outlook.AppointmentItem appointmentItem = null;
appointmentItem = outlookCalendarItems.Find(String.Format("[GAID] = '{0}'", globalAppointmentID));
if (appointmentItem != null)
{
appointmentItem.Delete();
}
}
catch (Exception ex)
{
classExecptionLogging.LogErrorToFolder(ex);
}
}
Related
When I Use OutlookSpy to get the EntryIDs from MailItems in a particular folder and supply them to the following code:
Outlook.Application myApp = new Outlook.ApplicationClass();
Outlook.NameSpace mapiNameSpace = myApp.GetNamespace("MAPI");
try
{
object obj = mapiNameSpace.GetItemFromID(sEntryID);
if (obj is Outlook.MailItem)
{
var getItem = (Outlook.MailItem)mapiNameSpace.GetItemFromID(sEntryID);
getItem.Display();
}
}
catch (Exception Ex)
{
Global.Common.LogError("Error accessing MailItem", Ex, "EntryID " + sEntryID + " not found in " + sFolder, "Warning");
}
I get unknown messaging errors for some EntryID values and successful display of the messages in Outlook with others. Can anyone suggest what attributes the MailItems might have which will affect whether I can display them successfully using GetItemFromID or any other method of displaying all messages by EntryID reliably?
Was the message store where the message resides touched in the active Outlook session? The way MAPI providers work, when a provider is loaded by MAPI, it registers the set of entry id guids (bytes 5-20 in the entry id) that it will handle. If the particular PST store has not been touched in the current session, MAPI does not know anything about its entry ids.
You can either access all the stores in the current session first (to make sure MAPI knows about their entry ids) or use the store entry id (second parameter, optional) when calling GetItemFromId - this way Outlook will open the store first, then ask the store to open the item. You can also call Namespace.AddStore / AddStoreEx to load the given PST file if it is not already in the current profile.
You might also want to log the exception details (Ex.Message) in your exception handler.
Thanks to all the respondents - this explains why sometimes particular messages would open and sometimes they would not. By getting the StoreId using the following code:
Outlook.Application myApp = new Outlook.ApplicationClass();
Outlook.NameSpace mapiNameSpace = myApp.GetNamespace("MAPI");
Object oStoreID = Common.GetFolder(myApp, sFolder).StoreID;
try
{
object obj = mapiNameSpace.GetItemFromID(sEntryID,oStoreID);
if (obj is Outlook.MailItem)
{
Outlook.MailItem getItem = (Outlook.MailItem)mapiNameSpace.GetItemFromID(sEntryID,oStoreID);
getItem.Display();
}
}
Where
public static Outlook.Folder GetFolder(Outlook.Application App, string folderPath)
{
Outlook.Folder folder;
string backslash = #"\";
try
{
if (folderPath.StartsWith(#"\\"))
{
folderPath = folderPath.Remove(0, 2);
}
String[] folders =
folderPath.Split(backslash.ToCharArray());
folder =
App.Session.Folders[folders[0]]
as Outlook.Folder;
if (folder != null)
{
for (int i = 1; i <= folders.GetUpperBound(0); i++)
{
Outlook.Folders subFolders = folder.Folders;
folder = subFolders[folders[i]]
as Outlook.Folder;
if (folder == null)
{
return null;
}
}
}
return folder;
}
catch { return null; }
}
All MailItems now display in Outlook.
I'll just throw this in here for posterity-- Outlook 2002 requires that the entry ID supplied to GetItemFromID use upper-case hex characters.
I am setting the property (for making them As Read and with High Importance) of the mail those are coming to the MS Outlook 2010 inbox using below code -
Microsoft.Office.Interop.Outlook.Application myApp = new Microsoft.Office.Interop.Outlook.Application();
Microsoft.Office.Interop.Outlook.NameSpace mapiNameSpace = myApp.GetNamespace("MAPI");
Microsoft.Office.Interop.Outlook.MAPIFolder myInbox = mapiNameSpace.GetDefaultFolder(Microsoft.Office.Interop.Outlook.OlDefaultFolders.olFolderInbox);
int i = myInbox.Items.Count;
((Microsoft.Office.Interop.Outlook.MailItem)myInbox.Items[i]).UnRead = false;
((Microsoft.Office.Interop.Outlook.MailItem)myInbox.Items[i]).Importance = OlImportance.olImportanceHigh;
This works fine when only one mail comes at a time (I can see the mail as Read and with High Importance) after the code execution but when three or four mails coming at a time then it set the property of only one mail not for all the three or four mails.
Please suggest.
Remember to save the message after setting any property.
Most importantly, your code uses multiple dot notation - for each ".", you get back a brand new COM object, so you end up setting Importance property on an object different from the one used to set the UnRead property.
int i = myInbox.Items.Count;
MailItem msg = (Microsoft.Office.Interop.Outlook.MailItem)myInbox.Items[i];
msg.UnRead = false;
msg.Importance = OlImportance.
msg.Save();
Another problem is that you assume that the last item in the Items collection is the latest one. This is not generally true. As cremor suggested, use Items.ItemAdd event, but still do not forget to save the message.
You can use the ItemAdd event of the Items property of the folder:
Items inboxItems = myInbox.Items;
inboxItems.ItemAdd += HandleItemAdded;
private void HandleItemAdded(object item)
{
MailItem mail = item as MailItem;
if (mail == null) { return; }
mail.UnRead = false;
mail.Importance = OlImportance.olImportanceHigh;
}
in my outlook addin I want to add a button on the Ribbon so when user click this button I want to retrieve the current selected email's body , I have this code but it retrieve only the first email from the inbox because the index is 1 :
Microsoft.Office.Interop.Outlook.Application myApp = new Microsoft.Office.Interop.Outlook.Application();
Microsoft.Office.Interop.Outlook.NameSpace mapiNameSpace = myApp.GetNamespace("MAPI");
Microsoft.Office.Interop.Outlook.MAPIFolder myInbox = mapiNameSpace.GetDefaultFolder(Microsoft.Office.Interop.Outlook.OlDefaultFolders.olFolderInbox);
String body = ((Microsoft.Office.Interop.Outlook.MailItem)myInbox.Items[1]).Body;
so how to retrieve the current opened email in outlook? , this method work for me but I need to get the index for the current email.
Thanks.
You shouldn’t initialize a new Outlook.Application() instance each time. Most add-in frameworks provide you with an Outlook.Application instance, corresponding to the current Outlook session, typically through a field or property named Application. You are expected to use this for the lifetime of your add-in.
To get the currently-selected item, use:
Outlook.Explorer explorer = this.Application.ActiveExplorer();
Outlook.Selection selection = explorer.Selection;
if (selection.Count > 0) // Check that selection is not empty.
{
object selectedItem = selection[1]; // Index is one-based.
Outlook.MailItem mailItem = selectedItem as Outlook.MailItem;
if (mailItem != null) // Check that selected item is a message.
{
// Process mail item here.
}
}
Note that the above will let you process the first selected item. If you have multiple items selected, you might want to process them in a loop.
On Top add reference to
using Outlook = Microsoft.Office.Interop.Outlook;
Then inside a method;
Outlook._Application oApp = new Outlook.Application();
if (oApp.ActiveExplorer().Selection.Count > 0)
{
Object selObject = oApp.ActiveExplorer().Selection[1];
if (selObject is Outlook.MailItem)
{
Outlook.MailItem mailItem = (selObject as Outlook.MailItem);
String htmlBody = mailItem.HTMLBody;
String Body = mailItem.Body;
}
}
Also you can change the body which will show in outlook before viewing the mail.
I am using below code to check unread mail from the outlook
and everything is working fine for the default inbox folder
Microsoft.Office.Interop.Outlook.Application oApp;
Microsoft.Office.Interop.Outlook._NameSpace oNS;
Microsoft.Office.Interop.Outlook.MAPIFolder oFolder;
Microsoft.Office.Interop.Outlook._Explorer oExp;
oApp = new Microsoft.Office.Interop.Outlook.Application();
oNS = (Microsoft.Office.Interop.Outlook._NameSpace)oApp.GetNamespace("MAPI");
oFolder = oNS.GetDefaultFolder(Microsoft.Office.Interop.Outlook.OlDefaultFolders.olFolderInbox);
oExp = oFolder.GetExplorer(false);
oNS.Logon(Missing.Value, Missing.Value, false, true);
Microsoft.Office.Interop.Outlook.Items items = oFolder.Items;
foreach (Object mail in items)
{
if ((mail as Microsoft.Office.Interop.Outlook.MailItem) != null && (mail as Microsoft.Office.Interop.Outlook.MailItem).UnRead == true)
{
string sasd= (mail as OutLook.MailItem).Subject.ToString();
}
}
But I want to check another folder [which I have created [Name = "Inbox_Personal"]]. How can I do that?
Edit 1
Any suggestion or reference to the tutorial will be appreciated.
I use something similar to the following to access different accounts in Outlook (2007 and greater; before 2007 stores do not exist and you simply need to look at the folders)
Microsoft.Office.Interop.Outlook.Application oApp;
Microsoft.Office.Interop.Outlook.NameSapce oNS = oApp.GetNameSpace(“Mapi”);
foreach(Microsoft.Office.Interop.Outlook.Store oAccounts in oNS.Stores)
{
// get the right account:
Microsoft.Office.Interop.Outlook.Store oDesiredAccount;
foreach(Microsoft.Office.Interop.Outlook.Store oAccount in oAccounts)
{
if(oAccount.DisplayName.ToLower.Equals(“<<Name of Account>>”)
{
oDesiredAccount = oAccount;
}
}
// do stuff with the account
Microsoft.Office.Interop.Outlook.MAPIFolder root = oAccount.GetRootFolder();
// ....
}
var fld = (Outlook.Folder)app.Session.GetFolderFromID("Inbox_Personal", storeID);
I can't remember where to get the store ID from, but should be stored in your session object oder default folder object.
EDIT
I've looked up in a project now: StoreID in GetFolderFromID is optional (Type.Missing).
Default Store ID can be found here:
app.Session.DefaultStore.StoreID
http://msdn.microsoft.com/en-us/library/microsoft.office.interop.outlook._namespace.defaultstore(v=office.12).aspx
I want to get the sender's emailId.
I am able to read all the data of calender by the below code but not the sender's emailId.
using Microsoft.Office.Interop.Outlook;
Microsoft.Office.Interop.Outlook.Application outlook = new Application();
Microsoft.Office.Interop.Outlook.NameSpace oNS = outlook.GetNamespace("MAPI");
oNS.Logon(Missing.Value, Missing.Value, true, true);
string currentUserEmail = oNS.CurrentUser.Address;
string currentUserName = oNS.CurrentUser.Name;
// Get the Calendar folder.
Microsoft.Office.Interop.Outlook.MAPIFolder objMAPIFolder =oNS.GetDefaultFolder(OlDefaultFolders.olFolderCalendar);
//Get the Sent folder
MAPIFolder sentFolder = oNS.GetDefaultFolder(Microsoft.Office.Interop.Outlook.OlDefaultFolders.olFolderSentMail);
Items sentMailItems = sentFolder.Items;
Items items = objMAPIFolder.Items;
foreach (object item in sentMailItems)
{
if (item is MailItem)
{
MailItem oneMail = item as MailItem;
string mailContent = oneMail.HTMLBody;
//item.sender is not available
}
}
foreach (object item in items)
{
if (item is Microsoft.Office.Interop.Outlook.AppointmentItem)
{
Microsoft.Office.Interop.Outlook.AppointmentItem mitem = item as Microsoft.Office.Interop.Outlook.AppointmentItem;
string subject = mitem.Subject;
DateTime start = mitem.Start;
DateTime end = mitem.End;
string body = mitem.Body;
string location = mitem.Location;
string entryId = mitem.EntryID;
//sender email id not available
//string senderEmail = mitem.sender;
}
}
oNS.Logoff();
But in any case whether reading appointments or sent folder emails, I am unable to obtain the sender's email Id.
does anybody have any solution for this problem ?
I think you can get the name from mitem.organizser and then look at the Recipients to find the match..
Then look up the email address via a mapi property PR_SMTP_ADDRESS using a PropertyAccessor.
AppoitnmentItem.GetOrganizer() is not necessarily the sender of the appointment. In a shared calendar (chief/secretary), they might be different.
You can get the sender from an appointment using
AppointmentItem.SendUsingAccount
But from my experience (outlook 2010), that property returns null unless you are logged in as the sender. But it is useful to check if the organizer is different than the sender anyway.