rspamd kurulumlarında en sık gördüğüm sessiz arıza şu: Bayes haftalardır "kurulu", ama rspamc stat çıktısında learns: 0 yazıyor. Yani sınıflandırıcı metascore'a hiç dokunmuyor; spam kararlarınız tamamen SPF/DKIM/DMARC ve statik kurallardan geliyor. SpamAssassin'in aksine rspamd Bayes'i varsayılan olarak sıfırdan başlar ve her iki sınıfta da min_learns eşiğine ulaşılana kadar tek bir puan bile üretmez. Kurdunuz sanıyorsunuz, aslında ölü.
İkinci klasik hata daha sinsi: bir tutorial'dan autolearn bloğunu kopyalayıp sınıflandırıcının kendi kararıyla kendini eğitmesine izin vermek. Bu, birkaç hafta içinde bir geri besleme döngüsü (echo chamber) yaratır — Bayes kendi hatalarını "doğru" olarak pekiştirir, ham tarafına kayar, spam sızmaya başlar.
Bayes'in değeri learn_spam komutunda değil. Değer iki yerde: korpus dengesinde ve autolearn eşiklerinin disiplininde. Sırasıyla gidelim: backend, dengeli korpus, güvenli otomatik öğrenme, kullanıcıdan öğrenme, doğrulama ve zehirlenmeyi geri alma.
Bayes rspamd'da nasıl puanlanır (ve çoğu kurulum neden sessizce ölü)
rspamd gelen mesajı OSB (Orthogonal Sparse Bigrams) tokenizer'ıyla token'lara böler. Her token için iki statfile'da — BAYES_SPAM ve BAYES_HAM — o token'ın kaç spam ve kaç ham mesajda görüldüğü tutulur. Klasik naive Bayes'ten farkı, tek tek kelimeler yerine kelime çiftlerine (bigram) bakmasıdır; bu, "ücretsiz" gibi tek bir kelimenin yanıltmasını azaltır.
Sınıflandırma anında bu token istatistikleri birleştirilip mesajın spam olma olasılığı (0..1) hesaplanır. Bu olasılık statik değil dinamik bir puana çevrilir: 0.5 civarı nötr, 1'e yakın güçlü BAYES_SPAM, 0'a yakın güçlü BAYES_HAM. Yani Bayes metascore'a sabit değil, güvenine göre değişen bir katkı yapar.
Kritik nokta min_learns. Her iki statfile'da da bu eşiğe (rspamd'nin varsayılanı: 200 örnek) ulaşılmadan BAYES_* sembolü hiç ateşlenmez. Bu bir bug değil, tasarım: 40 örnekle eğitilmiş bir Bayes güvenilmezdir ve iyi niyetli postaları yanlışlıkla spam'a atar. rspamd, istatistiksel olarak anlamlı örneğe ulaşana kadar susmayı tercih eder. Bu yüzden learns: 0 gördüğünüzde panik yapmadan önce bilin: 199 öğrenimde bile sembol görünmez.
İki mimari kararı en baştan doğru vermeniz gerekir, çünkü geri dönüşü zordur:
- Backend seçimi. Eski SQLite backend artık deprecated. Tek kullanıcılı bir test kutusunda bile kilitlenme (lock contention) yaşatır ve ölçeklenmez. 2026'da tek doğru cevap Redis.
- per-user vs shared (site geneli) istatistik. per-user'da her kullanıcının kendi Bayes'i olur; küçük/orta bir mail sunucusunda bu, her kullanıcının ayrı ayrı 200 örneğe ulaşması demektir — pratikte hiçbir zaman ateşlenmez. Site geneli (shared) istatistik tüm trafiği tek havuzda toplar ve çok daha hızlı eşiğe ulaşır. evilmail.pro gibi çok sayıda düşük hacimli kutuya sahip bir altyapıda shared tek makul seçimdir. Bu kararı en başta verin; sonradan değiştirmek istatistikleri sıfırlamak demektir.
Redis backend ve sınıflandırıcının temel yapılandırması
Önce ortak Redis'i tanımlayın. /etc/rspamd/local.d/redis.conf tüm modüller (Bayes, ratelimit, greylist) için paylaşılan bağlantıdır:
# /etc/rspamd/local.d/redis.conf
servers = "127.0.0.1:6379";
# parola varsa:
# password = "…";Asıl iş /etc/rspamd/local.d/classifier-bayes.conf dosyasında. Bu, sınıflandırıcının tüm davranışını belirler:
# /etc/rspamd/local.d/classifier-bayes.conf
classifier "bayes" {
tokenizer { name = "osb"; }
backend = "redis"; # servers redis.conf'tan gelir
new_schema = true; # yeni depolama şeması — mutlaka açık
expire = 8640000; # ~100 gün; eski token'lar düşer
min_tokens = 11; # çok kısa mesajları Bayes'ten muaf tut
min_learns = 200; # bu eşiğe kadar BAYES_* ateşlenmez
cache { } # öğrenme önbelleği; Redis'i redis.conf'tan alır
# aynı mesajın iki kez öğrenilmesini engeller
statfile { symbol = "BAYES_SPAM"; spam = true; }
statfile { symbol = "BAYES_HAM"; spam = false; }
autolearn {
spam_threshold = 6.0; # reject eşiğinin ALTINDA, gri bölgeden uzak
ham_threshold = -0.5; # tam 0 DEĞİL
check_balance = true;
min_balance = 0.9; # sınıflar arası denge zorunluluğu
}
}Birkaç satırın altını çizeyim. new_schema = true yeni kurulumlarda şart; eski şema token başına ayrı Redis key kullanır ve bellek israfıdır. expire = 8640000 yaklaşık 100 gündür — spam kalıpları değişir, üç ay önce öğrendiğiniz bir kampanyanın token'larının süresiz kalması bias yaratır. min_tokens = 11, "toplantı 15:00" tarzı iki kelimelik mesajların Bayes'i kirletmesini önler. Öğrenme önbelleği (cache bloğu) özellikle IMAPSieve ile öğreniyorsanız kritiktir; bir kullanıcı mesajı Junk'a atıp geri alırsa aynı mesaj iki kez sayılmasın.
Değiştirdikten sonra:
systemctl reload rspamd
rspamc stat | grep -A3 "Statfile"Dengeli korpus: eğitimin gerçekten belirleyici kısmı
İşte çoğu rehberin atladığı ve sonucu belirleyen kısım. Bayes'in matematiği spam ve ham örnek sayısının kabaca 1:1 olmasını varsayar. Korpusunuz 5000 spam, 300 ham ise sınıflandırıcı "her şey biraz spam" demeye meyleder; tersine 5000 ham, 300 spam ise gerçek spam'ı ham diye geçirir. check_balance ve min_balance = 0.9, sınıflar arası oranın 0.9'un altına düşmesini tam olarak bunun için engeller — ama bu yalnızca autolearn'ü frenler; manuel bootstrap dengesini siz kurmalısınız.
Ham'ı nereden topladığınız kritik. Sadece newsletter'lar değil — gerçek işlemsel ve kişisel posta: fatura bildirimleri, parola sıfırlama mailleri, gerçek yazışmalar. evilmail.pro gibi temp-email trafiğinde bu özellikle önemli, çünkü ham'ın büyük kısmı otomatik/işlemsel mesajlardan oluşur; korpusu elle dengelemezseniz Bayes sürekli ham tarafına kayar ve gerçek spam'ı yakalayamaz hale gelir. Spam tarafını ise karantina, honeypot adresleri ve kullanıcı şikayetlerinden besleyin.
Maildir üzerinde toplu bootstrap:
# Junk klasörlerindeki her şeyi spam olarak öğret
find /var/mail/vhosts/*/*/Maildir/.Junk/{cur,new} -type f 2>/dev/null \
| xargs -r -n 50 rspamc learn_spam
# INBOX'taki temiz postayı ham olarak öğret (dikkat: Junk KARIŞMASIN)
find /var/mail/vhosts/*/*/Maildir/{cur,new} -type f 2>/dev/null \
| xargs -r -n 50 rspamc learn_ham
# Öğrenim sayaçlarını doğrula — her iki sınıf da 200'ü GEÇMELİ
rspamc stat | grep -E "BAYES_(SPAM|HAM)|learned"İki uyarı, tecrübeyle sabit:
- GTUBE test string'iyle Bayes eğitmeyin. GTUBE sentetik bir imzadır, gerçek spam token dağılımını temsil etmez; korpusa sahte sinyal enjekte eder.
- Bayes bir mesajı yanlış sınıflandırdığında o mesajı doğru sınıfa yeniden öğretin (relearn). Öğrenme önbelleği sayesinde rspamd önceki öğrenimi geri alıp yenisini uygular. False-positive'lerinizi ham olarak geri beslemek, korpus hijyeninin en değerli parçasıdır.
Otomatik öğrenmeyi güvenli eşiklerle açmak
autolearn'ü ancak manuel bootstrap'tan sonra ve izlemeyle açın. Mantığı basit: bir mesajın metascore'u spam_threshold'un üstündeyse otomatik spam öğren, ham_threshold'un altındaysa otomatik ham öğren. Tehlike de tam burada — eşikleri yanlış koyarsanız sınıflandırıcı kendi belirsiz kararlarıyla kendini eğitir ve hata pekişir.
İki kural pazarlığa kapalı:
- `ham_threshold`'u tam 0 yapmayın, hafif negatif tutun (−0.5). Puanı 0 olan bir mesaj "nötr"dür; ham olduğu kesin değildir. Onu ham diye öğretirseniz nötr token'ları ham'a kaydırır ve spam'ın nötr bölgeye sızmasını kolaylaştırırsınız.
- `spam_threshold`'u reject/greylisting eşiğinin altında AMA gri bölgeden uzak tutun. Reject eşiğiniz 15 ise, spam_threshold'u 6.0 civarında tutmak "zaten güçlü spam olan"ı öğretir. 15'e koyarsanız yalnızca aşırı bariz spam'ı öğrenir (gereksiz); 2'ye koyarsanız kararsız mesajları öğrenip echo chamber'a girersiniz.
Aradaki geniş bant — "gri bölge" — kasıtlı olarak öğrenilmez. Bayes'in belirsiz olduğu yerden öğrenmesi, belirsizliği kendi kendine gerçeğe dönüştürmesi demektir.
Dovecot IMAPSieve ile kullanıcı davranışından öğrenme
En temiz, en sürekli ve insan etiketli sinyal budur: kullanıcı bir mesajı Junk'a taşıdığında bu spam'dir, Junk'tan çıkardığında ham'dır. autolearn'ün tahmin ettiği şeyi burada insan onaylar. Dovecot'un imap_sieve eklentisiyle bu hareketleri rspamc learn_* çağrısına bağlarsınız.
/etc/dovecot/conf.d/90-plugin.conf içinde mapping:
plugin {
sieve_plugins = sieve_imapsieve sieve_extprograms
sieve_pipe_bin_dir = /etc/dovecot/sieve
# INBOX/başka klasör -> Junk : spam öğren
imapsieve_mailbox1_name = Junk
imapsieve_mailbox1_causes = COPY APPEND
imapsieve_mailbox1_before = file:/etc/dovecot/sieve/learn-spam.sieve
# Junk -> başka klasör : ham öğren
imapsieve_mailbox2_name = *
imapsieve_mailbox2_from = Junk
imapsieve_mailbox2_causes = COPY
imapsieve_mailbox2_before = file:/etc/dovecot/sieve/learn-ham.sieve
}learn-spam.sieve mesajı script'e pipe'lar; /etc/dovecot/sieve/learn-spam.sh ise controller'a bağlanır:
#!/bin/sh
# /etc/dovecot/sieve/learn-spam.sh
exec /usr/bin/rspamc -h /run/rspamd/rspamd.sock learn_spamUnix soketine (/run/rspamd/rspamd.sock) bağlanmak TCP'den hızlıdır ve her IMAP hareketinde yeni bağlantı açmanın maliyetini düşürür. Öğrenme önbelleği burada güvenlik ağıdır: kullanıcı kararsız kalıp mesajı Junk'a atıp geri alırsa aynı mesaj çift sayılmaz. İki yönü de kurmayı unutmayın — sadece spam öğrenip ham öğrenmezseniz korpus yine dengesizleşir.
Doğrulama, izleme ve zehirlenmeyi geri alma
Kurdunuz; şimdi gerçekten çalışıyor mu görün. Temel sağlık kontrolü:
rspamc stat # learns sayıları, her iki sınıf ≥ 200 mı
rspamadm statistics # token dağılımı, hit oranlarıTek bir mesajda Bayes'in ne dediğini görmek için mesajı controller'a verin:
rspamc -v < suphelimesaj.eml | grep -i bayes
# BAYES_SPAM (4.20) veya BAYES_HAM (-2.10) satırı + olasılıkTeslim edilmiş bir mesajda ise X-Spamd-Result başlığına bakın — hangi sembollerin ateşlendiğini ve BAYES_*'in metascore'daki payını orada görürsünüz. Bayes sembolleri başlıkta hiç görünmüyorsa ya henüz 200 eşiğine ulaşmadınız ya da statfile boş.
Zehirlenme belirtileri: BAYES_HAM neredeyse her mesajda ateşleniyor ve spam sızmaya başlıyor, ya da tersine meşru posta BAYES_SPAM yiyor. Bu genellikle dengesiz bootstrap veya çok agresif autolearn'ün sonucudur. Geri alma prosedürü:
# İlgili Bayes anahtarlarını Redis'te bul (anahtar öneki kuruluma göre değişir; önce doğrula)
redis-cli --scan --pattern 'BAYES_*'
redis-cli --scan --pattern 'RS*' # new_schema anahtar öneki
# Statfile'ları temizle (dikkat: tüm Bayes istatistiğini sıfırlar)
redis-cli --scan --pattern 'BAYES_*' | xargs -r redis-cli del
# Sonra dengeli korpusla YENİDEN bootstrap yapSıfırlamak radikal ama bazen en temizidir — zehirlenmiş bir korpusu tek tek relearn ile düzeltmeye çalışmak, dengeli bir korpusla baştan öğretmekten uzun sürer. Tek bir yanlış öğretilmiş mesaj söz konusuysa relearn yeterli; sistemik kayma varsa flush + yeniden bootstrap.
Son bir netlik: Fuzzy storage ve neural modülü Bayes'ten ayrı sistemlerdir. Fuzzy, mesajların bulanık karma (hash) eşleşmesine bakar; neural, sembollerin üstünde ayrı bir katmandır. Birinde yaşadığınız sorunu diğerinin config'inde aramayın.
Pratik kontrol listesi
- Backend Redis mi ve
new_schema = trueaçık mı rspamc stat'ta her iki sınıfta dalearns ≥ 200mı (yoksa BAYES ateşlenmez)- Bootstrap korpusu ~1:1 dengede mi; ham gerçek işlemsel/kişisel postadan mı toplandı
autolearn:ham_thresholdnegatif (−0.5),spam_thresholdgri bölge dışında ve reject'in altında (6.0) mı- Öğrenme önbelleği (
cachebloğu) açık mı (çift öğrenme yok) - IMAPSieve iki yönlü mü çalışıyor (Junk'a taşı = spam, Junk'tan çıkar = ham)
- GTUBE ile eğitim yapılmadı, false-positive'ler ham olarak relearn edildi mi
X-Spamd-ResultbaşlığındaBAYES_*


