aslain.dev
0%
01 Hizmetler 02 Hakkımda 03 Projeler 04 Stack 05 Blog 06 İletişim
← Tüm makaleler Webentwicklung

Laravel Mail und Notifications: E-Mails richtig senden

Ein Anmeldeformular, eine Bestellbestätigung, ein Link zum Zurücksetzen des Passworts… nahezu jeder Ablauf in einer modernen Anwendung hat mit E-Mail zu tun. Die Laravel-mail-Schicht macht das deutlich weniger einschüchternd, als man erwarten könnte: Mailable-Klassen stehen für eine einzelne E-Mail, während Notification-Klassen es erlauben, dieselbe Nachricht gleichzeitig über mehrere Kanäle zuzustellen, etwa Mail, die Datenbank und Slack. In diesem Leitfaden gehen wir durch, wann man was einsetzt, wie man Templates gestaltet und wie man die Zustellung zuverlässig macht.

SMTP konfigurieren und einen Treiber wählen

Alles beginnt in config/mail.php und .env. Laravel unterstützt Treiber wie SMTP, Amazon SES, Postmark, Mailgun und log. Während der Entwicklung schreibt der log-Treiber Nachrichten nach storage/logs/laravel.log, sodass man die Ausgabe prüfen kann, ohne echte Mails zu versenden.

MAIL_MAILER=smtp
MAIL_HOST=smtp.mailgun.org
MAIL_PORT=587
MAIL_USERNAME=postmaster@example.com
MAIL_PASSWORD=secret
MAIL_ENCRYPTION=tls
MAIL_FROM_ADDRESS="hello@example.com"
MAIL_FROM_NAME="${APP_NAME}"

Für lokale Tests ist ein Tool wie Mailpit oder Mailtrap unverzichtbar: Jede ausgehende E-Mail wird in einem Web-Posteingang abgefangen und nichts erreicht echte Nutzer.

Dein erstes Mailable

Erzeuge mit Artisan eine Klasse, die eine einzelne E-Mail repräsentiert. Die Option --markdown erstellt ein fertiges Template:

php artisan make:mail OrderShipped --markdown=mail.orders.shipped

Seit Laravel 9 ist das Mailable in drei Methoden aufgeteilt: envelope() (Betreff, Absender), content() (View und Daten) und attachments(). Das Ergebnis ist klar und gut lesbar:

class OrderShipped extends Mailable
{
    use Queueable, SerializesModels;

    public function __construct(public Order $order) {}

    public function envelope(): Envelope
    {
        return new Envelope(
            subject: 'Deine Bestellung ist unterwegs',
        );
    }

    public function content(): Content
    {
        return new Content(
            markdown: 'mail.orders.shipped',
            with: ['order' => $this->order],
        );
    }
}

Zum Versenden genügt die Mail-Facade:

use Illuminate\Support\Facades\Mail;

Mail::to($order->user)->send(new OrderShipped($order));

Gestaltung mit Markdown-Templates

Markdown-Mailables nutzen die vorgefertigten Komponenten von Laravel und rendern automatisch sowohl eine HTML- als auch eine Klartextversion. Das Template kommt mit einem sauberen, responsiven Design:

<x-mail::message>
# Hallo {{ $order->user->name }}

Deine Bestellung ({{ $order->number }}) wurde versandt.

<x-mail::button :url="$url">
Bestellung ansehen
</x-mail::button>

Danke,<br>
{{ config('app.name') }}
</x-mail::message>

Um das Design an deine Marke anzupassen, führe php artisan vendor:publish --tag=laravel-mail aus, um die Komponenten und die Datei resources/css/mail.css zu veröffentlichen. Dort passt du Farben, das Logo und die Fußzeile an.

Mehrkanal-Zustellung mit Notifications

Wenn du dasselbe Ereignis über mehr als einen Kanal ankündigen willst, übernimmt Notification. Wird etwa eine Rechnung bezahlt, möchtest du vielleicht eine E-Mail senden und zugleich einen Eintrag in der Datenbank speichern.

php artisan make:notification InvoicePaid
class InvoicePaid extends Notification
{
    use Queueable;

    public function __construct(public Invoice $invoice) {}

    public function via(object $notifiable): array
    {
        return ['mail', 'database'];
    }

    public function toMail(object $notifiable): MailMessage
    {
        return (new MailMessage)
            ->subject('Deine Rechnung wurde bezahlt')
            ->greeting('Hallo!')
            ->line('Deine Rechnung über '.$this->invoice->amount.' wurde bezahlt.')
            ->action('Rechnung ansehen', url('/invoices/'.$this->invoice->id))
            ->line('Vielen Dank.');
    }

    public function toArray(object $notifiable): array
    {
        return ['invoice_id' => $this->invoice->id];
    }
}

Verwendet dein Modell den Notifiable-Trait, ist der Versand eine einzige Zeile:

$user->notify(new InvoicePaid($invoice));

Nutzt du den database-Kanal in via(), vergiss nicht, die Tabelle mit php artisan make:notifications-table anzulegen. Neben offiziellen Kanälen wie Slack, SMS (Vonage) und Broadcast fügen Community-Pakete Telegram oder WhatsApp hinzu.

Queueing und Fehlerbehandlung

E-Mail-Versand ist langsam; lass den Nutzer nicht auf eine SMTP-Antwort warten. Das Implementieren der Schnittstelle ShouldQueue stellt die Mail oder Notification automatisch in die Warteschlange:

class OrderShipped extends Mailable implements ShouldQueue
{
    use Queueable, SerializesModels;
    // ...
}

Für den Betrieb der Warteschlange wird ein Worker benötigt: php artisan queue:work. Halte ihn in der Produktion mit Supervisor am Laufen. Fehlgeschlagene Jobs landen in der Tabelle failed_jobs und lassen sich mit php artisan queue:retry erneut ausführen. Für vorübergehende SMTP-Fehler kannst du $tries und eine backoff()-Methode auf dem Mailable definieren, um die Intervalle für erneute Versuche zu steuern.

Testen

Du brauchst kein echtes SMTP, um den Versand zu testen. Mail::fake() fängt die Zustellung ab, sodass du sie prüfen kannst:

Mail::fake();

// ... die Bestellung verarbeiten ...

Mail::assertSent(OrderShipped::class, function ($mail) use ($order) {
    return $mail->order->id === $order->id;
});

Ebenso erlauben Notification::fake() und Notification::assertSentTo() das Testen von Notifications. Dieser Ansatz hält deine Tests schnell und unabhängig von externen Diensten.

Häufige Fragen

Sollte ich ein Mailable oder eine Notification verwenden?

Versendest du eine reichhaltige, individuell gestaltete Nachricht über einen einzigen Kanal (nur E-Mail), reicht ein Mailable. Möchtest du dasselbe Ereignis über mehrere Kanäle zustellen (Mail + Datenbank + Slack) oder den Nutzer seine Kanäle wählen lassen, passt eine Notification besser.

Warum werden meine E-Mails verspätet oder gar nicht versendet?

Die häufigste Ursache ist die Verwendung von ShouldQueue, ohne einen Worker zu betreiben. Prüfe, ob queue:work läuft, sieh in der Tabelle failed_jobs und in storage/logs nach und überprüfe deine SMTP-Zugangsdaten und Port-Einstellungen.

Wie verhindere ich, dass HTML-E-Mails im Spam landen?

Eine verifizierte Versanddomain, SPF/DKIM/DMARC-Einträge und eine Klartext-Alternative liefern die zuverlässigsten Ergebnisse. Markdown-Mailables erzeugen die Klartextversion bereits; bevorzuge außerdem einen Anbieter mit gutem Ruf wie SES, Postmark oder Mailgun.

Möchtest du deinen E-Mail-Ablauf von Grund auf aufbauen oder ein bestehendes Benachrichtigungssystem aufräumen? Lass uns den Laravel-mail- und Notification-Stack rund um deine Anforderungen gestalten. Kontaktiere mich.

Bu kategorideki tüm yazılar →

Devamı için