Hallo,
ich hatte die Aufgabe, von einem Delphi - Programm aus E-Mails über einen Exchange - Server in einem Active Directory - Netz zu empfangen und zu versenden.
Da ich an diesem Problem wochenlang gewerkelt und dabei auch einiges aus dem WWW benutzt habe, möchte ich meine gesammelten Erfahrungen rein informativ kundtun:
Achtung, ich hab den Code aus dem Live - Projekt extrahiert, bitte nur als Prinzipskizze betrachten und nicht steinigen, wenn mal ein Try /Except nicht richtig "aufgeht"
1. E-Mail - Empfang
Das Zauberwort heißt IMAP und mit der idIMAP - Komponente klappt das Abholen der Mails recht einfach:
[highlight=DELPHI]
function Tdm_EDIControl.PruefeMails: Boolean;
var msgID : Integer;
msgs : TIdMessageCollection;
msg:TIDMessage;
begin
result:=false;
try
try
if IDimap.Connected then
IDimap.CloseMailBox;
// set login informations
idimap.Username:={user_mailkonto};
idimap.Password:={};
idimap.Port:={143};
idimap.Host:={exchange server};
if not idimap.Connect then begin
{Fehler}
exit;
end;
except
{Fehler}
exit;
end;
// select Mailboxfolder
if not idimap.SelectMailBox('INBOX') then begin
{Fehler}
exit;
end;
try
msgs:=TIDMessageCollection.Create(TIdmessageItem);
try
// get headers
idimap.retrieveAllheaders(msgs);
// for each message
for msgID:=0 to msgs.Count - 1 do begin
msg:=TIDMessage.Create(self);
try
// get whole message
idimap.Retrieve(msgid, msg);
//showMessage(msg.Subject);
//showMessage(msg.From.Address);
msg.MessageParts.CountParts;
// save all attachments, (generate unique fName before)
for i:=0 to msg.MessageParts.count - 1 do
if msg.MessageParts[i] is TIDAttachment then
TIDAttachment(msg.MessageParts[i]).savetofile({fName});
finally
msg.Free;
end;
end;
finally
msgs.Free;
end;
result:=true;
except
{Fehler}
end;
end;
[/highlight]
2. Versand über den Exchange - Server
Hier kommt das SMTP - Protokoll zum Einsatz, in der geschilderten Umgebung in Kombination mit OpenSSL.
Vorlage war das hier, da ich wußte, dass nur NTLM - Authentifizierung zum Einsatz kommt habe ich auch nur diese eingebunden.
[highlight=delphi]procedure TForm2.SendNow2;
var MsgSend:TIdMessage;
SMTP:TIdSMTP;
SASLNTLM : TIdSASLNTLM;
UserPassProv:TIdUserPassProvider;
textPart:TIdText;
Logfile:TIdLogFile;
sentOK:Boolean;
begin
logfile:=NIL;
MsgSend:=TIdMessage.Create; //create the message
with MsgSend do
begin
Body.Text:='Test';
From.Text := '[email protected]';
Recipients.EMailAddresses := '[email protected]';
Subject := 'Test'; // set the subject
Priority := mpNormal; // set the priority (note that you could add to
// Destination to support different priorities)
end;
try
SMTP:=TIdSMTP.Create; //create the SMTP object
try
//*************
with TIdSSLContext.Create do
Free; //try to create a SSL context (immediately disposes of it)
//*************
//- need OpenSSL to support this, if it fails, it will fall into the exception
smtp.IOHandler := TIdSSLIOHandlerSocketOpenSSL.Create(smtp); //if we succeed, then we can create a SSL socket handler and assign it to the IOHandler
smtp.UseTLS := utUseExplicitTLS; //and we can mark the we can use tls
except
smtp.IOHandler := TIdIOHandler.MakeDefaultIOHandler(smtp); //the SSL failed to create, so make the default IO handler
smtp.UseTLS := utNoTLSSupport; //mark that we have no TLS support
end;
smtp.ManagedIOHandler := True; //either way, we now have a ManagedIOHandler
if cb_dbg.Checked then //if we marked that we wanted debugging, we need to do some setup
begin
logFile := TidLogFile.Create(nil); //create the log file
logFile.FileName:='Log.txt'; //set the default log file name - NOTE: you could get fancy with this, but I normally don't use it
logFile.Active:=true; //activate the log file (creates the file and intializes everything)
smtp.IOHandler.Intercept := logFile; //set the logFile to the intercept of the IOHandler to capture the events
smtp.IOHandler.OnStatus := smtp.OnStatus; // - not sure why we do this, copied code -
end;
try
SMTP.AuthType := satSASL;
SMTP.UserName := le_user.text; // User Input
SMTP.Password := le_password.Text; // User Input
userPassProv:=TIdUserPassProvider.Create; //create the user/pass provider - this handles the login functions for SASL
userPassProv.UserName:=SMTP.UserName; // setup user name
userPassProv.Password:=SMTP.Password; // & password
if SMTP.AuthType=satSASL then //if we are going to use SASL - basically, SASL just encrypts the login, everything else is still clear text
begin
SASLNTLM := TIdSASLNTLM.Create;
SASLNTLM.UserPassProvider:=userPassProv;
SMTP.SASLMechanisms.Clear;
SMTP.SASLMechanisms.Add.SASL:=SASLNTLM;
end;
{General setup}
SMTP.Host := le_server.text; //setup the server name
SMTP.Port := StrToInt(le_smtpport.Text); //setup the server port
{now we send the message}
SMTP.ConnectTimeout := 1000;
SMTP.Connect;
if not SMTP.Authenticate then //authenticate with the server - this will automatically use SASL if configured and supported
begin
MessageDlg('An error occurred attempting to send your e-mail. The error was : Unable to authenticate.', mtError, [mbOK], 0);
exit;
end;
try
try
ShowMessage('Before Send');
SMTP.Send(MsgSend); //send the message
ShowMessage('After Send');
SentOk:=true; //indicate success
finally
SMTP.Disconnect; //disconnect from the server
end;
except on E :Exception do //if we had a failure, say so
begin
MessageDlg('An error occurred attempting to send your e-mail. The error was : '+E.Message, mtError, [mbOK], 0);
SentOk:=false; //set failure
end;
end;
finally
SMTP.Free; //free the memory
end;
finally
if logFile<>nil then //if we had a log file, free that
logFile.Free;
MsgSend.Free; //free the message
end;
end;[/highlight]
Dazu müssen dann noch unbedingt die Open - SSL - DLLs
libeay32.dll
ssleay32.dll
ins Programmverzeichnis kopiert werden (muss man erstmal mit wissen, denn vom OpenSSL habe ich leider keine zielführenden Fehlermeldungen zurück erhalten).
OpenSSL ist übrigens -wie Indy- ein Wahnsinns - Projekt, Hut ab vor den Programmierern!
Weitere Hinweise siehe auch (böser Crosspost ;-) ) http://www.delphi-forum.de/viewtopic.php?t=102987
Ach ja, die notwendigen einzubindenen Units (Uses ....) habe ich per Suchfunktion aus dem Indy- Ordner herausgesucht. In der Regel heissen die Units wie die verwendeten Klassen, nur die SSL - Klassen weichen manchmal etwas davon ab.
Dann war das Ganze im Netz noch so konfiguriert, dass auch nur der im AD angemeldete Nutzer vom jeweiligen Client E-Mails mit SEINER (und keiner anderen) Adresse versenden darf. Das mußten wir dann als Randbedingung mit beachten.
Ja, so ein paar Zeilen, aber eine ewig lange Geschichte drumherum.
Viele Grüße
Tino
ich hatte die Aufgabe, von einem Delphi - Programm aus E-Mails über einen Exchange - Server in einem Active Directory - Netz zu empfangen und zu versenden.
Da ich an diesem Problem wochenlang gewerkelt und dabei auch einiges aus dem WWW benutzt habe, möchte ich meine gesammelten Erfahrungen rein informativ kundtun:
Achtung, ich hab den Code aus dem Live - Projekt extrahiert, bitte nur als Prinzipskizze betrachten und nicht steinigen, wenn mal ein Try /Except nicht richtig "aufgeht"
1. E-Mail - Empfang
Das Zauberwort heißt IMAP und mit der idIMAP - Komponente klappt das Abholen der Mails recht einfach:
[highlight=DELPHI]
function Tdm_EDIControl.PruefeMails: Boolean;
var msgID : Integer;
msgs : TIdMessageCollection;
msg:TIDMessage;
begin
result:=false;
try
try
if IDimap.Connected then
IDimap.CloseMailBox;
// set login informations
idimap.Username:={user_mailkonto};
idimap.Password:={};
idimap.Port:={143};
idimap.Host:={exchange server};
if not idimap.Connect then begin
{Fehler}
exit;
end;
except
{Fehler}
exit;
end;
// select Mailboxfolder
if not idimap.SelectMailBox('INBOX') then begin
{Fehler}
exit;
end;
try
msgs:=TIDMessageCollection.Create(TIdmessageItem);
try
// get headers
idimap.retrieveAllheaders(msgs);
// for each message
for msgID:=0 to msgs.Count - 1 do begin
msg:=TIDMessage.Create(self);
try
// get whole message
idimap.Retrieve(msgid, msg);
//showMessage(msg.Subject);
//showMessage(msg.From.Address);
msg.MessageParts.CountParts;
// save all attachments, (generate unique fName before)
for i:=0 to msg.MessageParts.count - 1 do
if msg.MessageParts[i] is TIDAttachment then
TIDAttachment(msg.MessageParts[i]).savetofile({fName});
finally
msg.Free;
end;
end;
finally
msgs.Free;
end;
result:=true;
except
{Fehler}
end;
end;
[/highlight]
2. Versand über den Exchange - Server
Hier kommt das SMTP - Protokoll zum Einsatz, in der geschilderten Umgebung in Kombination mit OpenSSL.
Vorlage war das hier, da ich wußte, dass nur NTLM - Authentifizierung zum Einsatz kommt habe ich auch nur diese eingebunden.
[highlight=delphi]procedure TForm2.SendNow2;
var MsgSend:TIdMessage;
SMTP:TIdSMTP;
SASLNTLM : TIdSASLNTLM;
UserPassProv:TIdUserPassProvider;
textPart:TIdText;
Logfile:TIdLogFile;
sentOK:Boolean;
begin
logfile:=NIL;
MsgSend:=TIdMessage.Create; //create the message
with MsgSend do
begin
Body.Text:='Test';
From.Text := '[email protected]';
Recipients.EMailAddresses := '[email protected]';
Subject := 'Test'; // set the subject
Priority := mpNormal; // set the priority (note that you could add to
// Destination to support different priorities)
end;
try
SMTP:=TIdSMTP.Create; //create the SMTP object
try
//*************
with TIdSSLContext.Create do
Free; //try to create a SSL context (immediately disposes of it)
//*************
//- need OpenSSL to support this, if it fails, it will fall into the exception
smtp.IOHandler := TIdSSLIOHandlerSocketOpenSSL.Create(smtp); //if we succeed, then we can create a SSL socket handler and assign it to the IOHandler
smtp.UseTLS := utUseExplicitTLS; //and we can mark the we can use tls
except
smtp.IOHandler := TIdIOHandler.MakeDefaultIOHandler(smtp); //the SSL failed to create, so make the default IO handler
smtp.UseTLS := utNoTLSSupport; //mark that we have no TLS support
end;
smtp.ManagedIOHandler := True; //either way, we now have a ManagedIOHandler
if cb_dbg.Checked then //if we marked that we wanted debugging, we need to do some setup
begin
logFile := TidLogFile.Create(nil); //create the log file
logFile.FileName:='Log.txt'; //set the default log file name - NOTE: you could get fancy with this, but I normally don't use it
logFile.Active:=true; //activate the log file (creates the file and intializes everything)
smtp.IOHandler.Intercept := logFile; //set the logFile to the intercept of the IOHandler to capture the events
smtp.IOHandler.OnStatus := smtp.OnStatus; // - not sure why we do this, copied code -
end;
try
SMTP.AuthType := satSASL;
SMTP.UserName := le_user.text; // User Input
SMTP.Password := le_password.Text; // User Input
userPassProv:=TIdUserPassProvider.Create; //create the user/pass provider - this handles the login functions for SASL
userPassProv.UserName:=SMTP.UserName; // setup user name
userPassProv.Password:=SMTP.Password; // & password
if SMTP.AuthType=satSASL then //if we are going to use SASL - basically, SASL just encrypts the login, everything else is still clear text
begin
SASLNTLM := TIdSASLNTLM.Create;
SASLNTLM.UserPassProvider:=userPassProv;
SMTP.SASLMechanisms.Clear;
SMTP.SASLMechanisms.Add.SASL:=SASLNTLM;
end;
{General setup}
SMTP.Host := le_server.text; //setup the server name
SMTP.Port := StrToInt(le_smtpport.Text); //setup the server port
{now we send the message}
SMTP.ConnectTimeout := 1000;
SMTP.Connect;
if not SMTP.Authenticate then //authenticate with the server - this will automatically use SASL if configured and supported
begin
MessageDlg('An error occurred attempting to send your e-mail. The error was : Unable to authenticate.', mtError, [mbOK], 0);
exit;
end;
try
try
ShowMessage('Before Send');
SMTP.Send(MsgSend); //send the message
ShowMessage('After Send');
SentOk:=true; //indicate success
finally
SMTP.Disconnect; //disconnect from the server
end;
except on E :Exception do //if we had a failure, say so
begin
MessageDlg('An error occurred attempting to send your e-mail. The error was : '+E.Message, mtError, [mbOK], 0);
SentOk:=false; //set failure
end;
end;
finally
SMTP.Free; //free the memory
end;
finally
if logFile<>nil then //if we had a log file, free that
logFile.Free;
MsgSend.Free; //free the message
end;
end;[/highlight]
Dazu müssen dann noch unbedingt die Open - SSL - DLLs
libeay32.dll
ssleay32.dll
ins Programmverzeichnis kopiert werden (muss man erstmal mit wissen, denn vom OpenSSL habe ich leider keine zielführenden Fehlermeldungen zurück erhalten).
OpenSSL ist übrigens -wie Indy- ein Wahnsinns - Projekt, Hut ab vor den Programmierern!
Weitere Hinweise siehe auch (böser Crosspost ;-) ) http://www.delphi-forum.de/viewtopic.php?t=102987
Ach ja, die notwendigen einzubindenen Units (Uses ....) habe ich per Suchfunktion aus dem Indy- Ordner herausgesucht. In der Regel heissen die Units wie die verwendeten Klassen, nur die SSL - Klassen weichen manchmal etwas davon ab.
Dann war das Ganze im Netz noch so konfiguriert, dass auch nur der im AD angemeldete Nutzer vom jeweiligen Client E-Mails mit SEINER (und keiner anderen) Adresse versenden darf. Das mußten wir dann als Randbedingung mit beachten.
Ja, so ein paar Zeilen, aber eine ewig lange Geschichte drumherum.
Viele Grüße
Tino