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"];
Related
I'm very new to C# development.
I'm trying to check and create a folder/ sub-folder exist in Outlook Mailbox using Exchange Web Service.
Folder Structure
MAIN_folder
Sub Folder-1
Sub Folder-2
Sub Folder-3
Implementation
public void checkFolderExistOrNot( String folder_name)
{
FolderView fv = new FolderView(100);
var findFoldersResults = exchangeService.FindFolders(
WellKnownFolderName.Inbox,
new SearchFilter.SearchFilterCollection(
LogicalOperator.Or,
new SearchFilter.ContainsSubstring(FolderSchema.DisplayName, folder_name)),
fv);
foreach (var folder in findFoldersResults)
{
if (folder is Folder)
{
if (folder.DisplayName == folder_name)
{
archiveFolderID = folder.Id;
}
}
}
//if archive folder not found create and assign the variable to the folderID
if (archiveFolderID == null)
{
Folder folder = new Folder(exchangeService);
folder.DisplayName = folder_name;
folder.Save(WellKnownFolderName.Inbox);
archiveFolderID = folder.Id;
}
}
checkFolderExistOrNot(MAIN_folder)
checkFolderExistOrNot(MAIN_folder.Sub Folder-1)
checkFolderExistOrNot(MAIN_folder.Sub Folder-2)
checkFolderExistOrNot(MAIN_folder.Sub Folder-3)
But this is only creating the Main folder under the inbox. It would be greatly appreciated if someone could help me to identify what is missing in my implementation.
Thanks in Advance.
The only way to tell if a folder exists is to search for it with your search because you don't specify the traversal in the Folderview it will always be shallow. If you specify a deep traversal in
FolderView fv = new FolderView(100);
fv.Traversal = FolderTraversal.Deep;
You should then be able to find the parent folder you want to create a new subfolder on. Your logic should work okay as long as you don't have any name clashes a different folder levels. Otherwise what I do is this Exchange Web Service FolderId for a folder created by user or Get to an Exchange folder by path using EWS
Have you given Microsoft Graph a look?
You can basically use it for anything in Microsoft 365. With you you can also achieve your goal.
You will need to create a GraphServiceClient and with it you can do the following to check if a folder exists:
string user = "emailAddressOfTheUser";
var parentFolderRequest = graphClient.Users[user].MailFolders.Inbox.ChildFolders
.Request()
.Filter($"startsWith(displayName, 'parentFolderName')");
var parentMailFolder = await parentFolderRequest.GetAsync(cancellationToken);
Once you have the parent folder you can get it's ID and once you know that you can search it for child folders:
var parentMailFolderID = parentMailFolder.First().Id;
var childFolderRequest = graphClient.Users[user].MailFolders[parentMailFolderID].ChildFolders
.Request()
.Filter($"startsWith(displayName, 'childFolderName')");
var childMailFolder = await parentFolderRequest.GetAsync(cancellationToken);
If the childMailFolder.Count > 0 then the folder exists, if not you create the child folder:
var childFolder = new MailFolder
{
DisplayName = "childFolderName",
IsHidden = false
};
await graphClient.Users[graphUser.Id]
.MailFolders[parentMailFolderID].ChildFolders
.Request()
.AddAsync(childFolder );
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 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.
My application is supposed to send some emails to some destination. After that operation I would like to automatically move sent mails to specific folder ( based on the document type that is in the mail attachment ). If the folder doesn't exist then the program has to create it and then move the mail to the newly created folder. The issue is that after I create a new folder and succcesfully move the mail to it for the first time, then when i sent anothe mails that are supposed to be moved to the said folder the program doesn't see the folder. In fact the Folders method doesn't return any folders at all.
frankly, im out of ideas whats wrong.
when checking in the debugger it says that parentFolder.Folders "Enumeration yielded no results"
I am not sure if I should do anything more after creating the folder in the method createFolder ( ie. something like, update folders list... )
here is my code:
public void moveEmails(string itemType, Boolean itemSent, Outlook.MailItem objMail)
{
Outlook.MAPIFolder folderParent = objMail.Parent as Outlook.MAPIFolder;
Outlook.Folders folders;
Boolean notMoved = true;
objMail.UserProperties.Add("TransferredBy", Outlook.OlUserPropertyType.olText, true, Outlook.OlUserPropertyType.olText);
objMail.UserProperties["TransferredBy"].Value = System.Security.Principal.WindowsIdentity.GetCurrent().Name;
objMail.Save();
if (folderParent.Name != "Inbox")
folderParent = digForInbox(folderParent);
folders = folderParent.Folders;
if (!itemSent)
itemType = "NOT DELIVERED";
foreach (Outlook.MAPIFolder folder in folders)
{
if (folder.Name == itemType)
{
objMail.Move(folder);
notMoved = false;
}
}
if (notMoved)
createFolder(itemType,objMail, folderParent);
}
public void createFolder(string itemType, Outlook.MailItem objMail, Outlook.MAPIFolder folderParent)
{
Outlook.MAPIFolder folderNew;
folderNew = folderParent.Folders.Add( itemType, Outlook.OlDefaultFolders.olFolderInbox ) as Outlook.MAPIFolder;
objMail.Move(folderNew);
}
private Outlook.MAPIFolder digForInbox(Outlook.MAPIFolder folder)
{
Boolean isNotInbox = true;
while(isNotInbox)
{
if(folder.Name != "Inbox")
{
folder = folder.Parent as Outlook.MAPIFolder;
}
else
{
isNotInbox = false;
}
}
return folder;
}
I have found the answer to my question:
https://social.msdn.microsoft.com/forums/windows/en-us/180c000c-524a-45dd-88fe-88b470be3597/accessing-subfolders-within-shared-mailbox?forum=outlookdev
the issue was similar to the one in the link. I didnt imagine that because my mailboxes are mainly shared ones that would affect it in any other way than performance (due to connecting to the exchange server )
Posting this as an answer
I'd suggest using the SaveSentMessageFolder property of the MailItem class. It allows to set a Folder object that represents the folder in which a copy of the e-mail message will be saved after being sent. Also you may find the following articles helpful:
How To: Change an Outlook e-mail message before sending using C# or VB.NET
How To: Create a new folder in Outlook
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