2

我正在使用 Delphi 2006、Indy 10(版本 4957)、IMAP4。

我想下载一封电子邮件,存储它,几周后我想在不同的文件夹中重新创建它。(这是一种存档和恢复,所以在文件夹之间简单移动不起作用,因为我会删除原始邮件。)我下载邮件,存储它,然后用AppendMsg.

它一直有效,直到我检查目标 Temp2 文件夹,其中大部分消息都包含

这是一条 MIME 格式的多部分消息

unit Mail_Test;

interface

uses
  Windows,
  Messages,
  SysUtils,
  Variants,
  Classes,
  Graphics,
  Controls,
  Forms,
  Dialogs,
  StdCtrls;

type
  TForm1 = class( TForm )
    memLog: TMemo;
    btn1: TButton;
    procedure btn1Click( Sender: TObject );
  private
    procedure Log( LogMsg: string );
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

uses
  IdIMAP4,
  IdMessage,
  IdExplicitTLSClientServerBase,
  IdSSLOpenSSL;

{$R *.dfm}

procedure TForm1.btn1Click( Sender: TObject );
var
  IMAPClient: TIdIMAP4;
  UsersFolders: TStringList;
  OpenSSLHandler: TIdSSLIOHandlerSocketOpenSSL;
  res: Boolean;
  i: integer;
  inbox, currUID: string;
  cntMsg: integer;
  msg, msg2: TIdMessage;
  BodyTexts: TStringList;
  flags: TIdMessageFlagsSet;
  fileName_MailSource, TmpFolder: string;
begin

  IMAPClient := TIdIMAP4.Create( nil );
  try
    OpenSSLHandler := TIdSSLIOHandlerSocketOpenSSL.Create( nil );
    try
      IMAPClient.Host := 'imap.gmail.com';
      IMAPClient.Port := 993;
      IMAPClient.Username := '....@gmail.com';
      IMAPClient.Password := '....';

      if Pos( 'gmail.com', IMAPClient.Host ) > 0 then begin
        OpenSSLHandler.SSLOptions.Method := sslvSSLv3;
        IMAPClient.IOHandler := OpenSSLHandler;
        IMAPClient.UseTLS := utUseImplicitTLS;
      end;

      try
        res := IMAPClient.Connect;
        if not res then begin
          Log( '  Unsuccessful connection.' );
          exit;
        end;

      except
        on e: Exception do begin
          Log( '   Unsuccessful connection.' );
          Log( '  (' + Trim( e.Message ) + ')' );
          exit;
        end;
      end;

      try
        UsersFolders := TStringList.Create;
        try
          res := IMAPClient.ListMailBoxes( UsersFolders );
          if not res then begin
            Log( '  ListMailBoxes error.' );
            exit
          end;
        except
          on e: Exception do begin
            Log( '  ListMailBoxes error.' );
            Log( '  (' + Trim( e.Message ) + ')' );
            exit;
          end;

        end;

        Log( 'User folders: ' + IntToStr( UsersFolders.Count ) );
        for i := 0 to UsersFolders.Count - 1 do begin
          Log( '  [' + inttostr( i + 1 ) + '/' + inttostr( UsersFolders.Count ) + '] Folder: "' + UsersFolders[ i ] + '"' );
        end;

        IMAPClient.RetrieveOnSelect := rsDisabled;
        inbox := 'INBOX';
        Log( 'Opening folder "' + inbox + '"...' );
        res := IMAPClient.SelectMailBox( inbox );
        cntMsg := IMAPClient.MailBox.TotalMsgs;
        Log( 'E-mails to read: ' + IntToStr( cntMsg ) );

    //    res := IMAPClient.RetrieveAllEnvelopes( AMsgList );

        msg := TIdMessage.Create( nil );
        msg2 := TIdMessage.Create( nil );
        BodyTexts := TStringList.Create;
        TmpFolder := 'c:\';
        res := IMAPClient.CreateMailBox( 'Temp2' )
        try

          for I := 0 to cntMsg - 1 do begin

            Log( '  [' + inttostr( i + 1 ) + '/' + inttostr( cntMsg ) + '] E-mail...' );

            IMAPClient.GetUID( i + 1, currUID );

            Log( '(Downloading message...)' );
            IMAPClient.UIDRetrieve( currUID, msg );

            fileName_MailSource := TmpFolder + 'Log_Mail_' + currUID + '.eml';
            msg.SaveToFile( fileName_MailSource, false );

            // In the final version I will delete the original message 
            // so I have to recreate it from the archived file

            msg2.LoadFromFile( fileName_MailSource );

            res := IMAPClient.AppendMsg( 'Temp2', msg2, msg2.Headers, [] );
          end;
        finally
          FreeAndNil( msg );
          FreeAndNil( msg2 );
          FreeAndNil( BodyTexts )
        end;

      finally
        IMAPClient.Disconnect;
      end;
    finally
      OpenSSLHandler.Free;
    end;
  finally
    IMAPClient.Free;
  end;
end;

procedure TForm1.Log( LogMsg: string );
begin
  memLog.Lines.Add( LogMsg );
  Application.ProcessMessages;
end;

end.
4

1 回答 1

3

您正在调用AppendMsg()允许您指定替代电子邮件标题的版本。在我能想到的几乎所有情况下,您永远都不想这样做(我什至不知道为什么 TIdIMAP4 会公开该功能)。

原因是因为将电子邮件AppendMsg()保存TIdMessage到内部TStream,然后将电子邮件正文从内部发送TStream到服务器。如果您指定备用标题,它们将按原样发送,并且与用于创建电子邮件正文的标题数据不匹配。最重要的是,用于分隔电子邮件正文中的 MIME 部分的 MIME 边界与实际发送到服务器的标头中指定的边界不匹配,这将解释您所看到的症状。该边界值是在编码时随机生成的,因此在调用之前TIdMessage它在属性中不可用。TIdMessage.HeadersAppendMsg()

因此,话虽如此,我强烈建议您更改代码以将AAlternativeHeaders参数设置为 nil(或使用根本没有参数AppendMsg()的重载版本),以便发送编码时自身生成的实际标头上传前:AppendMsg()AAlternativeHeadersAppendMsg()TIdMessage

res := IMAPClient.AppendMsg( 'Temp2', msg2, nil, [] );

或者:

res := IMAPClient.AppendMsg( 'Temp2', msg2, [] );
于 2013-03-12T21:17:24.950 回答