Copyright © 2024 IMIBO. Privacy Statement
Request # 29
How to spy for incoming messages where Subject contains „xxxxx“ and move them to specific folder?
This example requires you to use a Microsoft Exchange account.
Code snip:
procedure TfrmMain.ProcessConditions; var Subject: string; FolderName: string; Restriction: TRestrictionAnd; MessageCount: ULONG; MsgList: TMsgHeadList; EntryIDMsgList: array of TBytes; iCount: Integer; MAPIProgrs: IMAPIProgress; // Advise (spy) AdviseSink, AdviseSinkReal: IMAPIAdviseSink; ForceTagArray: PSPropTagArray; cValues: ULONG; PropValue: PSPropValue; const BindingProperties: record cValues: ULONG; aulPropTag: array [0 .. 1] of ULONG end = (cValues: 2; aulPropTag: (PR_ENTRYID, PR_SUBJECT);); begin MsgList := nil; EntryIDMsgList := nil; MAPIProgrs := nil; fInboxUID := nil; Subject := Trim(ebSubject.Text); if Subject = '' then raise Exception.Create('Subject field is Empty!'); FolderName := Trim(ebFolderName.Text); if (FolderName = '') then raise Exception.Create('Folder Name field is Empty!'); // "Top Of" folder fTopFolder := GetTopFolder(fMailbox); if not Assigned(fTopFolder) then raise EMAPIError.Create('Cannot get "Top Of" folder'); // Create/Open "Where" Folder hr := fTopFolder.CreateFolder(FOLDER_GENERIC, PChar(@FolderName[1]), nil, @IID_IMAPIFolder, fMAPIUnicode or OPEN_IF_EXISTS, fFolderTo); if failed(hr) then raise EMAPIError.CreateMAPI(fTopFolder, hr); if Assigned(fFolderTo) and (GetPropString(fFolderTo, PR_CONTAINER_CLASS)='') then SetPropString(fFolderTo, PR_CONTAINER_CLASS, 'IPF.Note'); // We have chosen to locate and move those messages if (rgFindAndSpy.ItemIndex = 0) or (rgFindAndSpy.ItemIndex = 2) then begin // Set mandatory properies // PR_ENTRYID - Message Unique ID // PR_SUBJECT - That which we look hr := fContentTable.SetColumns(@BindingProperties, TBL_BATCH); if failed(hr) then raise EMAPIError.CreateMAPI(fContentTable, hr); // Create AND Restriction Restriction := TRestrictionAnd.Create(fContentTable); // We will look for PT_SUBJECT existence with Restriction.Add(resEXIST) as TRestrictionExist do begin PropTag := PR_SUBJECT; end; // Set looking subject with Restriction.Add(resCONTENT) as TRestrictionContent do begin PropTag := PR_SUBJECT; Prefix := rbStart.Checked; FullString := rbIsEqual.Checked; SubString := rbContains.Checked; IgnoreCase := True; Loose := True; Value := Subject; end; // Apply restriction Restriction.Apply; MessageCount := 0; // Get Count of messages hr := fContentTable.GetRowCount(0, MessageCount); if failed(hr) then raise EMAPIError.CreateMAPI(fContentTable, hr); memoLog.lines.Add(IntToStr(MessageCount) + ' messages satisfy the restriction'); // if the number of messages that meet this criterion is greater than zero if MessageCount > 0 then begin // Get restricted message list MsgList := GetMessageList(fContentTable); // Set EntryID List Length SetLength(EntryIDMsgList, Length(MsgList)); for iCount := 0 to Length(MsgList) - 1 do begin SetLength(EntryIDMsgList[iCount], Length(MsgList[iCount].ID)); Move(MsgList[iCount].ID[0], EntryIDMsgList[iCount][0], Length(MsgList[iCount].ID)); memoLog.lines.Add('Message with subject ' + MsgList[iCount].Subject + ' found'); end; MAPIProgrs := TMAPIProgress.Create(Self, ' Copying messages '); Try CopyOrMoveMapiMessages(fInbox, fFolderTo, EntryIDMsgList, True, MAPIProgrs, Self.Handle); memoLog.lines.Add('Messages are moved...'); Finally MAPIProgrs := nil; for iCount := 0 to Length(EntryIDMsgList) - 1 do EntryIDMsgList[iCount] := nil; for iCount := 0 to Length(MsgList) - 1 do MsgList[iCount].ID := nil; EntryIDMsgList := nil; MsgList := nil; End; end; // if MessageCount>0 then end; // if (rgFindAndSpy.ItemIndex=0) or (rgFindAndSpy.ItemIndex=2) then // Advise if (rgFindAndSpy.ItemIndex <> 0) then begin // AdviseSink already exists ? if (fConnectionID <> 0) then Exit; // Create our Advise Sink Object AdviseSink := TStoreAdvise.Create(Self); // Creates an advise sink that wraps the existing advise sink for thread safety. // http://msdn.microsoft.com/en-us/library/office/cc765675.aspx hr := HrThisThreadAdviseSink(AdviseSink, AdviseSinkReal); If failed(hr) Then AdviseSinkReal := AdviseSink; AdviseSink := nil; // Get Inbox Unique ID // We will "spy" only Inbox folder fInboxUID := GetPropBinaryAsBytes(fInbox, PR_ENTRYID); // Register for notification // we will look only for - fnevNewMail -> Registers for notifications about the arrival of new messages. // http://msdn.microsoft.com/en-us/library/office/cc842238.aspx hr := fMailbox.Advise(ULONG(Length(fInboxUID)), PENTRYID(@fInboxUID[0]), fnevNewMail, AdviseSinkReal, fConnectionID); AdviseSinkReal := nil; If failed(hr) Then begin fConnectionID := 0; raise EMAPIError.CreateMAPI(fMailbox, hr); end; (* In order to "wake up" the MAPI Subsystem, and ignore the caching, we will again force RPC traffic, this time a little more intensely. All this is necessary when our MsgStore is on an Exchange Server. When we have a local MsgStore, it will suffice to only take some property through the function HrGetOneProp(lpMapiProp: IMAPIPROP; ulPropTag: ULONG; out lppProp: PSPropValue): HResult that generates the necessary RPC traffic *) ForceTagArray := nil; PropValue := nil; try hr := fInbox.GetPropList(0, ForceTagArray); if failed(hr) then ForceTagArray := nil; hr := fInbox.GetProps(ForceTagArray, 0, cValues, PropValue); if failed(hr) then MAPIFreeBuffer(PropValue); cValues := 0; fContentTable := nil; fContentTable := GetMsgTable(fInbox); fContentTable.GetRowCount(0, MessageCount); // end "wake up" memoLog.lines.Add('Inbox folder is monitored...'); finally if Assigned(ForceTagArray) then MAPIFreeBuffer(ForceTagArray); if Assigned(PropValue) then MAPIFreeBuffer(PropValue); end; end; if (rgFindAndSpy.ItemIndex <> 0) then begin btStart.Tag := -1; btStart.Caption := 'Stop'; gbSubjectConditions.Enabled := False; gbMoveTo.Enabled := False; rgFindAndSpy.Enabled := False; end else begin memoLog.lines.Add(' No more actions...') end; end; function TfrmMain.OnNotify(cNotif: ULONG; Notifications: PNOTIFICATION): ULONG; var iCount: Integer; NOTIFICATION: TNOTIFICATION; begin Result := S_OK; for iCount := 0 to cNotif - 1 do begin NOTIFICATION := PNOTIFICATIONArray(Notifications)[iCount]; case NOTIFICATION.ulEventType of // Registers for notifications about severe errors, such as insufficient memory. fnevCriticalError: begin // Nothing end; // Registers for notifications about the arrival of new messages. fnevNewMail: begin DoNewMail(NOTIFICATION); end; // Registers for notifications about events specific to the particular message store provider. fnevExtended: begin // Nothing end; // Registers for notifications about the creation of a new folder or message. fnevObjectCreated, // Registers for notifications about a folder or message being copied. fnevObjectCopied, // Registers for notifications about a folder or message being deleted. fnevObjectDeleted, // Registers for notifications about a folder or message being modified. fnevObjectModified, // Registers for notifications about a folder or message being moved. fnevObjectMoved, // Registers for notifications about the completion of a search operation. fnevSearchComplete: begin // Nothing end; end; end; end;
Download Request #29 as Compiled Application
Download Project (DELPHI 10.4) ZIP file
Source Code: In package