Mailen mit PHP

Mail-Protokoll SMTP verstehen
PHP konfigurieren
Header der mail()-Funktion für Absenderangaben nutzen
Mailen mit Hilfe von sendmail
Mailen per SMTP-Server

Neben den Datenbankfunktionen ist die mail()-Funktion zum Versenden elektronischer Nachrichten wohl eine der beliebtesten bei PHP. Wegen ihrer Einfachheit, ist sie aber auch bei weitem nicht so mächtig wie eine reine E-Mail-Software. Doch auch hier gibt es Möglichkeiten in PHP.

mail("info@example.com", "Testmail", "Das ist der Text der Nachricht.");

Schon erhält info@example.com eine E-Mail mit dem Betreff "Testmail" und dem Inhalt "Das ist der Text der Nachricht." Optional lassen sich auch noch sogenannte Header als viertes Argument übergeben. Ebenso können Variablen an Stelle der einzelnen Argumente angegeben werden. Doch dazu später mehr.

Die Einfachheit der mail()-Funktion führt natürlich auch zu Beschränkungen. PHP ist kein MTA (Message Transfer Agent) im Sinn des SMTP-Protokolls. Daher sind die Möglichkeiten der Funktion sehr unterschiedlich und vom eingesetzten MTA abhängig. So sind unter Windows derzeit beispielsweise keine CC beziehungsweise BCC möglich. Um dennoch Kopien der Nachricht an weitere Empfänger zu versenden, bietet PHP aber - ähnlich Perl - einige weitere Möglichkeiten. So läßt sich das auf den meisten Unix-Systemen (Linux, FreeBSD...) standardmäßig eingerichtete sendmail ebenso ansprechen wie direkt eine Verbindung zum Mailserver herstellen. Hierfür sollte aber das SMTP-Protokoll zumindest in seinen Grundzügen bekannt sein.

[TOP]

Mail-Protokoll SMTP verstehen

Ähnlich der berühmten Schnecken-Post wird bei SMTP eine Nachricht in einen Briefumschlag gepackt. Dieser SMTP-Envelope darf nicht mit den Header verwechselt werden, der in der eigentlichen E-Mail-Nachricht zu finden ist. Dieser läßt sich analog als Kopfbogen vorstellen, auf dem der eigentliche Mail-Inhalt geschrieben steht. In der Regel wird der SMTP-Envelope nach Eingang der Nachricht auf dem Mailserver des Empfängers gelöscht. Eine Mail würde schematisiert so aussehen.

|SMTP-Envelope|
Mailabsender: absender@example.com
Mailempfänger: empfaenger@example.com

|Mail-Header|
Mailabsender: absender@example.com
Mailempfänger: empfaenger@example.com
X-Mailer: Mein-PHP-Script

|Mail-Inhalt|
Das ist der Inhalt der Testmail.
.

Die Zustellung der Nachricht erfolgt immer an den Empfänger im SMTP-Envelope. So kommt es beispielsweise bei Mailinglisten oft dazu, daß als Empfänger der Mail im Mail-Header (Kopfbogen) eine ganz andere Adresse steht als im SMTP-Envelope (Briefumschlag).

PHP bietet mit der mail()-Funktion die Möglichkeit, auch Header zu senden. Gemeint ist dabei der Mail-Header (Kopfbogen). Die Angaben werden einfach als viertes Argument übergeben:

mail("info@example.com",
     "Testmail", 
     "Das ist der Text der Nachricht.", 
     "X-Mailer: Mein-PHP-Script");

Da es sich eben nicht um den SMTP-Envelope handelt, läßt sich mit der PHP-Funktion standardmäßig auch kein CC oder BCC realisieren. Um eine Kopie (carbon copy) an einen weiteren Empfänger zu schicken, müßte dieser sowohl im SMTP-Envelope wie im Mail-Header angegeben werden. Ähnlich ist es beim BCC (blind carbon copy), wo die einzelnen Empfänger nicht erkennen sollen, daß die Nachricht auch noch anderen Empängern zugestellt wurde. Dabei werden die weiteren Empfänger zwar im SMTP-Envelope (Briefumschlag) nicht aber im Mail-Header (Kopfbogen) angegeben. Das auf einigen Systemen dennoch die Angabe von CC: beziehungsweise BCC: als viertes Argument der mail()-Funktion zum gewünschten Erfolg führt, ist eher zufällig und hängt mit der Konfiguration von PHP sowie der weiteren Softwareausstattung des Rechners zusammen.

[TOP]

PHP konfigurieren

In der Datei php.ini erfolgt auch die Konfiguration der Mail-Einstellungen. Dort findet sich schon der erste Hinweis auf die unterschiedliche Arbeitsweise unter Unix bzw. Windows.

[mail function]
SMTP		=	;for win32 only
sendmail_from	=	;for win32 only
sendmail_path	=	;for unix only, may supply arguments as well (default is sendmail -t)

Dieser Abschnitt regelt, worauf die mail()-Funktion von PHP aufsetzen soll. Für Windows (die ersten beiden Einträge) wird zusätzlich die Angabe eines SMTP-Server benötigt. Außerdem muß ein Standard-Absender eingetragen werden. Bevor es also ans Mailen mit PHP geht, muß mindestens eine der beiden Varianten eingerichtet sein. In der Regel übernimmt das aber der Provider.

Unter Windows sollte also ein lokaler SMTP-Server zur Verfügung stehen. Es kann aber auch ein anderer Mailserver im LAN oder Internet genutzt werden. Vorausgesetzt natürlich, das beim Aufruf der mail()-Funktion auch eine Verbindung zu diesem Server herstellbar ist.

Unter Unix (Linux, FreeBSD...) wird das in fast allen Distributionen enthaltene sendmail genutzt. Wer die Windows-Version von sendmail installiert hat (Shareware), sollte diese auch unter Windows nutzen können. Weil nämlich sendmail selbst bei der Konfiguration die Angabe eines Mailservers verlangt ;-) Je nach Betriebssystem setzt PHP also entweder über sendmail auf einen SMTP-Server auf oder nutzt den Server direkt. Bei der Windows-Version von PHP ist dazu ein "abgespecktes" sendmail einkompiliert. Der sogenannte "interne Sendmail-Support" von PHP ist eine Anpassung der frühen Quellen von sendmail.

[TOP]

Header für Absenderangaben nutzen

Die bei "sendmail_from" in der php.ini angegebene E-Mail-Adresse ist der wohl größte Nachteil beim Einsatz der mail()-Funktion. Meist trägt der Provider dort einen eigenen Account ein, der dann für alle Nutzer von PHP gilt. Oder es steht dort etwas wie "me@localhost.com" als Absender. Will man sich selbst die Nachricht senden, um zum Beispiel Formulareingaben per E-Mail zu erhalten, ist das nicht weiter störend. Wenn aber Dritte eine E-Mail erhalten sollen, dann muß eine Absender und möglichst noch eine Antwortdresse im Mail-Header angegeben werden. Hierzu läßt sich das vierte Argument der mail()-Funktion nutzen:

mail("du@irgendwo.com",
     "Testmail", 
     "Das ist der Text der Nachricht.", 
     "From: absender@example.com\nreply-to: absender@ritze.com");

Das \n sorgt für einen Zeilenumbruch.

[TOP]

Mailen mit Hilfe von sendmail

Vor allem für Unix-Anwender dürfte die Möglichkeit von PHP, sendmail direkt anzusprechen, interessant sein. Im folgenden Beispiel wird davon ausgegangen, daß der Path zu sendmail

/usr/sbin/sendmail

lautet. Im Zweifel einfach den Provider fragen.

$fd = popen("/usr/sbin/sendmail -t ","w");
fputs($fd, "To: empfaenger@example.com\n");
fputs($fd, "From: absender@example.com\n");
fputs($fd, "Reply-To: absender@ritze.com\n");
fputs($fd, "Subject: Testmail\n\n");
fputs($fd, "Das ist der Text der Nachricht.\n");
pclose($fd);

Mit popen() lassen sich alle folgenden Zeilen per fputs() zu sendmail "pipen". Das heißt: $fd ist hier sendmail, an welches die schon genannten Argumente To: From: Reply-To: Subject: sowie der E-Mail-Inhalt übergeben werden bis die Verbindung mit pclose() beendet wird. Sendmail wertet die Zeilen aus und kümmert sich dann selbständig um das Erstellen des für SMTP notwendigen Envelope (Briefumschlag).

[TOP]

Mailen per SMTP-Server

Die Mail-Funktion und sendmail sind also eigentlich nur Hilfen, um eine E-Mail per SMTP zu versenden. Gelegentlich kann es aber notwendig oder vielleicht sogar einfacher sein, den Server direkt per PHP anzusprechen. Das Simple Mail Transfer Protocol (SMTP; RFC 821; http://www.cis.ohio-state.edu/htbin/rfc/rfc821.html) ist wirklich so einfach wie der Name andeutet ;-) Der grundsätzliche Aufbau einer E-Mail mit Envelope, Header und Mail-Inhalt wurde bereits oben besprochen. Das folgende Script öffnet eine Verbindung zum Mailserver "mail.example.com" auf dem Standard-Port 25. Der Mailserver muß natürlich noch auf den eigenen angepaßt werden. Auch ich mag es nämlich nicht, wenn böse Buben über anderer Leutz Server per RCPT: spammen. (Der besseren Übersichtlichkeit halber sind die Kopfzeilen für den Mail-Header aus mehrer Variablen zusammengesetzt und werden dann als $KopfZeilen übergeben.)

$K1 = "From: absender@example.com\n";
$K2 = "To: empfaenger@example.com\n";
$K3 = "Reply-To: absender@ritze.com\n";
$K4 = "Subject: Testmail\r\n";
$KopfZeilen = "$K1" . "$K2" . "$K3" . "$K4";

// Beim Mailserver (auf Standard-Port 25) einloggen
$login = fsockopen("mail.example.com", 25);
// Antwort entgegennehmen
$line = fgets($login, 1024);

// Hier beginnt der "BRIEFUMSCHLAG"
// Sich identifizieren: localhost ist immer richtig ;-)
fputs($login, "helo localhost\r\n");
$line = fgets($login, 1024);

// Es sollte nicht geschwindelt werden
fputs($login, "MAIL FROM: absender@example.com\r\n");
$line = fgets($login, 1024);

// Empfaengeradresse bekanntgeben (hier ist es BCC)
fputs($login, "RCPT TO: empfaenger@example.com\r\n");
$line = fgets($login, 1024);
// Hier endet der "BRIEFUMSCHLAG"

// Text schreiben ankuendigen
fputs($login, "DATA\r\n");
$line = fgets($login, 1024);

// Betreff und Kopfzeilen schreiben (zweites \r\n ist wichtig!)

fputs($login, "$KopfZeilen\r\n\r\n");

// Nun der Inhalt
fputs($login, "Das ist der Text der Nachricht.\r\n");

// Mail beenden mit einem alleinstehenden Punkt
fputs($login, ".\r\n");
$line = fgets($login, 1024);

// Verbindung beenden
fputs($login, "QUIT\r\n");
$line = fgets($login, 1024);

Zu einer Tücke an dieser Variante kann der Spam-Schutz werden. Einige Provider benutzen hierfür mail-after-pop. Das bedeutet: Erst nach einem erfolgreichen Login in einer Mailbox wird für eine gewisse Zeit die IP-Adresse fürs Versenden von E-Mail freigeschalten. Eventuell muß also erst ein Login beim POP3-Server erfolgen. Ein kurzes Script hierfür steht am Ende des Textes.

Nun sind hoffentlich alle Klarheiten beseitigt, der Text weitgehend fehlerfrei und auch für Einsteiger verständlich. Kritik ist jederzeit willkommen unter info@ritze.com - egal ob per mail() , sendmail oder Mailserver ;-)


[TOP]

POP3-Login

Ein einfaches Script, um auf Servern mit mail-after-pop-Spamschutz ein POP3-Login vor dem Mailen auszuführen. Als POP3-Server wird die Domain "test.ritze.com" mit POP3-Standardport 110 angenommen, als Nutzername "meinAccount" und als Passwort "SagIchNich".

@$login = fsockopen("test.ritze.com", 110) or die("Keine Verbindung zum POP-Server.");
$line = fgets($login, 1024);
fputs($login, "USER meinAccount\r\n");
$line = fgets($login, 1024);
fputs ($login, "PASS SagIchNich\r\n");
$line = fgets($login, 1024);
fputs($login, "QUIT\r\n");
$line = fgets($login, 1024);