PHP ile Otomatik E-Posta Gönderim Kuyruğu Nasıl Yapılır?
Modern web uygulamalarında e-posta gönderimi, kullanıcı deneyimi açısından kritik bir öneme sahiptir. Ancak, bir kullanıcı form gönderdiğinde veya bir işlem yaptığında doğrudan e-posta göndermek, sunucunun yanıt süresini uzatır ve sistemin yavaşlamasına neden olur. PHP ile otomatik e-posta gönderim kuyruğu oluşturmak, bu işlemi arka plana atarak uygulamanızın performansını artırmanın en profesyonel yoludur.
Bu rehberde, bir veritabanı tablosunu "kuyruk" (queue) olarak kullanarak, e-postaları nasıl sıraya alacağınızı ve bir "cron job" (zamanlanmış görev) yardımıyla bu e-postaları nasıl otomatik göndereceğinizi adım adım öğreneceksiniz. Bu yöntem, özellikle yüksek trafikli uygulamalarda sunucu yükünü dengelemek için standart bir yaklaşımdır.
Gereksinimler ve Ön Hazırlık
Bu sistemi kurabilmek için sunucunuzda aşağıdaki araçların ve yetkilerin bulunması gerekmektedir. PHP 8.2 veya daha güncel bir sürüm kullanmanız, performans ve güvenlik açısından 2026 standartlarına uygun olacaktır.
- PHP 8.2+: Güncel sözdizimi ve performans iyileştirmeleri için gereklidir.
- MySQL/MariaDB: E-posta kuyruğunu tutacağımız veritabanı sistemi.
- SMTP Erişimi: E-postaların güvenilir bir şekilde gönderilmesi için bir SMTP sunucusu (Mailtrap, SendGrid veya kendi SMTP sunucunuz).
- Cron Job Yetkisi: Arka plan süreçlerini tetiklemek için sunucunuzda zamanlanmış görev tanımlama yetkisi.
Adım 1: E-posta Kuyruğu Veritabanı Yapısını Oluşturma
E-postaları saklamak için bir veritabanı tablosuna ihtiyacımız var. Bu tablo, e-postanın alıcısını, konusunu, içeriğini ve gönderim durumunu takip edecektir. Aşağıdaki SQL sorgusu, temel bir kuyruk yapısı için gerekli olan tabloyu oluşturur.
CREATE TABLE email_queue (
id INT AUTO_INCREMENT PRIMARY KEY,
recipient_email VARCHAR(255) NOT NULL,
subject VARCHAR(255) NOT NULL,
body TEXT NOT NULL,
status ENUM('pending', 'sent', 'failed') DEFAULT 'pending',
attempts INT DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
Bu tablo yapısında status alanı, e-postanın gönderilip gönderilmediğini izlememizi sağlar. attempts sütunu ise, gönderim başarısız olursa kaç kez denendiğini takip etmek için kullanılır.
Adım 2: E-postaları Kuyruğa Ekleme
Kullanıcı bir işlem yaptığında, e-postayı doğrudan göndermek yerine veritabanına bir kayıt ekliyoruz. Bu işlem, uygulamanın bekleme süresini milisaniyelere indirir.
// Veritabanı bağlantısı (PDO kullanımı önerilir)
$pdo = new PDO('mysql:host=localhost;dbname=uygulama', 'kullanici', 'sifre');
function kuyrugaEkle($pdo, $email, $konu, $icerik) {
$sql = "INSERT INTO email_queue (recipient_email, subject, body) VALUES (?, ?, ?)";
$stmt = $pdo->prepare($sql);
$stmt->execute([$email, $konu, $icerik]);
}
// Kullanım örneği
kuyrugaEkle($pdo, 'kullanici@example.com', 'Hoş Geldiniz!', 'Sitemize kayıt olduğunuz için teşekkürler.');
Burada PDO kullanarak hazırlanan ifadeler (prepared statements) ile SQL Injection saldırılarına karşı önlem alıyoruz. Kullanıcıdan gelen veriyi doğrudan sorguya dahil etmemek, güvenlik için en temel kuraldır.
Adım 3: Kuyruktaki E-postaları Gönderen Betiği Yazma
Kuyruğa alınan e-postaları işlemek için bir PHP dosyası oluşturmalıyız. Bu dosya, veritabanındaki pending (bekleyen) durumundaki kayıtları çekecek ve bir e-posta kütüphanesi (PHPMailer gibi) kullanarak gönderecektir.
// worker.php
$pendingEmails = $pdo->query("SELECT * FROM email_queue WHERE status = 'pending' LIMIT 10");
foreach ($pendingEmails as $row) {
try {
// Burada PHPMailer veya benzeri bir kütüphane kullanmalısınız
$gonderimBasarili = mail($row['recipient_email'], $row['subject'], $row['body']);
if ($gonderimBasarili) {
$pdo->prepare("UPDATE email_queue SET status = 'sent' WHERE id = ?")->execute([$row['id']]);
}
} catch (Exception $e) {
$pdo->prepare("UPDATE email_queue SET attempts = attempts + 1 WHERE id = ?")->execute([$row['id']]);
}
}
Bu betik, her çalıştırıldığında en fazla 10 adet e-postayı işler. Bu limit, sunucu kaynaklarını korumak için önemlidir.
Adım 4: Cron Job ile Otomasyonu Sağlama
worker.php dosyasının sürekli çalışması için sunucunuzda bir cron job tanımlamanız gerekir. Bu, her dakika çalışan bir zamanlayıcıdır.
# Terminal üzerinden crontab -e komutu ile ekleyin:
* * * * * /usr/bin/php /var/www/html/worker.php > /dev/null 2>&1
Bu komut, sunucunun her dakika worker.php dosyasını tetiklemesini sağlar. Çıktıyı /dev/null adresine yönlendirerek gereksiz log dosyalarının birikmesini engelliyoruz.
E-posta Gönderim Yöntemlerinin Karşılaştırılması
| Yöntem | Avantaj | Dezavantaj |
|---|---|---|
| Doğrudan Gönderim | Basit, anlık | Yavaş, sunucu yükü yüksek |
| Veritabanı Kuyruğu | Güvenli, izlenebilir | Ek veritabanı yükü |
| Redis/RabbitMQ | Çok hızlı, ölçeklenebilir | Karmaşık kurulum |
Kritik Güvenlik Uyarısı: E-posta gönderiminde asla kullanıcıdan gelen veriyi filtrelenmemiş şekilde e-posta başlıklarına (header) eklemeyin. Bu, "Email Header Injection" saldırılarına yol açabilir. PHPMailer gibi güncel kütüphaneler bu konuda otomatik koruma sağlar.
Sıkça Sorulan Sorular
E-postalar neden "failed" durumuna düşer?
Genellikle SMTP sunucusu bağlantı hataları, geçersiz e-posta adresleri veya sunucunun spam filtrelerine takılması nedeniyle başarısız olur. attempts sütununu kontrol ederek hata sayısını takip edebilirsiniz.
Kuyrukta çok fazla e-posta birikirse ne yapmalıyım?
Eğer kuyruk çok hızlı doluyorsa, LIMIT 10 değerini artırabilir veya daha sık çalışan (örneğin her 30 saniyede bir) bir cron job tanımlayabilirsiniz.
PHPMailer kullanmak zorunda mıyım?
PHP'nin yerleşik mail() fonksiyonu genellikle güvenilir değildir ve spam olarak işaretlenme riski yüksektir. Profesyonel projelerde her zaman PHPMailer veya Symfony Mailer gibi kütüphaneler önerilir.
Veritabanı tablosunu temizlemeli miyim?
Evet, gönderilmiş (sent) e-postaları belirli bir süre sonra (örneğin 30 gün) silen bir temizleme betiği yazmanız veritabanınızın şişmesini engeller.
Bu yöntemle aynı anda kaç e-posta gönderebilirim?
Sunucunuzun işlemci gücüne ve SMTP servis sağlayıcınızın (SendGrid, Mailgun vb.) günlük gönderim limitlerine bağlıdır. Büyük ölçekli gönderimler için mutlaka profesyonel bir SMTP servisi kullanın.
Sorumluluk Reddi: Yukarıdaki kod örnekleri eğitim amaçlıdır. Üretim ortamında (production) kullanmadan önce hata yakalama mekanizmalarını (try-catch blokları) genişletmeli ve veritabanı bağlantı bilgilerini çevresel değişkenlerde (env dosyaları) saklamalısınız.
Kuyruk Yönetiminde Performans Optimizasyonu
E-posta kuyruğunuz büyüdükçe, veritabanı sorgularının verimliliği sistemin genel sağlığı için kritik hale gelir. Binlerce e-postanın bulunduğu bir tabloda, status = 'pending' olan kayıtları çekmek için indeksleme kullanmamak, sunucunuzun CPU kullanımını gereksiz yere artıracaktır.
Veritabanı performansını artırmak için email_queue tablonuzda mutlaka bir indeks oluşturmalısınız:
ALTER TABLE email_queue ADD INDEX idx_status_priority (status, priority);
Ayrıca, her cron çalıştırmasında tüm kuyruğu işlemek yerine, e-postaları "toplu" (batch) olarak işlemek daha güvenlidir. Örneğin, her seferinde sadece 50 e-posta gönderen bir yapı kurmak, scriptin zaman aşımına (timeout) uğramasını engeller.
Gelişmiş Hata Ayıklama ve Loglama Stratejileri
Kuyruk sistemlerinde en sık karşılaşılan sorun, gönderilemeyen e-postaların neden başarısız olduğunun takip edilememesidir. Sadece "failed" durumunu kaydetmek yeterli değildir; hatanın nedenini (SMTP bağlantı hatası, geçersiz adres, kota aşımı) mutlaka veritabanında saklamalısınız.
Aşağıdaki örnek, hata yakalama mekanizmasını nasıl genişletebileceğinizi göstermektedir:
try {
$mail->send();
$db->query("UPDATE email_queue SET status = 'sent', sent_at = NOW() WHERE id = " . $row['id']);
} catch (Exception $e) {
$errorMessage = $mail->ErrorInfo;
$db->prepare("UPDATE email_queue SET status = 'failed', error_log = ?, retry_count = retry_count + 1 WHERE id = ?")
->execute([$errorMessage, $row['id']]);
// Hataları bir log dosyasına da yazabilirsiniz
error_log("E-posta gönderimi başarısız: " . $errorMessage);
}
Bu yapı sayesinde, retry_count sütununu kullanarak belirli bir hata sayısına ulaşan e-postaları sistemden tamamen çıkarabilir veya manuel inceleme için işaretleyebilirsiniz.
Kuyruk İşlemlerinde "Dead Letter Queue" Mantığı
Sürekli başarısız olan e-postalar kuyruğu tıkayabilir. Bu durumun önüne geçmek için "Dead Letter Queue" (Ölü Mektup Kuyruğu) yaklaşımını benimseyebilirsiniz. 3 veya 5 kez denendiği halde gönderilemeyen e-postaları farklı bir tabloya taşıyarak, ana kuyruğunuzun her zaman hızlı ve temiz kalmasını sağlayabilirsiniz.
| Strateji | Avantajı | Kullanım Amacı |
|---|---|---|
| Batch Processing | Sunucu yükünü dengeler | Yüksek hacimli gönderimler |
| Index Optimization | Sorgu hızını artırır | Hızlı kuyruk taraması |
| Retry Logic | Geçici hataları tolere eder | Bağlantı kopmaları |
Sonuç
PHP ile otomatik e-posta gönderim kuyruğu kurmak, uygulamanızın profesyonelliğini ve performansını doğrudan etkileyen temel bir beceridir. Bu yapıyı kurarak, kullanıcılarınızın bekleme süresini azaltmış ve e-posta gönderim süreçlerinizi daha yönetilebilir hale getirmiş olursunuz. Bir sonraki adım olarak, e-posta gönderim hatalarını loglayan bir sistem geliştirebilir veya kuyruk işlemleri için Redis gibi bellek tabanlı teknolojileri araştırmaya başlayabilirsiniz.


Yorumlar (0)
Yorum Yaz