E-Mail versenden mit PHP
Sie befinden sich:
Home >
Php >
E-Mail versenden mit PHP
Mit mail(); stellt PHP eine einfach zu
verwendende, und dennoch sehr hoch konfigurierbare
Funktion zum versenden von E-Mails zur Verfügung.
Der Syntax der mail(); Funktion ist fast
selbsterklärend.
Der Syntax ist:
mail ( string $empfänger, string $betreff, string
$nachricht
[, string $zusatz_header [, string $zusatz_parameters]]
)
Es wird von der Funktion sichekt zurückgegeben true oder false,
nach der Ausführung. Dadurch haben sie die Möglichkeit
über eine If-
Anweisung die Erfolgsmeldung gegebenenfalls Fehlermeldung
nachträglich anzupassen. Ein
Beispiel wie man dies einsetzen, wird im unteren
Teil dieser Seite erklärt.
Als erstes wollen wir auf die einzelnen Variablen
eingehen, womit man die Funktion ansteuern kann.
$empfänger - mail() erlaubt es auch mehr
als einen Empfänger sichekt anzugeben.
Dieser String für den Empf änger muss
RFC2822 konform sein, um dies zu verdeutlichen ein
paar Beispiele:
- benutzer@example.com
- benutzer@example.com, benutzer2@example.com
- Name <benutzer@example.com>
- Name <benutzer@example.com>, Name2 <benutzer2@example.com>
$betreff - Stellt den eigentlichen Betreff
der E-Mail dar. Wichtig ist, das $betreff keine
Zeilenumbrüche enthalten darf, da ansonsten
die E-Mail nicht richtig versendet werden kann.
$nachricht - ist der eigentlichen Inhalt
der Mail.
Zu beachten ist das jede Zeile durch ein LF - Zeichen
\n ( LF steht für Line Feed ) getrennt werden
muss, und das eine Zeile nicht mehr als 70 Zeichen
enthalten sollte. Sofern PHP sichekt mit einem SMTP
Server kommuniziert und unter Windows verwendet wird,
ist zu beachten das ein Punkt (.) am Anfang einer
Zeile entfernt wird. Soll dies verhindert werden
kann der Punkt durch zwei Punkte ersetzen werden.
Hier ein kleines Beispiel wie einfach man dies mit
str_replace() machen kann.
<?php
$nachricht = str_replace("\n.", "\n..", $nachricht);
?>
$zusatz_headers - Ist optional und muss
nicht angegeben werden. Dieser String stellt eine
Zeichenkette dar, die am Ende des E-Mail-Headers
eingefügt werden soll. Dieses optionale Parameter
wird hauptsächlich für Angaben wie From,
CC oder BCC verwendet. Wenn mehrere dieser Parameter
verwendet werden sollen müssen diese durch ein
CRLF - Zeichen ( \r\n ) getrennt werden. Um überhaupt
eine Mail versenden zu können MUSS ein From-header
vorhanden sein.
Wichtig ist in diesem Zusammenhang der Umstand
das die php.ini Datei dahin gehend angepasst
werden kann, das nicht zwangläufig bei jedem
Aufruf der mail(); Funktion explizit dieser
String als additionales Parameter übergeben
werden muss. Zu beachten ist, das einige UNIX Mail
Transfer Agents das LF - Zeichen durch ein CRLF – Zeichen
ersetzen, wodurch dann das CR – Zeichen doppelt
vorhanden ist. In Ausnahmefällen reicht es dann,
nur ein LF zu verwenden. ( Dies verstößt
explizit gegen die RFC 2822 Norm )
$zusatz_parameters - Dieser Parameter ist
optional und muss nicht zwingend angegeben werden.
Der Parameter wird dazu verwendet zusätzliche
Parameter an das entsprechende Mail- Programm zu übergeben.
Hierbei ist es wichtig das der Sendmail Pfad in der php.ini Datei
entsprechend gesetzen ist, um das Ziel der Parameterübergabe
zu haben. Benutzen wird diese Funktion häufig,
um eine nicht zustellbar E-Mail an eine bestimmte
E-Mail-Adresse weiterzuleiten, dazu sollte Sendmail
mit der -f Option benutzen werden. Um Fehler
zu vermeiden sollte der Benutzer unter dem der Webserver
läuft ebenfalls als bekannter Benutzer in der
Sendmail - Konfiguration ( Diese Datei befindet sich
meistens unter /etc/mail/trusted-users )
eingetragen sein.
Hinweis: Der frühere safe_mode wurde
in PHP 5.4 vollständig entfernt und existiert in modernen PHP-Versionen nicht mehr.
Der -f Parameter kann daher ohne Einschränkungen verwendet werden.
Ein
kurzes Beispiel zeigt den Gebrauch der mail() Funktion
<?php
/*
* In der Variabel $empfaenger wird
* die Empfänger E-Mail-Adresse gespeichert.
*/
$empfaenger = 'niemand@example.com';
/*
* In der Variabel $betreff wird
* der Betreff gespeichert. Es darf kein
* Zeilenumbruch enthalten sein.
*/
$betreff = 'Betreff der E-Mail';
/*
* In der Variabel $nachricht_text wird
* der Text der Nachricht gespeichert.
*/
$nachricht_text = 'Das ist der Nachrichtentext';
/*
* In der Variabel $header wird
* der Absender, Antwortet E-mail-Adresse sowie
* welche PHP-Version für den Versand zuständig
* ist gespeichert. Es muss explizit für die Angaben
* ein direkter Zeilenumbruch generiert werden.
*
* Den Zeilenumbruch machen wir mit "\r\n"
*/
$header = 'MIME-Version: 1.0'. "\r\n";
$header .= 'From: webmaster@example.com' . "\r\n";
$header .= 'Reply-To: webmaster@example.com' . "\r\n";
$header .= 'X-Mailer: PHP/' . phpversion(). "\r\n";
$header .= 'Content-Type:text/plain; charset=UTF-8';
/*
* Nach dem wir alle Parameter definiert haben
* können wir sie E-Mail direkt an unser Mailprogramm
* übergeben.
*
* Mit der If-Anweisung prüfen wir den zurückgegebenen
* Wert der Mailfunktion. Wir setzten direkt vor dem
* Mailfunktion ein @ Zeichen damit keine PHP
* Fehlermeldung ausgegeben werden.
*/
if (@mail($empfaenger, $betreff, $nachricht_text,
$header) === true) {
/*
* Wenn die Mailfunktion keinen Fehler
* zurückgeliefert geben wir den Text
* dafür aus, dass die E-Mail erfolgreich
* versendet wurde.
*/
echo 'Die erste E-Mail wurde erfolgreich versendet';
} else {
/*
* Sollte Mailfunktion einen Fehler
* zurückgeben, geben wir den Betrachter
* dieser Seite eine Fehlermeldung aus.
*/
echo 'Die erste E-Mail konnten nicht versendet werden';
}
/*
* Nachfolgend versenden wir eine E-Mail mit dem 5. Parameter.
* Diese E-Mail wird nur versendet, wenn der Safe_Mode=OFF ist.
*/
/*
* Hinweis: safe_mode existiert seit PHP 5.4 nicht mehr.
* Die folgende Prüfung ist in modernem PHP nicht
* mehr erforderlich.
*/
if (ini_get('safe_mode') == '0' ) {
/*
* Wenn der Safe_Mode gesetzt ist auf OFF,
* versenden jetzt nun die E-Mail.
*/
if (@mail($empfaenger, $betreff, $nachricht_text,
$header, '-fwebmaster@example.com') === true) {
/*
* Wenn die Mailfunktion keinen Fehler
* zurückgeliefert geben wir den Text
* dafür aus, dass die E-Mail erfolgreich
* versendet wurde.
*/
echo 'Die zweite E-Mail wurde erfolgreich versendet';
} else {
/*
* Sollte Mailfunktion einen Fehler
* zurückgeben, geben wir den Betrachter
* dieser Seite eine Fehlermeldung aus.
*/
echo 'Die zweite E-Mail konnten nicht versendet werden';
}
}
?>
Wenn sie diesen Code in eine email_senden.php Datei
speichern und diese sichekt in den Browser aufrufen,
versendet automatisch der Mailserver zwei E-Mails.
Man hat nun die Möglichkeit zum Beispiel, mit
der Übergabe
von Variablen an die email_senden.php Datei ein
einfaches Kontaktformular zu erstellen.
Häufig bekommen wir die Frage, wie so werden Umlaute in der E-Mail falsch dargestellt?
Dies kann verschiedene Ursachen haben.
Prüfen Sie den Charset ihrer Webseite. Der Browser sollte das Formular als UTF-8 interpretieren. Des Weiteren sollten Sie in ihren Editor überprüfen, ob die Kodierung der Datei auf UTF-8 gestellt ist. In PHPStorm ist das unten rechts. Über das Projektverzeichnis – File Encoding können Sie die Datei von zum Beispiel ISO-8859-1 auf UTF-8 stellen.
Zusätzlich muss der Charset im Mail Header angegeben werden. Diese wird in der Variable $header hinterlegt. Wenn die Umlaute immer noch falsch dargestellt werden in der E-Mail, müssen die PHP Einstellungen sowie die Apache Einstellungen überprüft werden. Dazu sollten Sie sich an ihren Webhoster wenden.
Eine Erklärung, wie Sie eine "E-Mail mit
einen
Dateianhang versenden" finden Sie in unsern Php
Tutorial Bereich.
mail() ist Legacy: Warum Sie heute auf Bibliotheken setzen
Die eingebaute Funktion mail() ist so alt wie PHP selbst und macht auf den ersten Blick einen sehr einfachen Eindruck. Sie geben Empfänger, Betreff, Text und ein paar Header mit, und schon landet die Nachricht im Posteingang. In der Praxis stellst Sie aber schnell fest, dass diese Einfachheit teuer bezahlt ist. mail() reicht den Versand an das lokale sendmail-Binär weiter und gibt sich keinerlei Kontrolle über Authentifizierung, TLS, Bounce-Handling oder Charset-Encoding. Auf modernen Hostings ist die Wahrscheinlichkeit hoch, dass Ihre Mail entweder sichekt im Spam landet oder gar nicht erst ankommt.
Hinzu kommt, dass viele Provider den lokalen Mailversand abgeschaltet haben und stattdessen einen authentifizierten SMTP-Relay erwarten. Genau hier kommen Bibliotheken wie PHPMailer oder der Symfony-Mailer ins Spiel. Sie sprechen sichekt SMTP, kümmern sich um TLS-Verbindungen, MIME-Strukturen, Anhänge und korrekt kodierte Header. Sie investieren einmalig fünf Minuten in die Konfiguration und sparen sich dafür jede Menge merkwürdige Zustellprobleme. Eine ausführliche Anleitung dazu finden Sie im Tutorial PHPMailer mit SMTP.
PHPMailer mit SMTP konfigurieren
Die Einrichtung von PHPMailer ist denkbar überschaubar. Sie installieren das Paket per Composer, laden die Klassen, übergeben Hostname, Port, Benutzer und Passwort Ihres SMTP-Servers und schickst die erste Testmail. Wichtig ist, dass Sie die Verbindung explizit verschlüsselst. Für Port 587 nutzen Sie STARTTLS, für Port 465 implizites SMTPS. Klartext-SMTP auf Port 25 hat heute keinen Platz mehr in produktivem Code.
<?php
declare(strict_types=1);
require 'vendor/autoload.php';
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;
$mail = new PHPMailer(true); /* true aktiviert Exceptions */
try {
$mail->isSMTP();
$mail->Host = 'smtp.example.com';
$mail->SMTPAuth = true;
$mail->Username = 'noreply@example.com';
$mail->Password = getenv('SMTP_PASSWORT') ?: '';
$mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;
$mail->Port = 587;
$mail->CharSet = PHPMailer::CHARSET_UTF8;
$mail->setFrom('noreply@example.com', 'Mein Shop');
$mail->addAddress('kunde@example.com', 'Lisa Beispiel');
$mail->Subject = 'Willkommen';
$mail->Body = 'Schoen, dass du dabei bist!';
$mail->send();
} catch (Exception $e) {
error_log('Mail fehlgeschlagen: ' . $mail->ErrorInfo);
}
Beachte, dass das Passwort niemals sichekt im Code stehen sollte. Legen Sie es in eine Umgebungsvariable, eine .env-Datei oder einen Secret-Manager. Wenn Sie den Versand testen, aktiviere mit $mail->SMTPDebug = SMTP::DEBUG_SERVER; kurzzeitig die Debug-Ausgabe.
HTML-Mail mit Plaintext-Fallback
Eine reine HTML-Mail ohne Textalternative ist ein Klassiker für den Spamfilter. Spam-Scoring-Systeme wie SpamAssassin werten jede Mail negativ, die keinen multipart/alternative-Part mit Klartext anbietet. Außerdem gibt es immer noch Clients, die HTML nicht oder nur eingeschränkt darstellen. Eine gute Mail enthält deshalb beides: eine sauber formatierte HTML-Variante und einen lesbaren Text-Fallback.
<?php
declare(strict_types=1);
$mail->isHTML(true);
$mail->Subject = 'Deine Rechnung ist da';
$mail->Body = '<h1>Hallo Lisa</h1>'
. '<p>deine Rechnung Nummer <strong>R-2026-042</strong> '
. 'liegt bereit.</p>';
$mail->AltBody = "Hallo Lisa,\n\n"
. "deine Rechnung R-2026-042 liegt bereit.\n";
Wenn Sie dynamische Inhalte einsetzen, denk an saubere Ausgabe. Alles, was vom Nutzer kommt, läuft im HTML-Body durch htmlspecialchars. Andernfalls riskierst Sie HTML-Injection.
Anhänge richtig mitsenden
Anhänge sind das klassische Beispiel dafür, warum man mail() heute meidet. Sie müsstest manuell MIME-Boundaries setzen, Base64 kodieren und die Header korrekt verschachteln. Mit PHPMailer reduziert sich das auf einen Methodenaufruf. Wichtig ist, dass Sie den MIME-Type sinnvoll setzen, damit der Mail-Client die Datei korrekt öffnet.
<?php
declare(strict_types=1);
/* Datei vom Server-Pfad anhaengen. */
$mail->addAttachment(
'/var/app/rechnungen/R-2026-042.pdf',
'rechnung_R-2026-042.pdf',
PHPMailer::ENCODING_BASE64,
'application/pdf'
);
/* Auch direkt aus einem String moeglich. */
$pdfBinary = generierePdf($rechnung);
$mail->addStringAttachment(
$pdfBinary,
'kassenbon.pdf',
PHPMailer::ENCODING_BASE64,
'application/pdf'
);
/* Inline-Bild fuer den HTML-Body, referenziert per cid: */
$mail->addEmbeddedImage(
'/var/app/img/logo.png',
'logo_cid',
'logo.png',
PHPMailer::ENCODING_BASE64,
'image/png'
);
$mail->Body = '<img src="cid:logo_cid" alt="Logo"> ...';
Achten Sie auf die Grösse. Viele Mailserver akzeptieren keine Nachrichten über 25 MB, einige limitieren sogar bei 10 MB. Wenn Sie grössere Dateien verschicken wollen, lade sie auf Ihren Server und versende stattdessen einen signierten Download-Link. Das ist sicherer, schneller und zustellfreundlicher.
Header korrekt setzen: From, Reply-To und Return-Path
Viele Zustellprobleme entstehen, weil Header falsch oder widersprüchlich gesetzen werden. Drei Felder solltest Sie immer bewusst einstellen. Der From-Header gehört zwingend zu einer Domain, über die Sie auch versenden dürfen. Setzt Sie dort eine fremde Adresse ein, schlägt SPF an und die Mail landet im Spam. Der Reply-To-Header steuert, wohin Antworten gehen sollen.
<?php
declare(strict_types=1);
$mail->setFrom('noreply@example.com', 'Mein Shop');
$mail->addReplyTo('support@example.com', 'Shop-Support');
/* Der Return-Path (Envelope-Sender) ist die Adresse,
an die Bounces gehen. */
$mail->Sender = 'bounces@example.com';
/* List-Unsubscribe Header fuer Newsletter. */
$mail->addCustomHeader(
'List-Unsubscribe',
'<mailto:unsubscribe@example.com>'
);
Der wichtigste Punkt: Setzen Sie niemals einen From-Header mit der Adresse Ihres Nutzers. Wenn Sie beispielsweise ein Kontaktformular hast und dort die E-Mail des Absenders sichekt als Absender einsetzen, ist das ein Spoofing-Klassiker, der Ihre Reputation zerstört. Die Nutzeradresse gehört in Reply-To, der From bleibt Ihre eigene, authentifizierte Domain.
SPF, DKIM und DMARC: Spamfilter freundlich stimmen
Auch wenn Ihr PHP-Code perfekt arbeitet, entscheidet am Ende der DNS Ihrer Domäne über Zustellung oder Spam-Ordner. Drei DNS-Einträge sind heute Standard und ohne sie wird es schwer. SPF (Sender Policy Framework) listet, welche Server überhaupt im Namen Ihrer Domäne versenden dürfen. DKIM (DomainKeys Identified Mail) signiert jede Mail kryptografisch, sodass der Empfänger prüfen kann, ob sie unterwegs manipuliert wurde. DMARC verbindet beides und sagt dem Empfänger, was er tun soll, wenn SPF oder DKIM versagen.
; SPF: nur dieser SMTP-Server darf fuer example.com versenden
example.com. IN TXT "v=spf1 ip4:203.0.113.42 -all"
; DKIM: Public Key fuer den Selector mail2026
mail2026._domainkey.example.com. IN TXT "v=DKIM1; k=rsa; p=MIIBIjANBgkq..."
; DMARC: Bei Fehlschlag in Quarantaene
_dmarc.example.com. IN TXT "v=DMARC1; p=quarantine; rua=mailto:dmarc@example.com"
Die DNS-Einträge selbst kommen aus dem Verwaltungsbereich Ihres Domain-Hosters oder Ihres E-Mail-Dienstleisters. PHP hat mit der Konfiguration nichts zu tun, wohl aber mit der Konsequenz: Wenn Sie SPF eng stellst und dann plötzlich aus Ihrem Webhoster heraus über dessen lokales Sendmail verschicken, schlägt SPF fehl und Ihre Mails verschwinden.
E-Mail-Versand-Flow: vom Skript bis zum Postfach
Damit die Aufgabenverteilung klar wird, hilft eine kompakte Visualisierung. Vom Moment an, in dem Ihre PHP-Anwendung das Senden anstösst, bis die Mail beim Empfänger im Posteingang liegt, sind mehrere Stationen beteiligt. Jede davon kann den Versand stoppen, weshalb Sie bei Problemen wissen solltest, wo Sie suchen müssen.
flowchart LR
A[PHP-Anwendung] --> B[PHPMailer]
B --> C[SMTP-Relay]
C --> D[Empfaenger-MX]
D --> E[Postfach]
Hakt es bei A oder B, sehen Sie das in Ihrem Application-Log oder über $mail->ErrorInfo. Probleme bei C, also dem SMTP-Relay, werden meist als 5xx-Fehler beim send()-Aufruf zurückgegeben. Bei D entscheidet der empfangende Mailserver anhand von SPF, DKIM und DMARC über Annahme oder Ablehnung. Bei E kommen schliesslich noch Spamfilter, Regeln und Ordnerzuweisungen ins Spiel.
Praxisbeispiel: Kontaktformular-Mailer mit PHPMailer
Zum Abschluss bauen Sie sich ein robustes Kontaktformular zusammen, das alle bisherigen Punkte berücksichtigt. Eingaben werden validiert, der From bleibt Ihre eigene Domain, die Nutzeradresse landet im Reply-To, und die Mail wird sowohl als HTML als auch als Klartext verschickt. Für die Validierung der E-Mail-Adresse setzen Sie auf filter_var. Für die Ausgabe im HTML-Body kommt htmlspecialchars zum Einsatz.
<?php
declare(strict_types=1);
require __DIR__ . '/vendor/autoload.php';
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception as MailerException;
/* 1. Eingaben einsammeln und trimmen. */
$name = trim((string)($_POST['name'] ?? ''));
$absend = trim((string)($_POST['email'] ?? ''));
$nachr = trim((string)($_POST['message'] ?? ''));
/* 2. Validierung. Bei Fehlern raus mit klarer Meldung. */
$fehler = [];
if ($name === '' || mb_strlen($name) > 100) {
$fehler[] = 'Name fehlt oder ist zu lang';
}
if (filter_var($absend, FILTER_VALIDATE_EMAIL) === false) {
$fehler[] = 'Ungueltige E-Mail-Adresse';
}
if (mb_strlen($nachr) < 10) {
$fehler[] = 'Nachricht ist zu kurz';
}
if ($fehler !== []) {
http_response_code(422);
echo implode(' / ', array_map('htmlspecialchars', $fehler));
exit;
}
/* 3. PHPMailer aufsetzen und Mail bauen. */
$mail = new PHPMailer(true);
try {
$mail->isSMTP();
$mail->Host = 'smtp.example.com';
$mail->SMTPAuth = true;
$mail->Username = 'noreply@example.com';
$mail->Password = getenv('SMTP_PASSWORT') ?: '';
$mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;
$mail->Port = 587;
$mail->CharSet = PHPMailer::CHARSET_UTF8;
/* From bleibt unsere Domain, Antworten gehen
an den echten Absender. */
$mail->setFrom('noreply@example.com', 'Kontaktformular');
$mail->addAddress('support@example.com', 'Support');
$mail->addReplyTo($absend, $name);
$mail->Subject = 'Neue Kontaktanfrage von ' . $name;
/* HTML mit escapeten Werten. */
$mail->isHTML(true);
$mail->Body =
'<h2>Neue Anfrage</h2>'
. '<p><strong>Name:</strong> '
. htmlspecialchars($name, ENT_QUOTES, 'UTF-8') . '</p>'
. '<p><strong>E-Mail:</strong> '
. htmlspecialchars($absend, ENT_QUOTES, 'UTF-8') . '</p>'
. '<p><strong>Nachricht:</strong><br>'
. nl2br(htmlspecialchars($nachr, ENT_QUOTES, 'UTF-8'))
. '</p>';
$mail->AltBody =
"Neue Anfrage\n"
. "Name: {$name}\n"
. "E-Mail: {$absend}\n\n"
. "Nachricht:\n{$nachr}\n";
$mail->send();
echo 'Vielen Dank, deine Nachricht ist unterwegs.';
} catch (MailerException $e) {
error_log('Kontaktformular: ' . $mail->ErrorInfo);
http_response_code(500);
echo 'Versand momentan nicht moeglich, bitte spaeter erneut versuchen.';
}
Mit diesem Skript haben Sie ein produktionstaugliches Kontaktformular. Es validiert die Eingaben mit filter_var, schützt vor HTML-Injection per htmlspecialchars, hält sich an die Header-Regeln und liefert sowohl HTML als auch Plaintext. Wenn Sie es noch weiter härten wollen, ergänze einen Honeypot oder ein Captcha gegen Bots, ein Rate-Limit pro IP und einen Token-Check gegen CSRF.
weiter zum nächsten Kapitel:
Grundlegende Konzepte und Strukturen von PHP Function
|