The TIdMessage.LoadFrom…() methods only work reliably with EML files/streams that were created using one of the TIdMessage.SaveTo…() methods. The reason for this is because the SaveTo…() methods generate emails that are encoded with dot-transparency logic applied (a period at the front of a line is doubled, and a single period on a line by itself terminates the email). The LoadFrom…() methods expect this encoding. This is the encoding format used by the POP3 and SMTP protocols when transmitting emails over a socket, but this encoding is not typically used in EML files/streams.
TIdMessage uses an internal parser/generator (TIdMessageClient) that has no concept of where the data is coming from or going to. It just blindly assumes a socket is being used, and thus applies dot-transparency encoding/decoding logic accordingly. This is a known limitation of TIdMessage/Client that I have discussed many times before in various forums, and it will be addressed in Indy 11. Until then, Indy 10 does provide a workaround to load an EML file/stream that is not encoded with dot-transparency enabled:
var LStream: TIdReadFileExclusiveStream; LMsgClient: TIdMessageClient; LIOHandler: TIdIOHandlerStreamMsg; begin IdMessage1.Clear; LStream := TIdReadFileExclusiveStream.Create('email.eml'); try LMsgClient := TIdMessageClient.Create; try LIOHandler := TIdIOHandlerStreamMsg.Create(nil, LStream); try LIOHandler.FreeStreams := False; LIOHandler.EscapeLines := True; LMsgClient.IOHandler := LIOHandler; try LIOHandler.Open; LMsgClient.ProcessMessage(IdMessage1); finally LMsgClient.IOHandler := nil; end; finally LIOHandler.Free; end; finally LMsgClient.Free; end; finally LStream.Free; end; end;
A similar workaround is available to save an EML file/stream with dot-transparency disabled:
type TIdMessageAccess = class(TIdMessage) end; var LStream: TIdFileCreateStream; LMsgClient: TIdMessageClient; LIOHandler: TIdIOHandlerStreamMsg; begin LStream := TIdFileCreateStream.Create('email.eml'); try LMsgClient := TIdMessageClient.Create; try LIOHandler := TIdIOHandlerStreamMsg.Create(nil, nil, LStream); try LIOHandler.FreeStreams := False; LIOHandler.UnescapeLines := True; LMsgClient.IOHandler := LIOHandler; try TIdMessageAccess(IdMesssage).FSavingToFile := True; try LMsgClient.SendMsg(IdMessage1, False); finally TIdMessageAccess(IdMesssage).FSavingToFile := False; end; finally LMsgClient.IOHandler := nil; end; finally LIOHandler.Free; end; finally LMsgClient.Free; end; finally LStream.Free; end; end;
To make this easier to use, I have now wrapped these workarounds inside of a class helper in a new TIdMessageHelper.pas unit:
type TIdMessageHelper = class helper for TIdMessage public procedure LoadFromFile(const AFileName: string; const AHeadersOnly: Boolean; const AUsesDotTransparency: Boolean); overload; procedure LoadFromStream(AStream: TStream; const AHeadersOnly: Boolean; const AUsesDotTransparency: Boolean); overload; procedure SaveToFile(const AFileName: string; const AHeadersOnly: Boolean; const AUseDotTransparency: Boolean); overload; procedure SaveToStream(AStream: TStream; const AHeadersOnly: Boolean; const AUseDotTransparency: Boolean); overload; end;
This class helper is available in Delphi 2006 and later, and FreePascal.
To disable dot-transparency encoding/decoding logic, simply call TIdMessage.LoadFrom...() or TIdMessage SaveTo...() with the AUsesDotTransparency parameter set to False:
uses ..., IdMessage, IdMessageHelper; IdMessage1.LoadFromFile('email.eml', False, False); IdMessage1.SaveToFile('email.eml', False, False);
If you are using a older version of Delphi or FreePascal that does not support class helpers, or if you are using C++Builder, there are flat wrapper functions provided as well:
procedure TIdMessageHelper_LoadFromFile(AMsg: TIdMessage; const AFileName: string; const AHeadersOnly: Boolean; const AUsesDotTransparency: Boolean); procedure TIdMessageHelper_LoadFromStream(AMsg: TIdMessage; AStream: TStream; const AHeadersOnly: Boolean; const AUsesDotTransparency: Boolean); procedure TIdMessageHelper_SaveToFile(AMsg: TIdMessage; const AFileName: string; const AHeadersOnly: Boolean; const AUseDotTransparency: Boolean); procedure TIdMessageHelper_SaveToStream(AMsg: TIdMessage; AStream: TStream; const AHeadersOnly: Boolean; const AUseDotTransparency: Boolean);
For example:
uses ..., IdMessage, IdMessageHelper; TIdMessageHelper_LoadFromFile(IdMessage1, 'email.eml', False, False); TIdMessageHelper_SaveToFile(IdMessage1, 'email.eml', False, False);