Ausführlich: Mail mit OpenSSL-Client aus der Konsole versenden

Envelope

Beim Basteln eines Mailflow-Testers stand ich erstmalig vor dem Rätsel, eine Mail über einen oder mehrere MTAs zu versenden, die unbedingt auf eine Authentifizierung bestehen. Auskommen wollte ich mit einem einzigen Script, ganz ohne irgendetwas am System einstellen- oder verändern zu müssen.
Hier nun los resultados mit einigen Erklärungen zu den Basics…

Da SMTPS de facto ausgestorben ist, wähle ich den ansehnlicheren Weg über das klassische SMTP – jedoch auf dem Port TCP/587.
Hier leite ich die verschlüsselte Übertragung implizit mit einem „STARTTLS“ ein. Häufig unterscheiden sich Port 25 und 587 nur noch darin, dass auf letzterem Kanal die Anweisung „STARTTLS“ obligatorisch ist. Ich glaube, dass auch Google Mail die Policies beider Ports gleich hält. Eben bis auf die kleine Besonderheit der „STARTTLS“-Anweisung. Wobei ich die Idee auf Port 25 etwas strengere Voraussetzungen zu schaffen, gar nicht so verkehrt finde. Wahrscheinlich wieder ein Thema endloser Diskussion.

Die Login-Daten werden base64-kodiert übertragen, was keineswegs als Verschlüsselung zu verstehen ist. Ein base64-kodierter String lässt sich ebenso schnell dekodieren wie kodieren – absichtlich. Vorteile bieten sich nur in der Lesbarkeit für den Mailserver:

echo -ne '\000benutzer.name@domain.tld\000meinpasswort' | openssl base64

Die zu erwartende Ausgabe:

AGJlbnV0emVyLm5hbWVAZG9tYWluLnRsZABtZWlucGFzc3dvcnQ=
\000 stellt ein Nullzeichen dar

Im nächsten Schritt kann die Kommunikation mit dem Server begonnen werden:

openssl s_client -connect smtp.domain.tld:587 -starttls smtp -ign_eof -crlf

Damit uns der Mailserver die Verbindung nicht nach einem „RCPT TO“ kappt, sind die Parameter „-ign_eof -crlf“ angehangen.
Die Verbindung sollte nach erfolgreichem TLS-Handshake nun verschlüsselt bestehen und der Server unsere Befehle entgegennehmen. Beispiel:

250 SMTPUTF8

Einige Server bestehen darauf, dass wir uns kurz mit unserem FQDN vorstellen. GMail übrigens nicht, aber bitte nicht abgewöhnen. Denn dieses Vorgehen ist dringend erwünscht – auch nach RFC!
Vorsichtige Mailserver prüfen, ob der vorgestellte FQDN gültig ist, ganz vorsichtige sogar, ob eure IP dem Namen entspricht.
Da wir über den Submission Port TCP/587 hereinkommen, sollte uns das aber nicht betreffen. Wie gesagt: Es könnte auf Port 25 ein stengeres Regelwerk herrschen.
Eine IP ist nach RFC nicht erwünscht und wird zudem häufig abgelehnt. Ebenso „localhost“ oder „localhost.localdomain“.
Und was wäre nun richtig, wenn wir keinen FQDN zur Hand haben? -> [MEI.NE.IP.ADDR] – auch, wenn einem hierdurch keine Sonderrechte zugesprochen werden. „Kein gültiger FQDN, kein Eintritt“, heißt es im schlimmsten Fall. Allerdings nimmt es da keiner so genau, fast immer darf in diesem Fall ein fiktiver Name verwendet werden (bitte überlesen ;-) ):

EHLO ichtestenur

EHLO ist eine Erweiterung gegenüber HELO und wird heute in der Regel von allen Mailservern vertanden. Der Mailserver grüßt zurück und beschreibt kurz seine Fähigkeiten – das täte er nicht, würde die Begrüßung HELO lauten.
Ausgabe (Beispiel an GMail):

EHLO ichtestenur
250-mx.google.com at your service, [1.2.3.4]
250-SIZE 35882577
250-8BITMIME
250-AUTH LOGIN PLAIN XOAUTH XOAUTH2 PLAIN-CLIENTTOKEN
250-ENHANCEDSTATUSCODES
250-PIPELINING
250-CHUNKING
250 SMTPUTF8
Sehr oft verbietet der Mailserver, dass ihm ungefragt eine Liste an Befehlen vorgesetzt wird, ohne jeweils die Antwort abzuwarten. Etwa, wenn wir in einen Telnet-Prozess hinein“pipen“ – z.B. mit einem Script. Der Trick ist, sich mit einem EHLO vorzustellen, zu erfahren, dass wir „pipen“ dürfen (250-PIPELINING) und erst dann damit beginnen. Grund: Spam.

Da TLS initiiert wurde, darf die Anmeldung Klartext via „AUTH PLAIN“ erfolgen, gefolgt vom base64-kodierten String aus Benutzernamen und Passwort:

AUTH PLAIN AGJlbnV0emVyLm5hbWVAZG9tYWluLnRsZABtZWlucGFzc3dvcnQ=

Die erwartete Ausgabe:

AUTH PLAIN AGJlbnV0emVyLm5hbWVAZG9tYWluLnRsZABtZWlucGFzc3dvcnQ=
235 2.7.0 Accepted

Jetzt noch Absender und Empfänger nacheinander auf den Umschlag schreiben:

MAIL FROM: 
(Antwort) 250 2.1.0 OK
RCPT TO: 
(Antwort) 250 2.1.0 OK

…bevor endlich der Inhalt folgen darf:

DATA

Was sollte in einer Mail nicht fehlen?

FROM: Max Power 
TO: Harald Handsome 
SUBJECT: Ich bin eine Betreffzeile
DATE: Wed, 17 Dec 2014 08:29:19 +0100
Content-Type: text/plain; charset=UTF-8

Hallo,
siehst du die Leerzeile über "Hallo"? Sie trennt den Header vom Inhalt.
Hast du gemerkt, dass ich einen Umlaut und Sonderzeichen benutzt habe? Das geht in Ordnung, da ich das "Charset" festgelegt habe und die Mail UTF-8 formatiert verfasse.
Nach RFC sind in einer Mail übrigens nur das "DATE"- und "FROM"-Feld(er) des Urhebers Pflicht.

Viele Grüße
Max Power
.

Warum gibt es „MAIL FROM:“ UND „FROM:“? – Kleiner Exkurs: Bei der Nachrichtenübertragung muss man die beiden Felder strikt voneinander getrennt betrachten:
Der „Umschlag“ (> „Envelope“) gehört zum SMTP (ein Protkoll!). SMTP definiert die obigen Befehle „HELO/EHLO“, „MAIL FROM“, „RCPT TO“ und „DATA“. Diese Daten werden vom MTA (Postfix etc.) geprüft.
Alles, was ich im Verlauf unter „DATA“ schreibe, interessiert das SMTP (als Protokoll!) nicht. Hier können die lustigsten Dinge stehen. Das SMTP(rotkoll) bekommt/möchte die Information darüber, wer ich bin, von wo ich versende und wer meine Daten empfängt. Natürlich wurde in einem RFC definiert, was in den Daten stehen muss, damit es eine Mail wird. Aber SMTP ist auch ganz ohne diese Daten zufrieden.
„MAIL FROM“ auf dem Umschlag kann also auch „die.verwaltung@orga.tld“ sein, „FROM“ hingegen „Ursula Ungern die.sekretaerin@orga.tld“.
Der empfangende MTA fügt meine im Protokoll/auf dem Umschlag festgehaltenen Daten „MAIL FROM“ und „RCPT TO“ dem Header hinzu. Dieser Felder sind durch meine Eingaben im „DATA“-Teil nicht beeinflussbar. Sie sind Bestandteil des Protkolls:

Return-Path: 
Delivered-To: mein.empfaenger@domainext.tld

Das Feld „DATE“ erzeuge ich übrigens immer mit „date -R“ in der Konsole. Das „-R“ gibt ein Datum nach RFC 2822 zurück.
Einige MTAs wie – wieder einmal – Google Mail, ersetzen freundlicherweise einige unverständliche/defekte/falsch formatierte Header, so auch das Datum, behalten aber Kopien der Original-Header bei („X-Google-Original-XYZ“).

Wurde die Nachricht letztendlich mit einem „.“ beendet, fügt der MTA sie seiner Warteschleife an und wird sie schnellstmöglich versenden.

Die Verbindung wird mit einem „quit“ geschlossen.

So sieht es dann im Ganzen aus. Meine Eingaben habe ich mit einer Raute versehen, um sie etwas hervorzuheben – abgesehen vom Daten-Teil:

250 SMTPUTF8
# EHLO ichtestenur
250-mx.google.com at your service, [1.2.3.4]
250-SIZE 35882577
250-8BITMIME
250-AUTH LOGIN PLAIN XOAUTH XOAUTH2 PLAIN-CLIENTTOKEN
250-ENHANCEDSTATUSCODES
250-PIPELINING
250-CHUNKING
250 SMTPUTF8
# AUTH PLAIN AGJlbnV0emVyLm5hbWVAZG9tYWluLnRsZABtZWlucGFzc3dvcnQ=
235 2.7.0 Accepted
# MAIL FROM: 
250 2.1.0 OK h8sm5058885wiy.17 - gsmtp
# RCPT TO: 
250 2.1.5 OK h8sm5058885wiy.17 - gsmtp
# DATA
354  Go ahead h8sm5058885wiy.17 - gsmtp
FROM: Max Power 
TO: Harald Handsome 
SUBJECT: Ich bin eine Betreffzeile
DATE: Wed, 17 Dec 2014 08:29:19 +0100
Content-Type: text/plain; charset=UTF-8

Hallo,
siehst du die Leerzeile über "Hallo"? Sie trennt den Header vom Inhalt.
Hast du gemerkt, dass ich einen Umlaut und Sonderzeichen benutzt habe? Das geht in Ordnung, da ich das "Charset" festgelegt habe und die Mail UTF-8 formatiert verfasse.
Nach RFC sind in einer Mail übrigens nur das "DATE"- und "FROM"-Feld(er) des Urhebers Pflicht.

Viele Grüße
Max Power
.
250 2.0.0 OK 1418802796 h8sm5058885wiy.17 - gsmtp
# quit
221 2.0.0 closing connection h8sm5058885wiy.17 - gsmtp

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.