Reputation: 615
When I execute the following code, the error appears the item is moved or deleted
Outlook.Application outlookApp = new Outlook.Application();
Outlook.MailItem mailItem = (Outlook.MailItem)outlookApp.CreateItem(Outlook.OlItemType.olMailItem);
mailItem.Subject = mailSubject;
mailItem.To = "";
mailItem.CC = "";
mailItem.Attachments.Add(totalPath);
mailItem.Body = mailBody;
mailItem.Importance = Outlook.OlImportance.olImportanceNormal;
mailItem.Display(true);
//Mail is send succesfully?
Bool sent = true;
if (!mailItem.Sent)
{
sent = false;
}
The error appears when I check the mailItem.Sent property.
My question is how does .Sent
work? I am trying to display an email message to an end-user and then check if they have sent the email.
Upvotes: 0
Views: 2541
Reputation: 4582
This is how I solved this:
type
TOutlookFolderItemsEvent = procedure(ASender: TObject; const Item: IDispatch) of object;
TOutlookFolderItems = class(TOleServer)
private
FIntf: _Items;
FOnItemAdd: TOutlookFolderItemsEvent;
protected
procedure InitServerData; override;
procedure InvokeEvent(DispID: TDispID; var Params: TVariantArray); override;
public
procedure Disconnect; override;
procedure Connect; override;
procedure ConnectTo(svrIntf: _Items);
property OnItemAdd: TOutlookFolderItemsEvent read FOnItemAdd write FOnItemAdd;
end;
TMyForm = class(TForm)
OutlookApplication1: TOutlookApplication;
private
FMyEntryID: String;
FItems: TOutlookFolderItems;
procedure ItemsItemAdd(ASender: TObject; const Item: IDispatch);
procedure MySendEmail;
end;
procedure TMyForm.MySendEmail;
var
Mi: MailItem;
EntryID: TGUID;
begin
OutlookApplication1.Disconnect;
OutlookApplication1.Connect;
OutlookApplication1.Application.ActiveExplorer.WindowState := olMaximized;
CreateGuid(EntryID);
FMyEntryID:= GUIDToString(EntryID);
Mi.UserProperties.Add('MyEntryID', olText, True, olText).Value := FMyEntryID;
Mi.Save;
Mi.Display(0);
// Add the following code to OutlookApplication's OnItemSend
// to get a more accurate SaveSentMessageFolder
// (as it may change when selecting from different From accounts)
FItems := TOutlookFolderItems.Create(Self);
FItems.ConnectTo(Mi.SaveSentMessageFolder.Items);
FItems.OnItemAdd := ItemsItemAdd;
end;
procedure TMyForm.ItemsItemAdd(ASender: TObject; const Item: IDispatch);
var
S: String;
I: MailItem;
P: UserProperty;
begin
I := Item as MailItem;
P := I.UserProperties.Find('MyEntryID', True);
if (P = nil) or (P.Value <> FMyEntryID) then Exit; // Not the email we're waiting for
// MailItem is known to be sent and in SentFolders here.
// Add here any relevant code.
end;
{ TOutlookFolderItems }
procedure TOutlookFolderItems.Connect;
begin
end;
procedure TOutlookFolderItems.ConnectTo(svrIntf: _Items);
begin
Disconnect;
FIntf := svrIntf;
ConnectEvents(FIntf);
end;
procedure TOutlookFolderItems.Disconnect;
begin
if Fintf <> nil then
begin
DisconnectEvents(FIntf);
FIntf := nil;
end;
end;
procedure TOutlookFolderItems.InitServerData;
const
CServerData: TServerData = (
ClassID: '{00063052-0000-0000-C000-000000000046}';
IntfIID: '{00063041-0000-0000-C000-000000000046}';
EventIID: '{00063077-0000-0000-C000-000000000046}';
LicenseKey: nil;
Version: 500);
begin
ServerData := @CServerData;
end;
procedure TOutlookFolderItems.InvokeEvent(DispID: TDispID; var Params: TVariantArray);
begin
case DispID of
-1: Exit; // DISPID_UNKNOWN
61441: if Assigned(FOnItemAdd) then
FOnItemAdd(Self, Params[0] {const IDispatch});
end;
end;
Upvotes: 0
Reputation: 49405
The mail item may not exist any longer after calling the Display method (passing true). It can be moved to the Outbox folder for further processing by the transport provide.
The Sent property is set once and not what you are looking for. Moreover, checking the Sent property value right after calling the Display method is not a good idea. The mail item can be marked for processing by the transport provider, not being yet sent. Instead, you need to handle the ItemSend event in the code. But checking the Subject line is not a stable solution. At least users may change the pre-set value while the inspector window is displayed.
Before calling the display method of the MailItem class you can add a user property (your own ID) to the MailItem. Then in the ItemSend event handler you may check out the value and delete it if required. Thus, you can be sure that the item is going to be sent (not actually sent).
If you need to be sure that the mail item was sent for sure I'd recommend handling the ItemAdd event of the Items class (see the corresponding property of the Folder class). For example, when an Outlook item is sent, a sent copy is placed to the Sent Items folder in Outlook. You may handle the ItemAdd event for that folder to be sure that the item was sent for sure. Consider adding a user property before displaying the Outlook item and checking it in the ItemAdd event handler to identify the item uniquely.
Be aware, you can specify a custom folder where to place sent mails. The SaveSentMessageFolder property of the MailItem class 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. So, you can move sent mails to your own custom folder.
Upvotes: 1