如何下载邮件,存储并在不同的文件夹中重新创建?

时间:2013-03-12 11:20:00

标签: delphi imap indy

我正在使用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.

1 个答案:

答案 0 :(得分:3)

您正在调用AppendMsg()版本,可让您指定其他电子邮件标头。几乎在我能想到的每种情况下,你都不会想要这样做(我甚至不知道为什么TIdIMAP4会暴露这种功能)。

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

所以,话虽如此,我强烈建议您更改代码,将AAlternativeHeaders的{​​{1}}参数设置为nil(或使用没有AppendMsg()的重载版本完全AppendMsg()参数),以便AAlternativeHeaders发送AppendMsg()在上传之前编码时生成的实际标题:

TIdMessage

或者:

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