Das Senden einer Mail per SMTP leicht verständlich gemacht mit Beispielen in Perl
Der erste Schritt besteht darin, eine Verbindung zum Host herzustellen. Dieser Host ist derjenige, welcher eine Mail entgegennimmt und lauscht dafür gewöhnlich auf dem Port 25. Diesen ersten Schritt und alle Weiteren gehen wir nun gemeinsam durch, dazu öffnen wir eine Konsole und geben ein: telnet example.com 25
, also Hostname und Port mit Leerzeichen getrennt. Darauf antwortet der Mailserver z.B. so:
220 example.com ESMTP Postfix
Das nächste Kommando lautet wie folgt und wird wie alle weiteren Kommandos mit dem Drücken der Eingabetaste beendet:
HELO example.com
Worauf der Server antwortet:
250 example.com
Es folgt nun der Dialog zur Authentifizierung am Server, eingegeben wird hierzu:
AUTH LOGIN
Und der Server antwortet:
334 VXNlcm5hbWU6
Was soviel heißt wie Username:
und dieser soll Base64 kodiert sein, also geben wir ein:
dXNlcg==
Daraufhin möchte der Server in Base64 ein Password:
UGFzc3dvcmQ6
Und auch dieses geben wir ein:
cGFzcw==
Sofern das erfolgreich war, zeigt sich der Server mit:
235 2.7.0 Authentication successful
Ansonsten bekommen wir eine Fehlermeldung. Weiter geht es, wir geben ein:
Mail From: <from@example.com>
Und mit einem schlichten:
250 2.1.0 Ok
bedankt sich der Server dafür. Weiter gehts:
Rcpt To: <to@example.com>
Als Antwort erhalten wir:
250 2.1.5 Ok
Der Server ist nun bereit zum Senden der eigentlichen Daten. Zum kenntlich machen, daß Daten gesendet werden sollen, genügt das Kommando:
Data
Was der Server beantwortet mit:
354 End data with <CR><LF>.<CR><LF>
Das heißt, daß der Server nun bereit ist, eine komplette Mail entgegenzunehmen, die im einfachsten Fall so aussieht:
From: from@@example.com To: to@example.com Subject: Hey! text text text .
Beachte also den Punkt ganz unten, er signalisiert dem Mailserver, daß keine weiteren Daten folgen. Mit einem:
250 2.0.0 Ok: queued as 44445215690C
quittiert dies der Server womit er auch die ID
bekanngibt mit welcher die Mail in die Warteschleife kommt. Diese ID
wird bis zum Empfänger durchgereicht. Verabschieden wir uns nun vom Server:
Quit
Und zum Dank für diese Höflichkeit antwortet der Server schlußendlich:
221 2.0.0 Bye
Sämtliche zum Protokoll gehörigen Kommandos implementiert das Perlmodul Net::SMTP
, es gehört zur libnet
und ist auch auf CPAN verfügbar. Wer etwas tiefer eindringen möchte, folge den weiteren Ausführungen dieses Artikels.
Grundsätzlich gibt es zwei Möglichkeiten zum Senden einer Mail per SMTP mit Perl. Basis ist ein Socket
, was per IO:Socket::INET
recht einfach zu erstellen ist, dazu später mehr.
helo %host% auth login %user_base64% %pass_base64% mail from: <%from%> rcpt to: <%to%> data from: %from_plain% <%from%> to: %to_plain% <%to%> subject: %subject% %mesg% . Quit
Von daher kommt auch alles auf einmal vom Server als Antwort:
220 example.com ESMTP Postfix 250 example.com 334 VXNlcm5hbWU6 334 UGFzc3dvcmQ6 235 2.7.0 Authentication successful 250 2.1.0 Ok 250 2.1.5 Ok 354 End data with <CR><LF>.<CR><LF> 250 2.0.0 Ok: queued as 44445215690C 221 2.0.0 Bye
Hnweis: Jedes Zeilenende ist mit einem CRLF
(Carriage Return + Line Feed) abzuschließen. Dieselben Zeilenenden finden sich auch in der Serverantwort. Ausgenommen von dieser protokollspezifischen Festlegung sind die eigenen Maildaten die zwischen DATA
und <CR><LF>.<CR><LF>
eingebaut sind.
Dieser Allesaufeinmal
-Lösung haftet jedoch der Nachteil an, daß die Kommandos nicht im Einzelnen geprüft werden können ob sie erfolgreich waren. Beispiel einer Fehlermeldung wie sie erscheinen würde, wenn ein falscher Benutzername gesendet wurde:
535 5.7.8 Error: authentication failed: authentication failure
Die erste Ziffer kodiert die Fehlerklasse, diese sind:
# aus der libnet, Net::Cmd sub CMD_INFO {1} sub CMD_OK {2} sub CMD_MORE {3} sub CMD_REJECT {4} sub CMD_ERROR {5} sub CMD_PENDING {0}
Ein weiterer Nachteil ergibt sich daraus, daß mit dem SMTP-Kommando Quit
die Sitzung beendet und keine weitere Mail gesendet werden kann.
Betrachte untenstehenden Code:
use strict; use warnings; use IO::Socket; my $io = IO::Socket::INET->new('example.com:25') or die $@
Infolgedessen liegt in $io
das gewünschte Socket bzw. Handle zur Verbindung. Dieses Handle verhält sich wie ein PIPE
in welches Daten hineingeschoben und wieder ausgelesen werden können. So steht bereits die erste Antwort vom Mailserver in der PIPE
die wie folgt da ausgelesen wird:
$io->getline; # Antwort # 220 example.com ESMTP Postfix
Anmerkungen: Die Klasse IO::Socket::INET
ist als Package in der Datei IO/Socket.pm
definiert die mit use IO::Socket;
einzubinden ist. Sämtliche IO
-Klassen erben von IO::Handle
, somit also auch die Methoden print()
und getline()
. Letztere liest aus dem Handle (Socket) solange bis die einem CRLF
entsprechenden Bytes erscheinen. Untenstehende eigene Methode veranschaulicht die Funktionsweise:
sub _getline{ my $self = shift; my $line = ''; while( read($self, my $chr, 1) ){ $line .= $chr; return $line if $line =~ /\r\n$/; } }
Für etwas mehr Komfort, betrachte das SubModul SendMail::SMTP
in der Source (ganz unten). Das prüft jedes an den Mailserver abgesetztes Kommando einzeln und verwendet hierzu Perl's bewährtes Exceptionmodell: Wenn es einen Fehler gibt, wird dessen gesamte Statusline als Exception geworfen. Als besonderes Feature liefert sendmail()
die ID der gesendeten Mail zurück.
Während der Konstruktor eine SMTP Sitzung zum Mailserver aufgebaut hat, wird diese nach dem Senden einer Mail per sendmail()
nicht beendet, so daß weitere Mails mit der einmal erstellten Instanz gesendet werden können. Sofern die Sitzung nicht explizit per bye()
beendet wird, erfolgt dies im Destruktor der hier vorgestellten Klasse.
Verschlüsselte Übertragung: Mit SendMail::SMTP
können Mails auch per SSL versendet werden. Hierzu wäre einfach die Option ssl => 1
zu setzen bei der Objekterstellung. Es sei jedoch angemerkt, daß eine verschlüsselte Übertragung nicht immer sinnvoll ist, insbesondere wenn mehrere Mailserver im Spiel sind. Ebensowenig ist sichergestellt, daß ein Mailempfänger zum Abholen seiner Mails mit POP3 oder IMAP eine sichere Verbindung verwendet.
Eine Ende-zu-Ende-Sicherheit wird auch schon deswegen nicht erreicht, da alle Mailserver und Mailrelays die E-Mail im Klartext verarbeiten. Insofern ist es auch unsinnig, Mailformulare per HTTPS auszuliefern und abzusenden, weil HTTPS ja keine Garantie dafür ist, daß die Mail sicher übertragen wird.
Datenschutzerklärung: Diese Seite dient rein privaten Zwecken. Auf den für diese Domäne installierten Seiten werden grundsätzlich keine personenbezogenen Daten erhoben. Das Loggen der Zugriffe mit Ihrer Remote Adresse erfolgt beim Provider soweit das technisch erforderlich ist. sos@rolfrost.de.