发送 TMemoryStream 作为邮件附件

Sending TMemoryStream as mail attachment

我正在使用 TfrxPDFExport 将 FastReport 导出为 PDFFile。我创建了一个函数 returns 我将 PDF 作为 IStream:

Function TPDFReport.GetAsFile (): IStream;
var
  MStream: TMemoryStream;
Begin
  MStream := TMemoryStream.Create;
  try
    With formReport.Create (NIL) do begin
      frxPDFExport.Stream := MStream;
      frxReport.PrepareReport;
      frxReport.Export(frxPDFExport);
    end;
    Result := TStreamAdapter.Create(MStream) as IStream;
  finally

  end;
End;

然后在不同的单元中执行此函数,获取 IStream 并将其加载到 TMemoryStream 中:

  PDFOleStream := TOleStream.Create(PDFReport.GetAsFile ());
  PDFMemoryStream.LoadFromStream(PDFOleStream);

现在我得到了 MemoryStream,但我真的不知道下一步该怎么做。我通过网络搜索并发现使用 Indy 无法将 Stream 作为邮件附件发送。所以我认为,最好将 TMemoryStream 保存为临时文件,然后将其作为附件发送。但是一旦我执行

PDFMemoryStream.SaveToFile('c:\PDFExp.pdf');

我遇到访问冲突。我做错了什么?谢谢

您无需将 TMemoryStream 保存到文件中即可将其附加到电子邮件中。 Indy 的 TIdMessage 组件在您可以附加到它的数据类型方面非常灵活。

例如,Indy 有一个 TIdAttachmentMemory class 你可以使用,例如:

uses
 ..., IdAttachmentMemory;

var
  Attach: TIdAttachmentMemory;
begin
  ...

  Attach := TIdAttachmentMemory.Create(IdMessage1, PDFMemoryStream); // alternatively, use PDFOleStream instead...
  Attach.FileName := 'report.pdf';
  // set other properties as needed...

  // send the email...

  ...
end;

请注意 TIdAttachmentMemory 使用自己的内部 TMemoryStream 并将源 TStream 的数据复制到该内部流中。如果您想避免该副本并按原样发送您自己的 TStream,您可以为此从 TIdAttachment 派生您自己的 class,例如:

uses
  Classes, IdAttachment, IdMessageParts, IdGlobal;

type
  TIdAttachmentStream = class(TIdAttachment)
  protected
    FDataStream: TStream;
    FDataStreamBeforeLoadPosition: TIdStreamSize;
  public
    constructor Create(Collection: TIdMessageParts; Stream: TStream); reintroduce;
    property DataStream: TStream read FDataStream;
    function OpenLoadStream: TStream; override;
    procedure CloseLoadStream; override;
    procedure FinishTempStream; override;
    function PrepareTempStream: TStream; override;
  end;

constructor TIdAttachmentStream.Create(Collection: TIdMessageParts; Stream: TStream);
begin
  inherited Create(Collection);
  FDataStream := Stream;
end;

procedure TIdAttachmentStream.CloseLoadStream;
begin
  DataStream.Position := FDataStreamBeforeLoadPosition;
end;

function TIdAttachmentStream.OpenLoadStream: TStream;
begin
  FDataStreamBeforeLoadPosition := DataStream.Position;
  DataStream.Position := 0;
  Result := DataStream;
end;

procedure TIdAttachmentStream.FinishTempStream;
begin
  DataStream.Position := 0;
end;

function TIdAttachmentStream.PrepareTempStream: TStream;
begin
  DataStream.Size := 0;
  Result := DataStream;
end;
var
  Attach: TIdAttachmentStream;
begin
  ...

  Attach := TIdAttachmentStream.Create(IdMessage1, PDFMemoryStream); // alternatively, use PDFOleStream instead...
  Attach.FileName := 'report.pdf';
  // set other properties as needed...

  // send the email...

  ...
end;

或者,你可以写一个class直接发送原来的IStream,例如:

uses
  Classes, IdAttachment, IdMessageParts, IdGlobal;

type
  TIdAttachmentIStream = class(TIdAttachment)
  protected
    FDataStream: TStream;
    FDataStreamBeforeLoadPosition: TIdStreamSize;
  public
    constructor Create(Collection: TIdMessageParts; Stream: IStream); reintroduce;
    destructor Destroy; override;
    property DataStream: TStream read FDataStream;
    function OpenLoadStream: TStream; override;
    procedure CloseLoadStream; override;
    procedure FinishTempStream; override;
    function PrepareTempStream: TStream; override;
  end;

constructor TIdAttachmentIStream.Create(Collection: TIdMessageParts; Stream: IStream);
begin
  inherited Create(Collection);
  FDataStream := TOleStream.Create(Stream);
end;

destructor TIdAttachmentIStream.Destroy;
begin
  FDataStream.Free;
  inherited;
end;

procedure TIdAttachmentIStream.CloseLoadStream;
begin
  DataStream.Position := FDataStreamBeforeLoadPosition;
end;

function TIdAttachmentIStream.OpenLoadStream: TStream;
begin
  FDataStreamBeforeLoadPosition := DataStream.Position;
  DataStream.Position := 0;
  Result := DataStream;
end;

procedure TIdAttachmentIStream.FinishTempStream;
begin
  DataStream.Position := 0;
end;

function TIdAttachmentIStream.PrepareTempStream: TStream;
begin
  DataStream.Size := 0;
  Result := DataStream;
end;
var
  Attach: TIdAttachmentIStream;
begin
  ...

  Attach := TIdAttachmentIStream.Create(IdMessage1, PDFReport.GetAsFile());
  Attach.FileName := 'report.pdf';
  // set other properties as needed...

  // send the email...

  ...
end;