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);
