MailItem.Sent 在检查用户是否已发送邮件时出现错误 'Item is moved or deleted'

MailItem.Sent gives error 'Item is moved or deleted' when checking if user has sent mail

当我执行以下代码时,出现错误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;
}

检查mailItem.Sent属性时出现错误。

我的问题是 .Sent 是如何工作的?我正在尝试向最终用户显示一封电子邮件,然后检查他们是否已发送电子邮件。

邮件项在调用 Display 方法(传递 true)后可能不再存在。可以将其移动到发件箱文件夹以供传输提供商进一步处理。

代码中的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事件。但是检查主题行并不是一个稳定的解决方案。至少用户可以在显示检查器 window 时更改预设值。

在调用MailItem 的显示方法之前class 您可以向MailItem 添加一个用户属性(您自己的ID)。然后在 ItemSend 事件处理程序中,您可以检查该值并在需要时将其删除。因此,您可以确定该项目将被发送(而不是实际发送)。

如果您需要确定邮件是否已发送,我建议您处理邮件 class 的 ItemAdd 事件(请参阅相应的 属性文件夹 class)。例如,发送 Outlook 项目时,发送的副本将放置在 Outlook 中的“已发送邮件”文件夹中。您可以处理该文件夹的 ItemAdd 事件,以确保该项目确实已发送。考虑在显示 Outlook 项目之前添加用户 属性 并在 ItemAdd 事件处理程序中检查它以唯一标识该项目。

请注意,您可以指定一个自定义文件夹来放置已发送的邮件。 MailItem class 的 SaveSentMessageFolder 属性 允许设置一个 Folder 对象,该对象表示发送后将保存电子邮件副本的文件夹。因此,您可以将已发送的邮件移动到您自己的自定义文件夹中。

我是这样解决的:

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;