I am trying to retrieve the appointments for the same day from any given user's name.
So far, I am able to retrieve my own appointments for today with the code below.
else if (UserSelection == "2")
{
//Create the Outlook application
Outlook.Application oApplication = new Outlook.Application();
// Get the NameSpace and Logon information.
Outlook.NameSpace oNameSpace = oApplication.GetNamespace("mapi");
//Log on by using a dialog box to choose the profile.
oNameSpace.Logon(Missing.Value, Missing.Value, true, true);
// Get the Calendar folder.
Outlook.MAPIFolder oCalendar = oNameSpace.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderCalendar);
// Get the appointments (items) collection from the Calendar folder.
Outlook.Items oItems = oCalendar.Items;
oItems.IncludeRecurrences = true;
List<Outlook.AppointmentItem> lst = new List<Outlook.AppointmentItem>();
foreach (Outlook.AppointmentItem item in oItems)
{
if (item.Start.Day == DateTime.Today.Day && item.Start.Month == DateTime.Today.Month && item.Start.Year == DateTime.Today.Year)
{
Console.WriteLine("Organizer: " + item.Organizer);
Console.WriteLine("Start: " + item.Start.ToString());
Console.WriteLine("End: " + item.End.ToString());
Console.WriteLine("Location: " + item.Location);
Console.WriteLine("Recurring: " + item.IsRecurring);
Console.WriteLine("Subject: " + item.Subject);
Console.WriteLine("Attendees: " + item.OptionalAttendees);
Console.WriteLine("");
}
}
//Get the last appointment(item)
//Outlook.AppointmentItem oAppt = (Outlook.AppointmentItem)oItems.GetLast();
//Show the appointment(item) in outlook.
//oAppt.Display(true);
// Done. Log off.
oNameSpace.Logoff();
//Clean up.
oItems = null;
oCalendar = null;
oNameSpace = null;
oApplication = null;
Console.ReadLine();
This works fine. However, the following code below doesnt return the given user "userName"'s appointments.
if (UserSelection == "1")
//try (used for error handling)
{
string userName = Console.ReadLine();
Outlook.Application oApplication;
oApplication = new Outlook.Application();
Outlook.NameSpace oNameSpace = oApplication.GetNamespace("mapi");
oNameSpace.Logon(Missing.Value, Missing.Value, true, true);
Outlook.Recipient oRecip = (Outlook.Recipient)oNameSpace.CreateRecipient(userName);
Outlook.MAPIFolder oCalendar = (Outlook.MAPIFolder)oNameSpace.GetSharedDefaultFolder(oRecip, Outlook.OlDefaultFolders.olFolderCalendar);
// Get the appointments (items) collection from the Calendar folder.
Outlook.Items oItems = oCalendar.Items;
oItems.IncludeRecurrences = true;
List<Outlook.AppointmentItem> lst = new List<Outlook.AppointmentItem>();
foreach (Outlook.AppointmentItem item in oItems)
{
if (item.Start.Day == DateTime.Today.Day && item.Start.Month == DateTime.Today.Month && item.Start.Year == DateTime.Today.Year)
{
Console.WriteLine("Organizer: " + item.Organizer);
Console.WriteLine("Start: " + item.Start.ToString());
Console.WriteLine("End: " + item.End.ToString());
Console.WriteLine("Location: " + item.Location);
Console.WriteLine("Recurring: " + item.IsRecurring);
Console.WriteLine("Subject: " + item.Subject);
Console.WriteLine("Attendees: " + item.OptionalAttendees);
Console.WriteLine("");
}
}
//Show the appointment(item) in outlook.
//oAppt.Display(true);
// Done. Log off.
oNameSpace.Logoff();
// Clean up.
oItems = null;
oCalendar = null;
oNameSpace = null;
oApplication = null;
Console.ReadLine();
The code line producing the error is foreach (Outlook.AppointmentItem item in oItems)
The error returned is "An unhandled exception of type 'System.Runtime.InteropServices.COMException' occurred in mscorlib.dll
Additional information: Exception from HRESULT: 0x8834010F"
Any help to make this work would be greatly appreciated, thanks.
I'd suggest starting from releasing underlying COM objects instantly. Use System.Runtime.InteropServices.Marshal.ReleaseComObject to release an Outlook object when you have finished using it. This is particularly important if your add-in attempts to enumerate more than 256 Outlook items in a collection that is stored on a Microsoft Exchange Server. If you do not release these objects in a timely manner, you can reach the limit imposed by Exchange on the maximum number of items opened at any one time. Then set a variable to Nothing in Visual Basic (null in C#) to release the reference to the object. See Systematically Releasing Objects for more information.
Also I'd suggest using the Find/FindNext or Restrict methods of the Items class. You can read more about them in the following articles:
How To: Retrieve Outlook calendar items using Find and FindNext methods
How To: Use Restrict method in Outlook to get calendar items
Related
Using Visual Studio 2022
outlook 365 with IMAP account
VSTO addin.
c#
Event : newmaileX to capture every incoming email. If certain subject, then I enter text into the body. If body is html, I find the tag and insert after. I have create a button on ribbon to test, and the email subject is altered and new text is in the body.
fine so far.
When the newmailex is fired, it runs my code, but sometimes it does not save the changes, and sometimes it does.
Why ?
if I add "mailItem.Save()" this works, but I then get duplicates of the same email. Sometimes upto 10 duplicates. Is this an IMAP thing ? Below is my code.
void NewMail_Event(String entryIDCollection)
{
Outlook.NameSpace outlookNS = this.Application.GetNamespace("MAPI");
Outlook.MailItem mailItem = null;
try
{
string sTag;
string sBody;
int nPos;
sTag = "<table border=\"1\" cellspacing=\"0\"><tr bgcolor=\"#f5e942\"><td><font color=\"#FF0000\" size=\"4\">";
sTag += "This email originated from outside and was not listed in our safe senders list.<br>";
sTag += "DO NOT action, click on any links or open attachments unless you recognise the sender and know the content is safe.";
sTag += "</font></td></tr></table><br>";
string sSubject = null;
string filter = "[EXTERNAL]";
string[] sEmails = entryIDCollection.Split(',');
foreach (string sEmail in sEmails)
{
mailItem = (Outlook.MailItem)outlookNS.GetItemFromID(sEmail, Type.Missing);
if (mailItem.Subject != null)
{
File.AppendAllText("c:\\1data\\desktop\\vstolog.txt", mailItem.Subject + "\r\n");
if (mailItem.Subject.Length >= 10)
{
if (mailItem.Subject.ToUpper().StartsWith(filter))
{
sSubject = mailItem.Subject.Substring(filter.Length, mailItem.Subject.Length - filter.Length);
mailItem.Subject = sSubject;
sBody = mailItem.HTMLBody;
if (sBody.Contains("<body>") || sBody.Contains("<BODY>"))
{
if (sBody.Contains("<BODY>"))
{
sBody = sBody.Replace("<BODY>", "<body>" + sTag);
}
else
{
sBody = sBody.Replace("<body>", "<body>" + sTag);
}
}
else
{
if (sBody.Contains("<body") || sBody.Contains("<BODY"))
{
if (sBody.Contains("<body"))
{
nPos = sBody.IndexOf("<body", 0);
}
else
{
nPos = sBody.IndexOf("<BODY", 0);
}
nPos = sBody.IndexOf(">", nPos);
sBody = sBody.Insert(nPos + 1, sTag);
}
else
{
sBody = sTag + sBody;
}
}
if (mailItem.BodyFormat == OlBodyFormat.olFormatHTML)
{
mailItem.HTMLBody = sBody;
}
else
{
mailItem.Body = sBody;
}
//mailItem.Close(OlInspectorClose.olSave);
}
}
}
Marshal.ReleaseComObject(mailItem);
mailItem = null;
}
}
catch (Exception eX)
{
MessageBox.Show(eX.Message);
}
finally
{
if (mailItem != null) Marshal.ReleaseComObject(mailItem);
mailItem = null;
if (outlookNS != null) Marshal.ReleaseComObject(outlookNS);
outlookNS = null;
}
}
You can find similar issues described in case of IMAP profiles configured in Outlook, see IMAP Sent Messages are duplicated and unread in Sent Items folder for more information.
I suppose you are handling the NewMailEx event of the Application class, not the NewMail one. There are several aspects in the code:
string[] sEmails = entryIDCollection.Split(',');
The EntryIDsCollection string contains the Entry ID that corresponds to that item. Note that this behavior has changed from earlier versions of the event when the EntryIDCollection contained a list of comma-delimited Entry IDs of all the items received in the Inbox since the last time the event was fired.
However, depending on the setup on the client computer, after a new message arrives in the Inbox, processes like spam filtering and client rules that move the new message from the Inbox to another folder can occur asynchronously. You should not assume that after these events fire, you'll always get a one-item increase in the number of items in the Inbox.
As a possible workaround you may try to handle the ItemAdd event on the target folder instead.
I'm trying to build an Windows Forms application for exporting the folder structure of Outlook including the mail items to the hard drive.
private void ExportItems(MAPIFolder folder)
{
Directory.CreateDirectory(ExportPathField.Text + folder.FullFolderPath);
Items items = folder.Items;
if (items.Count > 0)
{
for (int counter = 1; counter <= items.Count; counter++)
{
object item = items[counter];
switch (Microsoft.VisualBasic.Information.TypeName(item))
{
case "MailItem":
MailItem mailitem = item as MailItem;
mailitem.SaveAs(ExportPathField.Text + folder.FullFolderPath + #"\" + mailitem.ReceivedTime.ToOADate() + ".msg");
System.Runtime.InteropServices.Marshal.ReleaseComObject(mailitem);
mailitem = null;
break;
case "MeetingItem":
MeetingItem meetingitem = item as MeetingItem;
meetingitem.SaveAs(ExportPathField.Text + folder.FullFolderPath + #"\" + meetingitem.ReceivedTime.ToOADate() + ".msg");
System.Runtime.InteropServices.Marshal.ReleaseComObject(meetingitem);
meetingitem = null;
break;
default:
break;
}
System.Runtime.InteropServices.Marshal.ReleaseComObject(item);
item = null;
}
}
for(int counter = 1; counter <= folder.Folders.Count; counter++)
{
ExportItems(folder.Folders[counter]);
}
}
This function works properly as long as the content of the Inbox is less than 1GB. If the Inbox exceeds this size, the following error message appears: 'System.OutOfMemoryException'.
All mail items up to here were correctly exported however.
I'm calling the function like this:
Outlook.Application app = new Outlook.Application();
Outlook.NameSpace outlookNs = app.GetNamespace("MAPI");
Outlook.MAPIFolder emailFolder = outlookNs.Folders[POBoxField.Text];
ExportItems(emailFolder);
I am creating add-in for outlook. In which I have created Drag and Drop user control.
In that when I drag drop mails, Some mail are fetched and provide proper information but in some of the mails in Inbox gives me the Error Like:
I am using following code to get Information of the dragged mails:
private void DragNDropArea_DragDrop(object sender, DragEventArgs e)
{
//wrap standard IDataObject in OutlookDataObject
OutlookDataObject dataObject = new OutlookDataObject(e.Data);
//get the names and data streams of the files dropped
string[] filenames = (string[])dataObject.GetData("FileGroupDescriptorW");
MemoryStream[] filestreams = (MemoryStream[])dataObject.GetData("FileContents");
this.label2.Text += "Files:\n";
for (int fileIndex = 0; fileIndex < filenames.Length; fileIndex++)
{
try
{
//use the fileindex to get the name and data stream
string filename = filenames[fileIndex];
MemoryStream filestream = filestreams[fileIndex];
this.label2.Text += " " + filename + "\n";
Outlook.Application app = new Microsoft.Office.Interop.Outlook.Application();
Outlook._NameSpace nameSpace = app.GetNamespace("MAPI");
nameSpace.Logon(null, null, false, false);
Outlook.Folder folder = (Outlook.Folder)app.Session.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox);
//From this it gives me mentioned error...
Outlook.MailItem msg = (Outlook.MailItem)app.CreateItemFromTemplate(filename, folder);
string sender1 = msg.SenderEmailAddress;
MessageBox.Show("Sender: \n" + msg.Sender.Name + "\n" + msg.Sender.Address);
MessageBox.Show("Message Body: \n" + msg.Body);
MessageBox.Show("Total Attachments: " + msg.Attachments.Count);
for (int i = 1; i <= msg.Attachments.Count; i++)
{
MessageBox.Show("Attachment " + i + " :" + msg.Attachments[i].FileName);
msg.Attachments[i].SaveAsFile("C:\\TestFileSave\\" + msg.Attachments[i].FileName);
}
}
catch (System.Exception ex)
{
MessageBox.Show("Error Occured In getting Mail info..: \n" + ex.ToString());
}
}
}
And when I drag mails from the folders which I have created in the Inbox folder it gives me the same error for every mails which are dragged.
How can I resolve this problem?
The error is STG_E_FILENOTFOUND.
I am not sure how your code could have ever worked: you are passing just the file name (it does not have path) that Outlook would have used to name it (e.g. "My Subject.msg") if you dragged the mesage to Windows Explorer. You need to save the memory stream (filestream in your code above) to an actual file. The file name does not make any difference.
I am working on an add-in for Outlook using C# and I want to be able to check the availability of calendars (mine and others'). I tried using GetSharedDefaultFolder() but it only worked with those who specifically gave me permission, even though all calendars in my company can be viewed by others (we can see the subject and times of appointments). Is there anyway I can get these information? Thanks.
EDIT: I want to emphasize that my problem is with GetSharedDefaultFolder() rather than GetDefaultFolder() (i.e. viewing others' calendars.) Also, I only need to be able to check others' calendars availability, as opposed to having full access to the calendar.
Do not access the folder directly - use Recipient.FreeBusy or AddressEntry.GetFreeBusy
Try This>>
public void GetAllCalendarItems()
{
Microsoft.Office.Interop.Outlook.Application oApp = null;
Microsoft.Office.Interop.Outlook.NameSpace mapiNamespace = null;
Microsoft.Office.Interop.Outlook.MAPIFolder CalendarFolder = null;
Microsoft.Office.Interop.Outlook.Items outlookCalendarItems = null;
oApp = new Microsoft.Office.Interop.Outlook.Application();
mapiNamespace = oApp.GetNamespace("MAPI"); ;
CalendarFolder = mapiNamespace.GetDefaultFolder(Microsoft.Office.Interop.Outlook.OlDefaultFolders.olFolderCalendar); outlookCalendarItems = CalendarFolder.Items;
outlookCalendarItems.IncludeRecurrences = true;
foreach (Microsoft.Office.Interop.Outlook.AppointmentItem item in outlookCalendarItems)
{
if (item.IsRecurring)
{
Microsoft.Office.Interop.Outlook.RecurrencePattern rp = item.GetRecurrencePattern();
DateTime first = new DateTime(2008, 8, 31, item.Start.Hour, item.Start.Minute, 0);
DateTime last = new DateTime(2008, 10, 1);
Microsoft.Office.Interop.Outlook.AppointmentItem recur = null;
for (DateTime cur = first; cur <= last; cur = cur.AddDays(1))
{
try
{
recur = rp.GetOccurrence(cur);
MessageBox.Show(recur.Subject + " -> " + cur.ToLongDateString());
}
catch
{ }
}
}
else
{
MessageBox.Show(item.Subject + " -> " + item.Start.ToLongDateString());
}
}
}
Seems problem similar to this>
http://www.add-in-express.com/forum/read.php?FID=5&TID=8953
So follow discussion on this link. It might helpful to you.
I'm writing a program to read all my outlook emails, eventually the search will be more specific but for now i want to read all the email in my inbox. i have code running that reads what i want up to 169 for some reason...
namespace reademail
{
static class Program
{
public static Microsoft.Office.Interop.Outlook.Application myApp;
public static void Main(string[] args)
{
// myApp = new Microsoft.Office.Interop.Outlook.Application();
//myApp.NewMailEx += new Microsoft.Office.Interop.Outlook.ApplicationEvents_11_NewMailExEventHandler(OutlookNewMailReceived);
ReadMail();
}
static void ReadMail()
{
Microsoft.Office.Interop.Outlook.Application app = null;
Microsoft.Office.Interop.Outlook._NameSpace ns = null;
Microsoft.Office.Interop.Outlook.MailItem item = null;
Microsoft.Office.Interop.Outlook.MAPIFolder inboxFolder = null;
app = new Microsoft.Office.Interop.Outlook.Application();
ns = app.GetNamespace("MAPI");
//ns.Logon(null, null, false, false);
inboxFolder = ns.GetDefaultFolder(Microsoft.Office.Interop.Outlook.OlDefaultFolders.olFolderInbox);
// subFolder = inboxFolder.Folders["Inbox"]; //folder.Folders[1]; also works
Console.WriteLine("Folder Name: {0}, EntryId: {1}", inboxFolder.Name, inboxFolder.EntryID);
Console.WriteLine("Num Items: {0}", inboxFolder.Items.Count.ToString());
//System.IO.StreamWriter strm = new System.IO.StreamWriter("C:/Test/Inbox.txt");
for (int counter = 1; counter <= inboxFolder.Items.Count; counter++)
{
Console.Write(inboxFolder.Items.Count + " " + counter);
item = (Microsoft.Office.Interop.Outlook.MailItem)inboxFolder.Items[counter];
Console.WriteLine("Item: {0}", counter.ToString());
Console.WriteLine("Subject: {0}", item.Subject);
Console.WriteLine("Sent: {0} {1}", item.SentOn.ToLongDateString(), item.SentOn.ToLongTimeString());
Console.WriteLine("Sendername: {0}", item.SenderName);
Console.WriteLine("Body: {0}", item.Body);
//strm.WriteLine(counter.ToString() + "," + item.Subject + "," + item.SentOn.ToShortDateString() + "," + item.SenderName);
}
//strm.Close();
}
}
}
The loop reads up to 169 emails and then crashes, also it starts reading emails at what seems to be an arbitrary date...I'm not sure whats preventing it from reading all emails...
Folder Name: Inbox, EntryId: 000000003527EA8DB4FFC04EB6ABA4DE31CB4BA40100C6D3EBA
DBDB57E438D0B53C5FB515CC50000660627C70000
Num Items: 1048
System.InvalidCastException: Unable to cast COM object of type 'System.__ComObje
ct' to interface type 'Microsoft.Office.Interop.Outlook.MailItem'. This operatio
n failed because the QueryInterface call on the COM component for the interface
with IID '{00063034-0000-0000-C000-000000000046}' failed due to the following er
ror: No such interface supported (Exception from HRESULT: 0x80004002 (E_NOINTERF
ACE)).
at CallSite.Target(Closure , CallSite , Object )
at reademail.Program.ReadMail() in C:\Documents and Settings\DBubel\my docume
nts\visual studio 2010\Projects\reademail\reademail\Program.cs:line 60
Press any key to continue . . .
My guess is that you have items in your inbox that do not apply the Microsoft.Office.Interop.Outlook.MailItem interface and therefore the code crashes while going through the loop and attempting to cast. One possible workaround, if you are using .NET4 since it has support for dynamic, is not to cast the object but rather pass it to a dynamic variable.
dynamic item = inboxFolder.Items[counter];
This worked for me as your code was having problems handling meeting invites in the inbox folder.
Full modified code:
namespace reademail
{
static class Program
{
public static Microsoft.Office.Interop.Outlook.Application myApp;
public static void Main(string[] args)
{
// myApp = new Microsoft.Office.Interop.Outlook.Application();
//myApp.NewMailEx += new Microsoft.Office.Interop.Outlook.ApplicationEvents_11_NewMailExEventHandler(OutlookNewMailReceived);
ReadMail();
}
static void ReadMail()
{
Microsoft.Office.Interop.Outlook.Application app = null;
Microsoft.Office.Interop.Outlook._NameSpace ns = null;
//Microsoft.Office.Interop.Outlook.MailItem item = null;
Microsoft.Office.Interop.Outlook.MAPIFolder inboxFolder = null;
app = new Microsoft.Office.Interop.Outlook.Application();
ns = app.GetNamespace("MAPI");
//ns.Logon(null, null, false, false);
inboxFolder = ns.GetDefaultFolder(Microsoft.Office.Interop.Outlook.OlDefaultFolders.olFolderInbox);
// subFolder = inboxFolder.Folders["Inbox"]; //folder.Folders[1]; also works
Console.WriteLine("Folder Name: {0}, EntryId: {1}", inboxFolder.Name, inboxFolder.EntryID);
Console.WriteLine("Num Items: {0}", inboxFolder.Items.Count.ToString());
//System.IO.StreamWriter strm = new System.IO.StreamWriter("C:/Test/Inbox.txt");
for (int counter = 1; counter <= inboxFolder.Items.Count; counter++)
{
Console.Write(inboxFolder.Items.Count + " " + counter);
dynamic item = inboxFolder.Items[counter];
//item = (Microsoft.Office.Interop.Outlook.MailItem)inboxFolder.Items[counter];
Console.WriteLine("Item: {0}", counter.ToString());
Console.WriteLine("Subject: {0}", item.Subject);
Console.WriteLine("Sent: {0} {1}", item.SentOn.ToLongDateString(), item.SentOn.ToLongTimeString());
Console.WriteLine("Sendername: {0}", item.SenderName);
Console.WriteLine("Body: {0}", item.Body);
//strm.WriteLine(counter.ToString() + "," + item.Subject + "," + item.SentOn.ToShortDateString() + "," + item.SenderName);
}
//strm.Close();
}
}
}
If you want only MailItems then you should check that the item you retrieve is a valid MailItem instead of assuming you have one. It could be CalendarItem, DocumentItem, etc. which varies by olItemType. Your current code explicitly assumes you only have MailItems in your inbox.
item = inboxFolder.Items[counter] as Microsoft.Office.Interop.Outlook.MailItem;
if (item != null)
{
....
}
Your error indicates that you may have a MailItem - but it could be a Mail Delivery Report (Read Receipt, etc.). See this post for reference with the casting error. They suggest leveraging the Outlook Table interface as a workaround and checking the object Class. This may be another option for you.