The task is to move multiple items from one folder to another without using any loops (which basically move 1 item at a time and then repeat the process again and again). In fact, I am talking about C# equivalent of choosing multiple items in folder in Outlook and moving them elsewhere. Is there a way of doing this, or am I stuck with loops anyway here? Thanks in advance.
Yes you can move items without using a loop using EWS API.The do while loop used here is to loop through the pages as the ItemView has a pagesize of 100. You can change this logic as you wish. But I haven't looped through the findResults which is a set of emails.
Here I am assuming that the folder 'Test' is under the root folder. If the folder is a subfolder under Inbox change it to WellKnownFolderName.Inbox
List<SearchFilter> searchFilterCollection = new List<SearchFilter>();
searchFilterCollection.Add(new SearchFilter.IsEqualTo(EmailMessageSchema.IsRead, false));
SearchFilter searchFilter = new SearchFilter.SearchFilterCollection(LogicalOperator.And, searchFilterCollection);
ItemView view = new ItemView(100);
view.PropertySet = new PropertySet(BasePropertySet.IdOnly, ItemSchema.Subject);
view.Traversal = ItemTraversal.Shallow;
FindItemsResults<Item> findResults;
do
{
findResults = service.FindItems(new FolderId(WellKnownFolderName.Inbox, new Mailbox(user)), searchFilter, view);
var itemIds = from item in findResults
select item.Id;
service.MoveItems(itemIds,
(Folder.Bind(service, WellKnownFolderName.MsgFolderRoot)
.FindFolders(new SearchFilter.IsEqualTo(FolderSchema.DisplayName, "Test"), new FolderView(1))
.FirstOrDefault(x => x.DisplayName == "Test")).Id);
view.Offset = Convert.ToInt32(findResults.NextPageOffset);
} while (findResults.MoreAvailable);
While it would occasionally be nice to be able to move a bunch of messages at once, the simple answer is you can't.
The EWS API does not provide a method for moving a list of messages all at once, only a method for moving an individual message to a different folder. As such you are stuck with looping through your messages and moving them individually.
Which, incidentally, is how Outlook seems to do it... so in that regard you're at least fulfilling that requirement :)
I think you need a loop like foreach, while to iterate through the collection of your selected mail items.
The Outlook object model doesn't provide any method for moving multiple items at once. Use the Move method of the MailItem class for moving items in the loop.
On the Extended MAPI level (C++ or Delphi only), IMAPIFolder::CopyMessages(MESSAGE_MOVE ) takes a list of entry ids and thus allows to move or copy multiple messages in a single call.
Outlook Object Model however only allows to copy or move one message at a time. If using Redemption (I am its author - any language) is an option, it exposes RDOFolder.Items.MoveMultiple / CopyMultiple methods that take a list of ";" or CR/LF separated entry ids or an array of entry id or items.
Related
I am writing a C# application where I want to loop through the 500 most recent emails in a given folder. The reason is because getting all the emails takes a long time using the below lines:
MAPIFolder folder = outlookApp.GetNamespace("MAPI").GetDefaultFolder(OlDefaultFolders.olFolderInbox);
List<MailItem> items = folder.Items.OfType<MailItem>().ToList();
However, I know that what I am searching for each time is always going to be a recent email, so there's no need to get an entire year's worth of emails each time (over 8000, and I get less emails than the average employee at my job).
So, is there a way to only retrieve a certain amount of emails from a folder with Microsoft.Office.Interop.Outlook? Thanks in advance.
Iterating over all items in the folder is not really a good idea:
List<MailItem> items = folder.Items.OfType<MailItem>().ToList();
Instead, you need to use the Find/FindNext or Restrict methods of the Items class. They allow getting only items that correspond to your conditions. Read more about these methods in the following articles:
How To: Use Find and FindNext methods to retrieve Outlook mail items from a folder (C#, VB.NET)
How To: Use Restrict method to retrieve Outlook mail items from a folder
Instead of getting recent 500 emails you may retrieve emails for a day, few days, week and etc. So, you can process items in bunch. For example:
criteria = "[ReceivedTime] > '" _
& Format$("6/12/20 3:30PM","General Date") & "'"
You may find the Filtering Items Using a Date-time Comparison article helpful.
I am writing some scripting processes in C# to update a SharePoint Online list with data from a system database (there's a whole heap in between, but that's irrelevant).
The issue I am having is that when I add new records, they are being added without validation rules being applied by SharePoint e.g. you can add an entry that has a missing mandatory field which then shows up OnLine with a (!) Required placeholder.
In the example below, lets assume the list has these (text) fields all of which are tagged as mandatory.
Title
Address
Rating (Just a simple 3 letter code)
And then the script has the following to add a new item ..
ClientContext clientContext = new ClientContext("my sponline site url");
List myList = client.Web.Lists.GetByTitle("my list");
ListItemCreationInformation newRecContext = new ListItemCreationInformation();
ListItem newItem = myList.AddItem(newRecContext);
newRecord.Add("Title", "My Name");
newRecord.Add("Address", "My Address");
/* Removed for Testing validation*/
//newRecord.Add("Rating", "AAA");
newItem.Update();
clientContext.Load(newItem);
clientContext.ExecuteQuery();
If the "Rating" field is populated then all good, item gets added... but if the line is removed should it not raise an exception to say that a mandatory field (Rating) is not provided.
Why is the CSOM not checking for validity?
Edit: I am using the Microsoft.SharePointOnline.CSOM (v16.1.7115.1200) package from NuGet
None of the code object models apply those rules. They're strictly for the UI controls shown to users. This is by design.
Well, this is how Sharepoint works. If you add list items programmatically - by default it does not validate required fields. You should just keep it in mind (on other hand - you have more freedom). You can add your custom validation in place where you save item. Other way is to create list item event receiver for your list and add your validation in the ItemUpdating method.
I want to be able to apply a SearchFilter based off the Item Id when I find all items in a selection of folders.
I can easily get all items and then using linq apply a where clause like
(w => !uniqueItemIdList.Contains(w.Id.UniqueId))
But the issue is this would be after it's pulled 1000's of mail items instead of during the original find of the items.
My goal is to pull all emails copy them to a db then afterwards to only pull emails that I haven't already copied by excluding emails with matching unique ids.
So far everything indicates that this isn't possible and that I could only search on individual fields like FolderId = "..." or subject that contains "...", with no mention of a list or exclusion.
Any help would be much appreciated.
ItemId isn't a searchable property so what you trying to do with a SearchFilter won't work. SyncFolderItems https://msdn.microsoft.com/en-us/library/office/aa563967(v=exchg.150).aspx does allow an exclusion list based on ItemId (but I would think for a large number of items this wont scale) an easier solution would be just use a SearchFilter based on Item Creation Date.
I am having an issue where I am trying to find at least one contact inside any of the outlook folders. I have a recursive function that iterates thru the items inside a folder and if the item is of type contact then we add it to a list. However, this code runs extremely slow when folders have a large number of records say 4000 items.
Is there any way just to get contacts or is there a way to make this code more efficient?
foreach (var item in folderBase.Items)
{
if (returnFirst && result.Count > 0)
break;
if ((item is Outlook.ContactItem))
{
result.Add((Outlook.ContactItem)item);
}
}
Firstly, storing 4000 live Outlook objects in a list is a bad idea: you will run out of RPC channels in case of online Exchange store at item 255. Store the entry ids and use them to call Namespace.GetItemFromID() when you actuqlly need it; then release it as soon as you are done.
Secondly, use MAPIFolder.GetTable - it will let you retrieve values from multiple items without actually opening them; perfect in your case. Try something like the following (VB script):
set Folder = Application.ActiveExplorer.CurrentFolder
set Table = Folder.GetTable("[MessageClass] = 'IPM.Contact' ")
Table.Columns.Add("EntryID")
while not Table.EndOfTable
set Row = Table.GetNextRow()
vEntryId = Row.Item(1)
Debug.Print vEntryId
wend
You need to use the Find/FindNext or Restrict methods of the Items class instead.
Read more about these methods and see the sample code in the following articles:
How To: Use Restrict method in Outlook to get calendar items
How To: Retrieve Outlook calendar items using Find and FindNext methods
You can use the MessageClass property of Outlook items to get the contact items only.
For example, how do I know how many email items in inbox folder?
FindItemsResults findResults = service.FindItems(
WellKnownFolderName.Inbox,
new ItemView(10,0));
The above code only lists first 10 items, how to know how many items in inbox folder, so that I can calculate how many pages with 10 items in one page.
Maybe Folder.TotalCount Property?