How to loop through all MailItems of certain Outlook subfolders - c#

I'm working on an Outlook 2007 add-in. I found some code to loop through all the folders but I have not been able to figure out how to loop inside any given folder to examine the MailItem objects (ultimately, I want to save the emails elsewhere and modify the .Subject property).
Here is what I have so far:
private void btnFolderWalk_Click(object sender, EventArgs e)
{
// Retrieve the name of the top-level folder (Inbox) , for
// the purposes of this demonstration.
Outlook.Folder inbox = Application.Session.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox)
as Outlook.Folder; // Cast the MAPI folder returned as an Outlook folder
// Retrieve a reference to the top-level folder.
if (inbox != null)
{
Outlook.Folder parent = inbox.Parent as Outlook.Folder; // the mailbox itself
if (parent != null)
{
RecurseThroughFolders(parent, 0);
}
}
}
private void RecurseThroughFolders(Outlook.Folder theRootFolder, int depth)
{
if (theRootFolder.DefaultItemType != Outlook.OlItemType.olMailItem)
{
return;
}
lbMail.Items.Add(theRootFolder.FolderPath);
foreach (Object item in theRootFolder.Items)
{
if (item.GetType() == typeof(Outlook.MailItem))
{
Outlook.MailItem mi = (Outlook.MailItem)item;
lbMail.Items.Add(mi.Subject);
//-------------------------------------------------------------------------
// mi.Subject is actually a folder name as it's full path.
// How to "open it" to get emails?
// need loop here to modify .Subject of MailItem(s) in certain subfolders
//-------------------------------------------------------------------------
}
}
foreach (Outlook.Folder folder in theRootFolder.Folders)
{
RecurseThroughFolders(folder, depth + 1);
}
}
I'm using a listbox at this stage of working things out and the output currently looks like this below. I want to "process" the email messages of the "Projectnnnnnn" folders.
\\Personal Folders
\\Personal Folders\Deleted Items
\\Personal Folders\Inbox
\\Personal Folders\Inbox\MySubFolder
\\Personal Folders\Inbox\MySubFolder\Project456212
\\Personal Folders\Inbox\MySubFolder\Project318188
\\Personal Folders\Inbox\Outbox
\\Personal Folders\Inbox\SentItems
EDIT:
I fixed this with a slight change in the loop above (i.e. removing the check that the current item is a mailitem):
foreach (Object item in theRootFolder.Items)
{
Outlook.MailItem mi = (Outlook.MailItem)item;
string modifiedSubject = "Modifed Subject: " + mi.Subject;
lbMail.Items.Add(modifiedSubject);
mi.Subject = modifiedSubject;
mi.Save();
// insert call webservice here to upload modified MailItem to new data store
}

While the above code may work it is likely that you will come across an unhandled InvalidCastException as not all items in the root folder will be mail items (e.g. meeting requests).
The following code worked for me:
foreach (object item in items)
{
if (item is Outlook.MailItem)
{
///The rest of your code
}
}

// iterating backwards is needed because of .move below
for (int i = theRootFolder.Items.Count; i > 0; i--)
{
Outlook.MailItem mi = (Outlook.MailItem)theRootFolder.Items[i];
if (mi != null)
{
if (!mi.Subject.StartsWith("M1"))
{
mi.Move(_TRIM_archiveFolder);
}
}
}

Related

Delete Emails from Outlook Folder Using C#

I can't seem to get this working. I am trying to iterate through all the mail items in a folder I created named 'SlaughterPDFs' and delete the emails.
Below is the code I am using. In this code I was just trying to delete the mail items out of the outlook 'Drafts' folder.
public void deleteMails()
{
Application tempApp = new Application();
MAPIFolder tempInbox = default(MAPIFolder);
Items JunkItems = default(Items);
tempInbox = tempApp.GetNamespace("MAPI").
GetDefaultFolder(OlDefaultFolders.olFolderDrafts);
JunkItems = tempInbox.Items;
MailItem DeleteMail = default(MailItem);
foreach (object newMail_loopVariable in JunkItems)
{
DeleteMail = (MailItem)newMail_loopVariable;
DeleteMail.Delete();
}
JunkItems = null;
tempInbox = null;
tempApp = null;
}
Anyone have any idea what I am doing wrong? Or should I be moving these emails to a new folder.
I'm not sure where you are having an issue.
If you replace your for loop with the below while loop it should delete all emails in the folder.
while (tempInbox.Items.Count > 0)
{
DeleteMail = (MailItem)tempInbox.Items.GetFirst();
DeleteMail.Delete();
}
If you are having trouble accessing the folder I would use (assuming SlaughterPDFs is a sub folder of inbox):
tempInbox = tempApp.GetNamespace("MAPI").
GetDefaultFolder(OlDefaultFolders.olFolderInbox);
tempInbox = tempInbox.Folders["SlaughterPDFs"];

Unable to view child elements from OneDrive C# SDK

I am coding against the OneDrive C# SDK and I was shared a folder which contains multiple files. When accessing the shared folder from the onedrive.com, I am able to view the files -- however when trying to check the Item the children count is always at zero. I am assuming this may be some mix up on my end or permissions issue -- but I just wanted to run it past for a sanity check.
Code:
private async Task GetItem(string id = null)
{
List<string> idsToSearch = new List<string>();
var expandValue = this.clientType == ClientType.Consumer
? "thumbnails,children(expand=thumbnails)"
: "thumbnails,children";
try
{
Item folder;
if (id == null)
{
folder = await this.oneDriveClient.Drive.Root.Request()
.Expand(expandValue).GetAsync(); //root
}
else
{
folder = await this.oneDriveClient.Drive.Items[id].Request()
.Expand(expandValue).GetAsync(); //children of root
}
WriteToFile(new List<string>(new[] { #"Folder: " + folder.Name }));
if (folder.Children.Count == 0)
{
WriteToFile(new List<string>(new[] { #"NO Children" }));
}
else
{
foreach (var child in folder.Children)
{
WriteToFile(new List<string>(new[] {
#"Children of " + folder.Name + " : " + child.Name }));
}
foreach (var item in folder.Children)
{
GetItem(item.Id);
idsToSearch.Add(item.Id);
}
}
}
catch (Exception exception)
{
PresentServiceException(exception);
}
}
I also included a snapshot of the Item object when it reaches the Shared folder object:
Update
After looking through the folder object some more I found that there is RemoteItem which is returning the correct number of child counts -- however does not have any meta data to fetch the child elements.
From the comments on the question it was determined that this is a RemoteItem scenario. Remote items are different to local items - while there's some local metadata that's useful for rendering, the actual metadata for the item lives in another user's drive. Therefore, when such an item is encountered it may be necessary (e.g. if you need to enumerate children of a remote folder) for a subsequent request needs to be made directly for the item in question (using the driveId from the remoteItem.parentReference and the id from remoteItem.Id).
Have a look at this documentation for some more information.

Error when opening some Outlook MailItems with GetItemFromID using EntryID from Outlook Spy

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.

Download all email messages via EWS

I currently want to download all email messages (regardless in which folder they're in) to my SQL Server database.
Now while I know how to search for email messages or subscribe to streaming notifications, I've yet to learn on how to synchronize all messages from EWS to my database.
var emailMessages = GetItems<MSEmailMessage>(WellKnownFolderName.MsgFolderRoot);
foreach (var emailMessage in emailMessages)
{
Debug.WriteLine(emailMessage.Subject);
}
private IList<T> GetItems<T>(WellKnownFolderName wellKnownFolderName) where T : Item
{
IList<T> result = new List<T>();
Folder folder = Folder.Bind(_exchangeService, wellKnownFolderName);
if (folder.TotalCount > 0)
{
ItemView view = new ItemView(folder.TotalCount);
FindItemsResults<Item> items = _exchangeService.FindItems(wellKnownFolderName, view);
foreach (var resultItem in items.OfType<T>())
{
result.Add(resultItem);
}
}
return result;
}
This returns 0 email messages (it even threw an exception before checking for the folder.TotalCount before initializing a new ItemView...).
While checking for WellKnownFolderName.Inbox returns the email messages from the inbox, it does not allow me to query for sub folders to synchronize the entirety of the messages.
What am I missing?
You can build up a list of folders to search for mail in. Then iterate through each folder and get all the emails in that folder.
In the code snippet below we can create a folderSearchFilter with FolderTraversal set to Deep which will scan all sub folders of the target folder. We can then apply this filter to the two main well-known folders Inbox and SentItems
Once you have a list of folders to index, then you can use your own code to retrieve all the mails from that folder.
var view = new FolderView(int.MaxValue)
{
PropertySet = new PropertySet(BasePropertySet.FirstClassProperties) { FolderSchema.DisplayName }
};
SearchFilter foldersearchFilter = new SearchFilter.IsGreaterThan(FolderSchema.TotalCount, 0);
view.Traversal = FolderTraversal.Deep;
List<Folder> searchFolders;
try
{
searchFolders = new List<Folder>
{
Folder.Bind(ExchangeService, WellKnownFolderName.Inbox),
Folder.Bind(ExchangeService, WellKnownFolderName.SentItems)
};
}
catch (ServiceResponseException e) {}
searchFolders.AddRange(ExchangeService.FindFolders(WellKnownFolderName.Inbox, foldersearchFilter, view).Folders);
searchFolders.AddRange(ExchangeService.FindFolders(WellKnownFolderName.SentItems, foldersearchFilter, view).Folders);
var results = new List<Item>();
foreach (var searchFolder in searchFolders)
{
//Get all emails in this folder
}
Right, the root folder likely has 0 messages in it. When you do FindItems in a folder, the results don't bubble up from subfolders. You need to iterate over every folder if you want to get to their messages.

Outlook.MailItem - Unable to get To, CC & BCC from Outlook

I am trying to create Outlook Addin using C# by Customizing Application_ItemSend event of the Send button.
I need All the email details before sending an email.
When i run the below code # my home i get proper results by putting some personal email id its working.
But when i run this similar code in office outlook machine i get the names.
As by default outlook's check names code is enabled, this returns first and last name.
I am using Outlook 2010 # both the places. Office outlook is mapped to office active directory. my home outlook is not mapped. Can anyone provide a common solution which will give me all the email address used(to, cc, bcc & from) irrespective of active directory mapped or not.
private void ThisAddIn_Startup(object sender, System.EventArgs e) {
Application.ItemSend += new Outlook.ApplicationEvents_11_ItemSendEventHandler(Application_ItemSend);
}
void Application_ItemSend(object Item, ref bool Cancel) {
Outlook.MailItem mail = Item as Outlook.MailItem;
Outlook.Inspector inspector = Item as Outlook.Inspector;
System.Windows.Forms.MessageBox.Show(mail.CC);
System.Windows.Forms.MessageBox.Show(mail.BCC);
}
Maybe is late, but someone can check this code (it's works for me)
private string[] GetCCBCCFromEmail(Outlook.MailItem email)
{
string[] ccBCC = new string[] { "", "" };//cc y bcc
Outlook.Recipients recipients = email.Recipients;
foreach (Outlook.Recipient item in recipients)
{
switch (item.Type)
{
case (int)Outlook.OlMailRecipientType.olCC:
ccBCC[0] += GetEmail(item.AddressEntry) + ";";
break;
case (int)Outlook.OlMailRecipientType.olBCC:
ccBCC[1] += GetEmail(item.AddressEntry) + ";";
break;
}
}
return ccBCC;
}
private string GetEmail(Outlook.AddressEntry address)
{
string addressStr = "";
if (address.AddressEntryUserType ==
Outlook.OlAddressEntryUserType.
olExchangeUserAddressEntry
|| address.AddressEntryUserType ==
Outlook.OlAddressEntryUserType.
olExchangeRemoteUserAddressEntry)
{
//Use the ExchangeUser object PrimarySMTPAddress
Outlook.ExchangeUser exchUser =
address.GetExchangeUser();
if (exchUser != null)
{
addressStr = exchUser.PrimarySmtpAddress;
}
}
//Get the address from externals
if (address.AddressEntryUserType == Outlook.OlAddressEntryUserType.
olSmtpAddressEntry)
{
addressStr = address.Address;
}
return addressStr;
}
Hope it helps
To/CC/BCC properties (corresponding to PR_DISPLAY_TO/CC/BCC in MAPI) are updated by the store provider when the item is saved (MailItem.Save). You can also access all recipients using the MailItem.Recipeints collection.

Categories

Resources