Reputation: 119
To move all mails in Outlook I use the following code:
var
App, NS, Inbox, Items, OtherFolder, Item: OleVariant;
i: Integer;
begin
App := CreateOleObject('Outlook.Application');
NS := App.GetNamespace('MAPI');
NS.Logon;
Inbox := NS.GetDefaultFolder(olFolderInbox);
OtherFolder := Inbox.Parent.Folders('Eléments supprimés');
Items := Inbox.Items;
for i := Items.Count downto 1 do
begin
Item := Items.Item(i);
Item.Move(OtherFolder);
end;
end.
Is there a way to move only all read mails to the folder?
Upvotes: 1
Views: 289
Reputation: 3830
The simple answer is to use Item.UnRead
to determine whether the item has been read, however:
MailItem
that supports the UnRead
property. You're using late binding to automate MS Outlook and the code will crash if you try to access UnRead
property on an item that doesn't support it.To demonstrate the options let's first move away from late binding which makes things somewhat complicated and slower. Add unit Outlook2010
to your uses clause. The source code of the unit is located in OCX\Servers subfolder of RAD Studio installation location. The skeleton of code to process mail items using early binding could then look like this:
uses
System.SysUtils, System.Variants, Outlook2010;
var
App: OutlookApplication;
InboxFolder, OtherFolder: Folder;
begin
App := CoOutlookApplication.Create;
App.Session.Logon(EmptyParam, EmptyParam, EmptyParam, EmptyParam);
InboxFolder := App.Session.GetDefaultFolder(olFolderInbox);
OtherFolder := (InboxFolder.Parent as Folder).Folders.Item('Eléments supprimés');
ProcessFolder(InboxFolder, procedure(const Item: MailItem)
begin
Item.Move(OtherFolder);
end);
end.
The naïve implementation of ProcessFolder
would be:
type
TMailItemProc = reference to procedure(const Item: MailItem);
procedure ProcessFolder(const AFolder: Folder; MailItemProc: TMailItemProc);
var
ItemsToProcess: Items;
Item: MailItem;
Index: Integer;
begin
ItemsToProcess := AFolder.Items;
for Index := ItemsToProcess.Count downto 1 do
if Supports(ItemsToProcess.Item(Index), MailItem, Item) and (not Item.UnRead) then
MailItemProc(Item);
end;
This approach sucks as it has to go through each item in the folder and check its UnRead
status. This can cause performance issues when the number of items in the folder is high. But we can do better. Let Outlook do the hard work. And there are multiple ways to do it. The following snippets were inspired by article How to get unread mail in Outlook.
Using Items.Restrict
method:
procedure ProcessFolder(const AFolder: Folder; MailItemProc: TMailItemProc);
var
ItemsToProcess: Items;
Item: MailItem;
Index: Integer;
begin
ItemsToProcess := AFolder.Items.Restrict('[UnRead]=false');
for Index := ItemsToProcess.Count downto 1 do
if Supports(ItemsToProcess.Item(Index), MailItem, Item) then
MailItemProc(Item);
end;
Using Items.Find
and Items.FindNext
methods:
procedure ProcessFolder(const AFolder: Folder; MailItemProc: TMailItemProc);
var
ItemsToProcess: Items;
FoundItem: IDispatch;
Item: MailItem;
begin
ItemsToProcess := AFolder.Items;
FoundItem := ItemsToProcess.Find('[UnRead]=false');
while Assigned(FoundItem) do
begin
if Supports(FoundItem, MailItem, Item) then
MailItemProc(Item);
FoundItem := ItemsToProcess.FindNext;
end;
end;
Using Folders.GetTable
method:
procedure ProcessFolder(const AFolder: Folder; MailItemProc: TMailItemProc);
var
Session: NameSpace;
Table: OutlookTable;
LRow: Row;
FoundItem: IDispatch;
Item: MailItem;
begin
Session := AFolder.Session;
Table := AFolder.GetTable('[UnRead]=false', EmptyParam);
while not Table.EndOfTable do
begin
LRow := Table.GetNextRow;
FoundItem := Session.GetItemFromID(VarToStr(LRow.Item('EntryId')), EmptyParam);
if Supports(FoundItem, MailItem, Item) then
MailItemProc(Item);
end;
end;
Upvotes: 2