I am in the process of writing an app that will use the Outlook API to copy Calendar Items from a shared calendar to my personal calendar. Here is what I have so far...
using Outlook = Microsoft.Office.Interop.Outlook;
public Outlook.Items GetPublicEntries(string calendar)
{
Microsoft.Office.Interop.Outlook.Items CalendarFolderItems = null;
Outlook.Application oApp;
oApp = new Outlook.Application();
Outlook.NameSpace oNS = oApp.GetNamespace("MAPI");
//oNS.Logon(Missing.Value, Missing.Value, true, true);
Outlook.Recipient oRecip = (Outlook.Recipient)oNS.CreateRecipient(calendar);
Outlook.MAPIFolder usersCalendarFolder = (Outlook.MAPIFolder)oNS.GetSharedDefaultFolder(oRecip, Outlook.OlDefaultFolders.olFolderCalendar);
CalendarFolderItems = usersCalendarFolder.Items;
return CalendarFolderItems;
}
static void Main(string[] args)
{
String[] Cals = { "Appointments","Deadlines","Hearings"};
foreach (string cal in Cals)
{
CalendarItems calobj = new CalendarItems();
Outlook.Items calobjs = calobj.GetPublicEntries(cal);
foreach (Microsoft.Office.Interop.Outlook.AppointmentItem item in calobjs)
{
try
{
Console.WriteLine(item.Subject + " -> " + item.Start.ToLongDateString() + " - " + item.GlobalAppointmentID);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
Console.ReadKey();
}
}
I am able to return a list of items from the three calendars, but now I need to copy them to my personal calendar and that is where I am stuck. Anyone know how to go about doing this?
Thanks!
Tony
Outlook will not let you copy directly to a specified folder (unlike AppointmentItem.Move() which takes a MAPIFolder object as a parameter) - use AppointmentItem.Copy, followed by AppointmentItem.Move:
AppointmentItem copiedItem = Item.Copy();
AppointmentItem newItem = copiedItem.Move(YourDestinationFolder);
newItem.Save();
Beware that Outlook will wipe out the global appointment id when you call Copy() - this means message updates, even if they come directly to your Inbox, will not find the appointment.
You can avoid the intermediary step if you use Redemption (I am its author) - its RDOAppointmentItem (derived from the RDOMail object) lets you pass the target folder when calling CopyTo().
Related
I have the following code to login to an outlook inbox to retrieve emails. If I don't find a certain email that I'm looking for I would like to refresh Inbox folder and try again. Is it as simple as running this function again?
I want the equivalent of clicking on "Send/Receive" button in outlook to fetch any new emails.
private Microsoft.Office.Interop.Outlook.Items loginEmail()
{
//TODO.............................................
//RDOSession session = new RDOSession();
//session.Logon();
//Microsoft.Office.Interop.Outlook.Application myApp = new Microsoft.Office.Interop.Outlook.ApplicationClass();
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 myContacts = mapiNameSpace.GetDefaultFolder(Microsoft.Office.Interop.Outlook.OlDefaultFolders.olFolderContacts);
//login
mapiNameSpace.Logon(null, null, false, false);
mapiNameSpace.Logon("login#mywebsite.com", "pass", false, true);
//Microsoft.Office.Interop.Outlook.Items myItems = myContacts.Items;
// Console.WriteLine("Total : ", myItems.Count);
Microsoft.Office.Interop.Outlook.MAPIFolder myInbox = mapiNameSpace.GetDefaultFolder(Microsoft.Office.Interop.Outlook.OlDefaultFolders.olFolderInbox);
// Console.Write(myInbox.Name);
Microsoft.Office.Interop.Outlook.Items inboxItems = myInbox.Items;
// Console.WriteLine("Total : ", inboxItems.Count);
//Microsoft.Office.Interop.Outlook.Explorer myexp = myInbox.GetExplorer(false);
//mapiNameSpace.Logon("Profile", Missing.Value, false, true);
return inboxItems;
}
Call this function to fetch new mail
mapiNameSpace.SendAndReceive(false);
The NameSpace.SendAndReceive method initiates immediate delivery of all undelivered messages submitted in the current session, and immediate receipt of mail for all accounts in the current profile.
SendAndReceive provides the programmatic equivalent to the Send/Receive All command that is available when you click Tools and then Send/Receive.
If you don't need to synchronize all objects, you can use the SyncObjects collection object to select specific objects. For more information, see NameSpace.SyncObjects.
private void DirectSendAndReceiveCall(object sender, IRibbonControl control, bool pressed)
{
Outlook.NameSpace ns = OutlookApp.GetNamespace("MAPI");
ns.SendAndReceive(false);
if (ns != null) Marshal.ReleaseComObject(ns);
}
See How To: Perform Send/Receive in Outlook programmatically for more information.
I have made an Outlook Add-In (Outlook 2013 and 2016 VSTO Add-In) for business purposes to save the email details to our database. The add-in is launched when a new email is composed, but closes when the email is sent.
The sent date of the email is only added after the email is moved to the Sent mailbox. Is there a way to use my current add-in (or another add-in) can be used to get that sent date after it has been closed without letting the user wait for it to be moved to the sent mailbox?
I know it can easily be done in VBA, but I want to preferably use an Add-in so that it can be easily loaded to all users with exchange server.
Wouldn't that date be today's date/time (Now) or something close to it?
Everything you can do in VBA you can do in a COM addin - subscribe to the Items.ItemAdd event on the Sent Items folder and retrieve the date when the event fires.
Thank you Dmitry for the reply. It set me on the right path. I used my existing VSTO add in to fire when a new item is added to the Sent mailbox. I did not know that when inserting this in the "ThisAddIn_Startup" method re-activates the add-in, which now makes sense.
I followed this example.
Here is my code:
Outlook.NameSpace outlookNameSpace;
Outlook.MAPIFolder Sent_items;
Outlook.Items items;
private void ThisAddIn_Startup(object sender, System.EventArgs e)
{
outlookNameSpace = this.Application.GetNamespace("MAPI");
Sent_items = outlookNameSpace.GetDefaultFolder(Microsoft.Office.Interop.Outlook.OlDefaultFolders.olFolderSentMail);
items = Sent_items.Items;
items.ItemAdd += new Outlook.ItemsEvents_ItemAddEventHandler(items_ItemAdd);
}
void items_ItemAdd(object Item)
{
Outlook.MailItem mail = (Outlook.MailItem)Item;
string strMailItemNumber_filter = mail.UserProperties["MailItemNumber"].Value;
if ((Item != null) && (!string.IsNullOrWhiteSpace(strMailItemNumber_filter)))
{
if (mail.MessageClass == "IPM.Note" &&
mail.UserProperties["MailItemNumber"].Value.ToUpper().Contains(strMailItemNumber_filter.ToUpper())) //Instead of subject use other mail property
{
//Write 'Sent date' to DB
System.Windows.Forms.MessageBox.Show("Sent date is: "+ mail.SentOn.ToString()+ " MailNr = "+strMailItemNumber_filter);
}
}
}
I had to create a new mail user defined property to match the email I sent to find the correct email in the sent mailbox:
private void AddUserProperty(Outlook.MailItem mail)
{
Outlook.UserProperties mailUserProperties = null;
Outlook.UserProperty mailUserProperty = null;
try
{
mailUserProperties = mail.UserProperties;
mailUserProperty = mailUserProperties.Add("MailItemNrProperty", Outlook.OlUserPropertyType.olText, false, 1);
// Where 1 is OlFormatText (introduced in Outlook 2007)
mail.UserProperties["MailItemNumber"].Value = "Any value as string...";
mail.Save();
}
catch (Exception ex)
{
System.Windows.Forms.MessageBox.Show(ex.Message);
}
finally
{
if (mailUserProperty != null) Marshal.ReleaseComObject(mailUserProperty);
if (mailUserProperties != null) Marshal.ReleaseComObject(mailUserProperties);
}
}
So I'm working on an app that will be able to read the outlook calendars for a set of individuals and build an itinerary for them. I've got it pretty much working except that when I scrape a user's calendar, I'm not getting any information on the events they have marked as private.
Let me make it clear that I'm not trying to peer into a user's calendar and read their darkest secret appointment titles, but I would still like to be able to show that this person is unavailable during that time. For example in Outlook proper it just shows as "Private Appointment" - which is exactly what I want to be able to do in my app.
Here's the code I've got for scraping the user's calendar:
private Calendar CreateCalendar(String User_Name, String Initials, DateTime Week)
{
string filter = "[Start] >= '"
+ Week.ToString("g")
+ "' AND [End] <= '"
+ Week.AddDays(7).ToString("g") + "'";
Microsoft.Office.Interop.Outlook.Application App = new Microsoft.Office.Interop.Outlook.Application();
Microsoft.Office.Interop.Outlook.NameSpace mapiNamespace = App.GetNamespace("MAPI");
//Resolve the person whose calendar We're trying to read.
Outlook.Recipient rm = App.Session.CreateRecipient(User_Name);
if (rm.Resolve())
{
try
{
Outlook.Folder calFolder = App.Session.GetSharedDefaultFolder(rm, Outlook.OlDefaultFolders.olFolderCalendar) as Outlook.Folder;
Outlook.Items CalItems = calFolder.Items;
CalItems.IncludeRecurrences = true;
CalItems.Sort("[Start]", Type.Missing);
//Search for Items within the pre-defined time range.
Outlook.Items restrictItems = CalItems.Restrict(filter);
if (restrictItems.Count == 0)
{
Debug.Print("No Items Found");
return new Calendar(User_Name, Initials);
}
else
{
//Create our internal representation of their calendar, for use elsewhere.
Calendar cal = new Calendar(User_Name, Initials);
Outlook.AppointmentItem i = (Outlook.AppointmentItem)restrictItems.GetFirst();
do
{
cal.AddAppointment(i.Subject, i.Start, i.End);
i = restrictItems.GetNext();
} while (i != null);
App = null;
mapiNamespace = null;
return cal;
}
}
catch (Exception ex)
{
App = null;
mapiNamespace = null;
throw new AccessViolationException(User_Name + " was resolved but could not access their calendar. Have they set you up as a delegate?", ex);
}
}
else
throw new AccessViolationException("The name " + User_Name + " was not resolved, make sure their name in the RM List is spelled correctly. If you can enter their name as a recipient in an outlook mail message and it resolves correctly when you click 'Check Names', then it should work!");
}
I'm not sure if private events are contained in the same "Folder" in outlook's data structures, so maybe I'm just not looking in the right spot?
I've been having trouble googling this because "private" is a reserved word in C# that basically hits on every single post with code and a function declaration in it. Hopefully you guys will be more helpful.
Thanks!
I have 2 accounts added to outlook , two seperate pst files. You will get clear idea with image below :
First i prompt user select folders from the outlook which ones to read, image attached for better understanding:
At the end i have the folderpaths in a list, same as in the image.
Now i want to read emails only from these specific paths and send them replies or delete them, so how can i do that?How can i read the folder based on a path n such way i get the account associated with it so i can also send emails using that accounts.
Use the following code to loop through all the folders then match the path with the ones in the list.
CODE:
OutLook.Application oApp = new OutLook.Application();
OutLook.NameSpace oNS = (OutLook.NameSpace)oApp.GetNamespace("MAPI");
oNS.Logon(Missing.Value, Missing.Value, false, true);
foreach (OutLook.MAPIFolder folder in oNS.Folders)
{
string folderName = folder.Name;
GetFolders(folder);
}
public void GetFolders(MAPIFolder folder)
{
if (folder.Folders.Count == 0)
{
string path = folder.FullFolderPath;
if (foldersTocheck.Contains(path))
{
//GET EMAILS.....
foreach (OutLook.MailItem item in folder.Items)
{
Console.WriteLine(item.SenderEmailAddress + " " + item.Subject + "\n" + item.Body);
}
}
}
else
{
foreach (MAPIFolder subFolder in folder.Folders)
{
GetFolders(subFolder);
}
}
}
Is there any way to get all mail from an specific Folder into my Application?
Check this link. Introduction to Outlook Programming will explain things more clearly.
You could loop through the mailitems. Sample code
using System.Runtime.InteropServices;
using OutLook = Microsoft.Office.Interop.Outlook;
using Office = Microsoft.Office.Core;
OutLook.Application oApp;
OutLook._NameSpace oNS;
OutLook.MAPIFolder oFolder;
OutLook._Explorer oExp;
oApp = new OutLook.Application();
oNS = (OutLook._NameSpace)oApp.GetNamespace("MAPI");
oFolder = oNS.GetDefaultFolder(OutLook.OlDefaultFolders.olFolderInbox);
oExp = oFolder.GetExplorer(false);
oNS.Logon(Missing.Value, Missing.Value, false, true);
OutLook.Items items = oFolder.Items;
foreach (OutLook.MailItem mail in items)
{
if (mail.UnRead == true)
{
}
}
Edit:
Reference other folders
oFolder.Folders["Foldername"]
OutLook Code
Common Outlook tasks
Looping through all items in a folder is a terrible idea, especially if you are working against an online Exchange store. Items.Find/FindNext or Items.Restrict is the way to go.
Find/FindNext:
OutLook.Items items = oFolder.Items;
OutLook.MailItem mail = items.Find("[Unread] = true");
while (mail != null)
{
MessageBox.Show(mail.Subject);
mail = items.FindNext();
}
Items.Restrict:
OutLook.Items items = oFolder.Items.Restict("[Unread] = true")
foreach (OutLook.MailItem mail in items)
{
MessageBox.Show(mail.Subject);
}
There's some examples of accessing Outlook folders here, one of which deals specifically with unread mail.
Edit: There's a KB article specifically about accessing folders from C#, Programming samples that can reference items and folders in Outlook by using Visual C# .NET
To open another user's folder, use GetSharedDefaultFolder
foreach (Object Unreadmail in folderItems)
{
if ((Unreadmail as Outlook.MailItem) != null && (Unreadmail as Outlook.MailItem).UnRead == true)
{
//DO Your action Here
}
}
I have experienced "COM_object" exception error with above solutions, More info please refer here