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.
İş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:
php artisan make:mail OrderConfirmed
Bu komut app/Mail/OrderConfirmed.php dosyasını oluşturuyor. Temel yapı şöyle:
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ı gibi yazılıyor:
<!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:
Mail::to($order->user)->send(new OrderConfirmed($order));
Queue’ya ekleyerek göndermek içinse:
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=...
[email protected]
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.
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.