# Laravel ile e-posta gönderimi ve şablonları

> Laravel Mailable sınıfı ve Blade e-posta şablonları ile işlemsel e-postaları güvenilir ve bakımı kolay şekilde kurmak.

- Yayın: 2017-03-05
- Kategori: Web Geliştirme
- Etiketler: Laravel
- Okuma süresi: 3 dk okuma
- Kaynak: https://www.muhammetsafak.com.tr/blog/laravel-ile-e-posta-gonderimi-ve-sablonlari/
- Dil: tr-TR
- Yazar: Muhammet Şafak

---
İşlemsel e-posta (transactional email) — yani "kayıt oldunuz", "siparişiniz alındı", "şifrenizi sıfırlayın" gibi tetikleyiciye bağlı mesajlar — her web uygulamasının bir noktada ihtiyaç duyduğu şey. Ama "sadece bir e-posta gönder" diye başlayan iş, birkaç hafta sonra içinden çıkılmaz bir PHP `mail()` yığınına dönüşebiliyor.

Laravel 5.3'te tanıtılan **Mailable** sınıfları bu karmaşayı önemli ölçüde azalttı. E-posta gönderme mantığını ayrı bir sınıfa taşımak, hem testi kolaylaştırıyor hem de şablonları düzenli tutuyor.

## Mailable sınıfı oluşturmak

Artisan komutu işi hızlandırıyor:

```bash
php artisan make:mail OrderConfirmed
```

Bu komut `app/Mail/OrderConfirmed.php` dosyasını oluşturuyor. Temel yapı şöyle:

```php
namespace App\Mail;

use App\Order;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;

class OrderConfirmed extends Mailable
{
    use SerializesModels;

    public $order;

    public function __construct(Order $order)
    {
        $this->order = $order;
    }

    public function build()
    {
        return $this->subject('Siparişiniz Alındı')
                    ->view('emails.orders.confirmed');
    }
}
```

`$order` public olarak tanımlandığında şablon tarafında otomatik olarak erişilebilir oluyor — ekstra `with()` çağrısı gerekmiyor. Bu küçük konvansiyonu sevdim; veriyi sınıfın içine gömmek yerine açıkça görmek işlemi daha takip edilebilir kılıyor.

`SerializesModels` trait'i ise queue'ya alınan e-postalarda devreye giriyor: modelin tamamını serileştirmek yerine yalnızca kimliğini (ID) queue'ya yazıyor ve gönderim sırasında tazeliyor. Büyük model nesnelerini queue'da taşımanın neden sorun çıkardığını bu trait sayesinde erken fark ettim.

## Blade e-posta şablonu

`resources/views/emails/orders/confirmed.blade.php` şablonu normal [Blade şablonları](/blog/blade-sablon-motoru-tekrar-eden-htmli-bitirmek) gibi yazılıyor:

```blade
<!DOCTYPE html>
<html>
<body>
    <h1>Siparişiniz Alındı</h1>
    <p>Sayın {{ $order->user->name }},</p>
    <p>
        #{{ $order->id }} numaralı siparişiniz alınmıştır.
        Toplam tutar: {{ number_format($order->total, 2) }} TL
    </p>
    <p>Siparişinizin detaylarını hesabınızdan takip edebilirsiniz.</p>
</body>
</html>
```

E-posta şablonlarında `@extends` ve `@section` kullanmak mümkün, dolayısıyla ortak bir e-posta layout'u oluşturup tüm mesajlarda paylaşabilirsiniz. Başlık, altbilgi ve marka renklerini tek bir yerde tutmak büyük kolaylık.

Bir detay: e-posta istemcileri (özellikle eski Outlook sürümleri) harici CSS dosyalarını görmezden gelebiliyor. Bu yüzden e-posta şablonlarında stilleri satır içi (`style="..."`) yazmak ya da `premailer` gibi bir araçla derleme aşamasında satır içine çevirmek gerekiyor. Markdown Mailable bunu kısmen çözüyor; yerleşik şablonlar zaten inline stil kullanıyor.

## Gönderme

Controller'dan göndermek tek satır:

```php
Mail::to($order->user)->send(new OrderConfirmed($order));
```

Queue'ya ekleyerek göndermek içinse:

```php
Mail::to($order->user)->queue(new OrderConfirmed($order));
```

Queue ile gönderim kullanıcıya anında yanıt dönmesi için önemli; e-posta sunucusu yavaş yanıt verdiğinde HTTP isteğini bekletmiyor. Özellikle SMTP üzerinden gönderilen e-postalarda sunucu bağlantısı bazen birkaç saniyeye uzayabiliyor — bu gecikmeyi kullanıcı hissettirmemek için queue neredeyse zorunlu hale geliyor.

`Mail::to()` dışında `cc()` ve `bcc()` zincirlenebiliyor; birden fazla alıcıya ya da gizli kopyayla göndermek için ayrı bir yöntem aramak gerekmiyor.

## Yapılandırma ve ortam farkı

`.env` dosyasından sürücü seçmek mümkün: `smtp`, `mailgun`, `sendmail`, `log`... Geliştirme ortamında `log` sürücüsünü kullanıyorum; e-postalar `storage/logs/laravel.log` dosyasına yazılıyor, gerçek bir e-posta gönderilmiyor. Üretim ortamında ise SMTP yapılandırması geçerli.

```
MAIL_DRIVER=smtp
MAIL_HOST=smtp.mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=...
MAIL_PASSWORD=...
MAIL_FROM_ADDRESS=noreply@example.com
MAIL_FROM_NAME="Uygulama Adı"
```

Mailtrap gibi bir test aracını geliştirme sürecine erken eklemek, gerçek kullanıcılara yanlışlıkla e-posta atmayı önlüyor. Bunu bir kez yaşadım: yerel geliştirme ortamında gerçek SMTP ayarları kalınca, bir test sırasında gerçek kullanıcılara sipariş onay e-postası gönderildi. O günden beri `log` sürücüsü geliştirme ortamının standart parçası.

## Markdown Mailable

Laravel 5.4 ile gelen Markdown Mailable özelliği, HTML ve düz metin sürümlerini aynı anda oluşturuyor. Yerleşik şablonlar var; `mail::message`, `mail::button` gibi bileşenler. Her şirkete özel tasarım gerekmiyorsa bu şablonlar temiz ve hızlı bir başlangıç noktası sunuyor.

```php
return $this->subject('Siparişiniz Alındı')
            ->markdown('emails.orders.confirmed-markdown');
```

Markdown Mailable'ın bir avantajı daha var: `vendor:publish` komutuyla yerleşik şablonları projeye kopyalayabiliyorsunuz ve yalnızca HTML/CSS'i değiştirerek markaya uygun hale getiriyorsunuz. Tüm şablonları sıfırdan yazmak yerine var olan temeli özelleştirmek zaman kazandırıyor.

## Birden fazla e-posta türü yönetmek

Proje büyüdükçe e-posta türleri çoğalıyor: kayıt onayı, şifre sıfırlama, sipariş bildirimi, fatura... Her biri için ayrı bir Mailable sınıfı ve ayrı bir Blade şablonu olduğunda `app/Mail/` klasörü hızla şekilleniyor. Bu yapı dağınık görünse de her e-posta türünü bağımsız olarak değiştirebilmek büyük esneklik sağlıyor. Tek bir `sendEmail($type, $data)` fonksiyonu yerine her türün kendi sınıfı olması, ileride bir e-postanın şablonunu ya da konu satırını değiştirirken diğerlerini etkilemeden yapabilmenizi sağlıyor.

E-posta gönderimini Mailable sınıflarıyla yapılandırmak, projenin büyümesiyle birlikte gerçekten ödemesini yapıyor. Dağınık `mail()` çağrıları yerine her mesaj türü için bir sınıf, gönderilen e-postaların neyin ne zaman gittiğini takip etmeyi kolaylaştırıyor.
