Announcement

Collapse
No announcement yet.

MS Exchange / Delphi / Indy

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • MS Exchange / Delphi / Indy

    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
    Zuletzt editiert von tinof; 04.01.2011, 23:22.
    Ich habs gleich!
    ... sagte der Programmierer.
Working...
X