Email mit SMTP-Auth

Hier könnt Ihr gute, von Euch geschriebene Codes posten. Sie müssen auf jeden Fall funktionieren und sollten möglichst effizient, elegant und beispielhaft oder einfach nur cool sein.
Der-T
Beiträge: 65
Registriert: 06.05.2009 20:01

Email mit SMTP-Auth

Beitrag von Der-T »

Hallo,

auch wenn ichnicht davon ausgehe, dass der nachfolgende Code besonders effizient, elegant und beispielhaft oder einfach nur cool ist, so wurde er nachgefragt und mir fällt kein besser Ort als dieses Sub-Forum ein, um der Anfrage nachzukommen.

Folgender Code entstammt meinem Projekt rLOOKvUPs. Die Besonderheit daran ist eben, dass hier als Absender und Empfänger Email-Adresse die gleiche Adresse verwendet wird. Ferner wir lediglich ein übergebener String versender, die Authentifizierung am Mail-Server erfolgt wie der Topic schon sagt mit SMTP-Auth. Erfolgreich getestet habe ich es mit 1&1, GMX und web.de. Den Code habe ich selbst geschrieben, mit ein klein wenig "Inspiration" durch das Code Archive und der Beschreibung einer SMTP-Auth-Sitzung bei Wikipedia.

Viel Spaß damit!

Code: Alles auswählen

InitNetwork() 

Enumeration    
  #NotificationMail  
EndEnumeration

Declare.s ReceiveData(ConnectionID.i)
Declare SendString(ConnectionID, StringToSend.s)

Procedure.i SendMyMail(Server.s,User.s,Pass.s,Mail.s,Betreff.s,Inhalt.s)
  Protected ReturnValue.i = 0      
  Protected ConnectionID
  ConnectionID = OpenNetworkConnection(Server,25)        
  If ConnectionID
    If ReceiveData(ConnectionID) = "220"
      SendString(ConnectionID,"EHLO rvsLOOKUP.localhost")      
      If ReceiveData(ConnectionID) = "250"          
        If ReceiveData(ConnectionID) = "250"
          SendString(ConnectionID,"AUTH LOGIN")          
          If ReceiveData(ConnectionID) = "334"
            Protected tmpString.s = Space(1024) 
            Base64Encoder(@User,StringByteLength(User),@tmpString,1024)
            SendString(ConnectionID,tmpString)            
            If ReceiveData(ConnectionID) = "334"
              tmpString = Space(1024) 
              Base64Encoder(@Pass,StringByteLength(Pass),@tmpString,1024)
              SendString(ConnectionID,tmpString)              
              If ReceiveData(ConnectionID) = "235"
                SendString(ConnectionID,"MAIL FROM: <"+Mail+">")                
                If ReceiveData(ConnectionID) = "250"
                  SendString(ConnectionID,"RCPT TO: <"+Mail+">")                  
                  If ReceiveData(ConnectionID) = "250"
                    SendString(ConnectionID,"DATA")                    
                    If ReceiveData(ConnectionID) = "354"
                      SendString(ConnectionID,"From: <"+Mail+">")                      
                      SendString(ConnectionID,"To: <"+Mail+">")                      
                      SendString(ConnectionID,"Subject: "+Betreff)                      
                      SendString(ConnectionID,"")                      
                      SendString(ConnectionID,Inhalt)                      
                      SendString(ConnectionID,".")                      
                      If ReceiveData(ConnectionID) = "250"
                        SendString(ConnectionID,"QUIT")   
                        CloseNetworkConnection(ConnectionID)
                        ReturnValue = 1                      
                      EndIf                  
                    EndIf                      
                  EndIf                    
                EndIf                  
              EndIf                
            EndIf              
          EndIf            
        EndIf          
      EndIf
    EndIf      
  EndIf 
  ProcedureReturn ReturnValue
EndProcedure

Procedure.s ReceiveData(ConnectionID)
  Define DataResult.s
  DataResult = Space(4999)
  ReceiveNetworkData(ConnectionID,@DataResult,4999)   
  DataResult = Left(DataResult,3)
  ProcedureReturn DataResult
EndProcedure

Procedure SendString(ConnectionID, StringToSend.s)
  StringToSend + #CRLF$
  SendNetworkData(ConnectionID, @StringToSend, Len(StringToSend))
EndProcedure
Zuletzt geändert von Der-T am 12.07.2010 20:18, insgesamt 2-mal geändert.
Gruß
Der-T
PB 4.50 RC2
walker
Beiträge: 278
Registriert: 29.08.2004 18:39
Wohnort: Bayern

Re: Email mit SMTP-Auth

Beitrag von walker »

Hi,

das kann aber nur funktionieren, wenn im Datenverkehr keine "Panne" passiert oder sonst eine Verzögerung auftritt. Die Daten müssen immer sofort vorhanden sein ... oder?
Imho ist es besser, diese Routine in eine Repeat/Until Schleife zu packen und die Ereignisse mit NetworkClientEvent() abfragen... und dann in einer Select/Endselect Schleife die einzelnen Schritte abarbeiten .... Angenehmer Nebeneffekt... der Code wird lesbarer ....
Der-T
Beiträge: 65
Registriert: 06.05.2009 20:01

Re: Email mit SMTP-Auth

Beitrag von Der-T »

Hallo Walker,

ja, wenn es während der Übertragung zu einem Fehler kommt, kann die Mail nicht gesendet werden. In der Praxis ist das bei mir allerding noch nicht vorgekommen und ich bekomme von meinem rvsLOOKUP täglich im Schnitt 2 bis 3 Mails. Ok, ist nicht viel, aber es dennoch auch, dass das senden bei den wenigen Mails bisher immer tadellos funktioniert hat. Wie du das mit dem Select-Block meinst, ist mir hingegen nicht ganz klar. Klar weiss ich, wie man mit Select arbeitet, aber da der SMTP-Server an unterschiedlichen Stellen die gleichen Meldungen liefert, müsste man innerhalb eines Case-Blocks auch wieder verzweigen, entweder mit nem weiteren Select oder mit if. Ob dies wirklich übersichtlicher wird, sei mal dahingestellt.
Gruß
Der-T
PB 4.50 RC2
Benutzeravatar
Blackskyliner
Beiträge: 532
Registriert: 28.07.2005 00:54
Wohnort: /home/Blackskyliner/

Re: Email mit SMTP-Auth

Beitrag von Blackskyliner »

walker hat geschrieben:Hi,

das kann aber nur funktionieren, wenn im Datenverkehr keine "Panne" passiert oder sonst eine Verzögerung auftritt. Die Daten müssen immer sofort vorhanden sein ... oder?
Imho ist es besser, diese Routine in eine Repeat/Until Schleife zu packen und die Ereignisse mit NetworkClientEvent() abfragen... und dann in einer Select/Endselect Schleife die einzelnen Schritte abarbeiten .... Angenehmer Nebeneffekt... der Code wird lesbarer ....
Ich weiß es ist getrollt...

Select/Endselect Schleife gibt es nicht, genau so wenig wie eine if-schleife...
Am Ende sind beides Ausdrücke, die eine Bedingung signalisieren/darstellen/evaluieren...

Ansonsten ist der Code doch für kleinere Projekte ganz i.O. finde ich zumindest :allright:
Keine meiner Antworten ist endgültig, es kann passieren, dass ich den so eben geposteten Beitrag noch mehrmals ändere, um Doppelposts zu umgehen.
_________________
Purebasic Windows 7 x64 & Linux (Ubuntu 10.04LTS) 4.50[x64|x86] Nutzer
_________________
Projekte: YAED - Yet another Event Dispatcher
Dark
Beiträge: 93
Registriert: 24.08.2007 20:36
Kontaktdaten:

Re: Email mit SMTP-Auth

Beitrag von Dark »

Hallo,

ich finde erstmal gut das du anderen Leuten den Code zur Verfügung stellst. Jedoch möchte ich auch etwas Kritik hevorbringen, da Anfänger sonst davon ausgehen sie könnten diesen Code einfach benutzen ohne die Gefahren zu kennen.
Es wird nicht überprüft ob Daten vorhanden sind, sondern einfach ReceiveNetworkData() aufgerufen, dies funktioniert nur, da dieser Befehl in PureBasic blocking ist. Dies bedeutet, dass die API von dem jeweiligen Betriebsystem den Thread so lange anhält, bis Daten vorhanden sind.
Dies führt auch direkt zu dem nächsten Problem: Du überprüfst nicht ob überhaupt Daten empfangen wurden (Rückgabewert von ReceiveNetworkData()). Dies könnte zum Beispiel bei einem Disconnect seitens des Serves passieren. Dieser Fehler fällt bei dir nicht so schwer auf, da du eine eigene Prozedur zum Empfangen geschrieben hast, sonst könnte in dem Empfangsbuffer noch der Wert von vorher drinne stehen. Zugleich entsteht hierdurch jedoch ein weiterer sehr wichtiger und gerne ingorierter Fehler: SMTP basiert auf TCP, einem streambasieren (und nicht paketbasierten!) Protokoll. Dies bedeutet das die Daten in beliebig vielen Aufrufen von ReceiveNetworkData auftauchen könne. Es könnte also sein das du einmal nur ein Byte und dann die ganzen anderen Bytes erhälst. In diesem Fall würde die Zahl nicht mehr richtig ausgelesen.
Das gleiche trifft nebenbei auch auf das Senden zu: Bei dem Senden besteht keine Garantie, das alle Daten gesendet werden, sondern es kann vorkommen, das nur die Hälfte oder gar nur ein Byte übermittelt wurde (Rückgabewert!). Die weiteren Daten müssten also nochmal gesendet werden. In der Hilfe steht auch drinne das die größe bei SendNetworkData und TCP nicht 65536 bytes überschreiten darf. Dies könnte jedoch beim Inhalt ggf. überschritten werden.
So wie deine Senden routinen geschrieben sind, sind sie außerdem auch Unicode kompatibel, was sie mit SendNetworkString wären. Jedoch steht in der PureBasic Hilfe nichts zu dem Rückgabewert der Funktion drinne. Es wäre also vll, ratsam eine Umkonvertierungsroutine mithilfe eines CompilerIf zu implementieren.

Zum schluß noch nen kleiner tipp: Initialisiere den Wert von ReturnValue auf #False/0 dann musst du ihn nicht jedes mal ändern, sondern nur im Erfolgsfall auf #True/1 setzen.

mfg,
Dark
Der-T
Beiträge: 65
Registriert: 06.05.2009 20:01

Re: Email mit SMTP-Auth

Beitrag von Der-T »

Blackskyliner hat geschrieben:Ansonsten ist der Code doch für kleinere Projekte ganz i.O. finde ich zumindest :allright:
Danke, aber ich habe gerade noch etwas unschönes gefunden. Da stehen immer noch relikte von der PB-Mail-Lib drin (CreateMail etc.), welche überhaupt nicht mehr gebraucht werden, die werde ich noch rausnehmen ....
Dark hat geschrieben:Jedoch möchte ich auch etwas Kritik hevorbringen, da Anfänger sonst davon ausgehen sie könnten diesen Code einfach benutzen ohne die Gefahren zu kennen.
Hallo Dark. In der Tat waren mir die von dir geschilderten Probleme so auch nicht wirklich bewusst. Daher ein ganz großes Danke für deine konstruktive Kritik, werde versuchen, diese in den Code einfliessen zu lassen.
Gruß
Der-T
PB 4.50 RC2
Der-T
Beiträge: 65
Registriert: 06.05.2009 20:01

Re: Email mit SMTP-Auth

Beitrag von Der-T »

Ok, die Relikte der PB-Mail-Lib sind nun vollständig entfernt und die wirklich mehr als unnötigen Else-Zweige wurden ebenfalls entfernt. Alle anderen Überarbeitungen dauern noch ein wenig.
Gruß
Der-T
PB 4.50 RC2
Benutzeravatar
rolaf
Beiträge: 3843
Registriert: 10.03.2005 14:01

Re: Email mit SMTP-Auth

Beitrag von rolaf »

Sehr schön, weiter so... :allright:
:::: WIN 10 :: PB 5.73 :: (x64) ::::
Benutzeravatar
X360 Andy
Beiträge: 1206
Registriert: 11.05.2008 00:22
Wohnort: Bodensee
Kontaktdaten:

Re: Email mit SMTP-Auth

Beitrag von X360 Andy »

Vielen dank für das bereitstellen :)
Andreas21
Beiträge: 390
Registriert: 30.08.2004 09:05
Computerausstattung: Desktop
Windows 10 Pro x64
CPU: AMD Ryzen 5 2600 3.40 GHz
Ram: 16GB RAM
Grafik: NVIDA Geforce 1060
PB: 5.72 X86/X64
Wohnort: Heidelberg

Re: Email mit SMTP-Auth

Beitrag von Andreas21 »

In Zeile 19 und 20 wertest du die Antwort vom Server aus.
Der Server sendet aber diese nur 1 mal. Da bleibt der Code stehen.
Der-T hat geschrieben:

Code: Alles auswählen

19 If ReceiveData(ConnectionID) = "250"          
20   If ReceiveData(ConnectionID) = "250"
Das müste geändert werden.

Und ein InitNetwork() mit rein nehmen damit der Code auch lauffähig ist.
Windows 10 x64 Pro - PB 5.61 X64 / x32 - PB 4.6 x32
Antworten