Şu tanıdık mı: Thunderbird'de yıllar içinde biriktirdiğiniz 40 filtre kuralı var. Bilgisayarı kapatıp telefondan bakıyorsunuz, INBOX yine 300 okunmamış. Bültenler, GitHub bildirimleri, faturalar, hepsi üst üste yığılmış. Çünkü o 40 kural telefonda yok, webmail'de yok, ikinci dizüstünüzde de yok. Sadece o tek Thunderbird kurulumunda, o da yalnızca uygulama açıkken çalışıyor.
İstemci tarafı filtrenin üç yapısal kusuru var ve hiçbiri düzeltilebilir değil:
- İstemci açık olmalı. Kural, uygulamanın IMAP'e bağlanıp yeni postayı çekmesiyle tetiklenir. Bilgisayar kapalıysa kural da yok.
- Tek cihaz. Kurallar
.thunderbirdprofilinde yaşar. Telefon o profili görmez; her cihaz için kuralları elle senkronlamak zorundasınız. - IMAP tarafında görünmez. Sunucu, filtrenin varlığından habersizdir. Webmail açtığınızda ham INBOX'la yüzleşirsiniz.
Çözüm tek cümle: filtreyi teslimata taşıyın. Posta INBOX'a yazılmadan, herhangi bir istemci onu görmeden önce sunucuda bir kez ayıklansın. Dovecot bunu Pigeonhole Sieve motoruyla yapar ve sonuç bütün cihazlarda birebir aynıdır.
Sieve teslimat anında nerede çalışır
Bir mesajın sunucunuza giriş zinciri şöyle: dışarıdaki MTA, Postfix'in 25. portuna bağlanır, Postfix mesajı kabul eder ve yerel teslimat için LMTP üzerinden Dovecot'a devreder. İşte tam bu noktada, mesaj kullanıcının mailbox'ına yazılmadan hemen önce, Pigeonhole devreye girer ve aktif Sieve scriptini değerlendirir.
"Teslimat anı" ifadesi burada kritik. Kural, mesaj daha diskteki hiçbir klasöre yazılmadan çalışır. fileinto "Bultenler" derseniz, mesaj INBOX'a hiç uğramadan doğrudan Bultenler klasörüne düşer. Bir istemcinin sonradan taşıması değil bu; mesaj baştan orada doğar. Bir kez çalışır, her yerde geçerlidir.
Sieve tek katman da değildir. Üç ayrı script katmanı sırayla değerlendirilir: önce organizasyon geneli sieve_before, sonra kullanıcının kendi ~/.dovecot.sieve scripti, en sonda sieve_after. Bu katmanlama, "tüm kullanıcılar için spam'i Junk'a at" gibi global politikayı kişisel kurallardan ayırmanızı sağlar.
Pigeonhole'u devreye almak
Debian/Ubuntu üzerinde iki paket yeter:
apt install dovecot-sieve dovecot-managesieveddovecot-sieve Pigeonhole motorunu ve sievec, sieve-test, sieve-filter araçlarını getirir. dovecot-managesieved, kullanıcıların kendi scriptlerini uzaktan düzenlemesini sağlayan ManageSieve servisini ekler (TCP 4190).
Önce teslimat protokollerine plugin'i tanıtın. /etc/dovecot/conf.d/15-lda.conf ve 20-lmtp.conf içinde:
protocol lda {
mail_plugins = $mail_plugins sieve
}
protocol lmtp {
mail_plugins = $mail_plugins sieve
}Sonra /etc/dovecot/conf.d/90-sieve.conf içinde script yollarını tanımlayın:
plugin {
sieve = file:~/sieve;active=~/.dovecot.sieve
sieve_before = /etc/dovecot/sieve/global-before.sieve
sieve_after = /etc/dovecot/sieve/global-after.sieve
}sieve = file:~/sieve;active=~/.dovecot.sieve satırı şunu söyler: kullanıcının scriptleri ~/sieve/ dizininde dosya olarak durur, aktif olan ~/.dovecot.sieve sembolik bağıyla işaretlenir. ManageSieve bu düzeni kendi yönetir; siz elle uğraşmazsınız.
Yeniden yükleyin ve yapılandırmayı doğrulayın:
doveadm reload
doveconf -n sievedoveconf -n sieve çıktısında sieve, sieve_before, sieve_after değerlerini görmelisiniz. Görmüyorsanız plugin protokole eklenmemiştir.
Bir kuralın anatomisi
Her Sieve kuralı üç parçadan oluşur: require (kullanacağınız eklentileri bildirir), test (koşul) ve action (eylem). En küçük çalışan script:
require ["fileinto"];
if header :contains "list-id" "" {
fileinto "Bultenler";
}Kritik kavram implicit keep: hiçbir kural eşleşmezse veya hiçbir aksiyon çalışmazsa, Sieve mesajı sessizce INBOX'a bırakır. Yani "eşleşmeyen her şey INBOX'a" davranışını siz yazmak zorunda değilsiniz; varsayılan budur. fileinto çalıştığı anda ise implicit keep iptal olur — mesaj artık INBOX'a değil, belirttiğiniz klasöre gider. Bu incelik ileride çift kopya tuzağının kaynağı olacak.
Temel aksiyonlar:
- keep — mesajı INBOX'ta tut (implicit keep'in açık hali)
- fileinto "Klasor" — belirtilen klasöre koy
- discard — sessizce sil (bounce yok)
- redirect "adres" — başka adrese yönlendir
- stop — script değerlendirmesini burada kes
require satırı zorunludur, çünkü Sieve'in çekirdeği (RFC 5228) minimaldir. fileinto, mailbox (klasör oluşturma), imap4flags (bayrak işleme), envelope, regex — her biri ayrı bir eklentidir ve kullanmadan önce require ile bildirilmelidir. Bildirmeden fileinto yazarsanız script derlenmez.
Gönderen, konu ve başlığa göre ayırma
İşin ustalık gerektiren kısmı doğru testi seçmek. "Gönderene göre" üç farklı şey demek olabilir:
- `address "from"` — mesaj başlığındaki görünen
From:adresi. Arayüzde gördüğünüz gönderen. - `envelope "from"` — SMTP zarfındaki
MAIL FROMadresi. Forward edilen postada bu, görünen From'dan farklıdır; mailing list'lerde de zarf genelde listenin bounce adresidir.envelopeeklentisirequiregerektirir. - `header "from"` — ham başlık metni. İsim + adresin tamamı üzerinde eşleşme yaparsınız.
Domain'e göre eşleşmek için address testinin adres bölümleyicilerini kullanın: address :domain "from" sadece github.com kısmını verir, :localpart sadece kullanıcı kısmını, :all tümünü.
List-Id ile bülten yakalamak en sağlam yöntemdir. Konu satırı değişir, gönderen adresi kampanyadan kampanyaya farklılaşır, ama düzgün bir bülten altyapısı her mesaja aynı List-Id: başlığını koyar (RFC 2919). Konuya göre tahmin yürütmek yerine bu değişmez imzayı yakalayın.
Klasör yoksa fileinto :create ile otomatik açın (mailbox eklentisi). Otomatik okundu işaretlemek için imap4flags ile addflag "\\Seen". Eşleşme tipleri: :is (tam), :contains (içerir), :matches (* ve ? joker), :regex (Pigeonhole eklentisi, maliyeti daha yüksek).
Production'a yakın çok kurallı bir script:
require ["fileinto", "mailbox", "envelope", "imap4flags", "subaddress"];
# 1) Bültenler — List-Id imzası her şeyden sağlam
if header :contains "list-id" "" {
fileinto :create "Bultenler";
stop;
}
# 2) GitHub bildirimleri
if address :domain "from" "github.com" {
fileinto :create "Dev/GitHub";
stop;
}
# 3) Muhasebe — konuda fatura/invoice
if anyof (header :contains "subject" "fatura",
header :contains "subject" "invoice") {
fileinto :create "Muhasebe";
stop;
}
# 4) Subaddress etiketi: user+shop@domain -> Shop klasörü
if envelope :detail "to" "shop" {
fileinto :create "Shop";
addflag "\\Seen";
stop;
}subaddress eklentisi sayesinde [email protected] gibi bir adrese gelen postanın + sonrasındaki shop etiketini envelope :detail "to" ile okursunuz. Nereye kaydolduğunuzu takip edebilir, sızan adresleri tespit edebilirsiniz.
Kural sırası: her şeyi belirleyen kısım
Sieve yukarıdan aşağı akar. Yukarıdaki scriptin her fileinto'sunun peşine neden stop koyduğuma dikkat edin. stop olmadan bir mesaj birden fazla if bloğuna uyar ve iki kez dosyalanabilir.
İki yaklaşım var. Birbirini dışlayan kurallarda if / elsif / else zinciri en temizidir; ilk uyan blok çalışır, gerisi hiç değerlendirilmez. Bağımsız if bloklarını art arda dizerseniz her biri ayrı çalışır ve stop koymazsanız aynı mesaj birden çok klasöre kopyalanır.
En sık yapılan hata: fileinto yazıp ardından refleksle keep de eklemek. fileinto zaten implicit keep'i devraldığı için keep gereksizdir; onu eklerseniz mesaj hem hedef klasöre hem INBOX'a düşer. Çift kopya buradan gelir. Kural basit: fileinto kullanıyorsanız keep yazmayın.
:matches joker eşleşmesi :regex'ten ucuzdur. Basit desenler için :matches "*@github.com" yeterliyken düzenli ifadeye uzanmayın; her mesajda çalışacak bu motorda maliyet birikir.
Global scriptler ve spam entegrasyonu
Tüm kullanıcılar için tek bir politikayı sieve_before ile uygularsınız. Klasik örnek, Rspamd veya SpamAssassin'in eklediği başlığa bakıp Junk'a atmak. /etc/dovecot/sieve/global-before.sieve:
require ["fileinto", "mailbox"];
if header :contains "X-Spam-Flag" "YES" {
fileinto :create "Junk";
stop;
}Ham başlık yerine skora göre eşiklemek isterseniz spamtest eklentisi (RFC 5235) daha esnek:
require ["spamtest", "relational", "fileinto", "comparator-i;ascii-numeric"];
if spamtest :value "ge" :comparator "i;ascii-numeric" "6" {
fileinto "Junk";
stop;
}Global scriptler dosya olarak durur; performans için sievec ile derleyin:
sievec /etc/dovecot/sieve/global-before.sieveBu, yanına .svbin bytecode üretir ve her teslimatta yeniden derlemeyi önler. .sieve dosyasını değiştirdiğinizde .svbin'i yenilemeyi unutmayın, yoksa Dovecot eski derlenmiş halini kullanır.
Not: tatil/otomatik yanıt (vacation, RFC 5230) da aynı motorda yaşar ve aynı require mekaniğiyle çalışır, ama teslimat filtrelemesinden ayrı bir konudur; burada karıştırmayın.
Test ve hata ayıklama
Scripti canlıya sürmeden önce gerçek bir .eml dosyası üzerinde kuru çalıştırın:
sieve-test ~/.dovecot.sieve mesaj.emlÇıktı, hangi kuralın eşleştiğini ve mesajın nereye gideceğini (fileinto hedefi veya implicit keep) satır satır gösterir. Klasörün gerçekten oluşup oluşmadığını değil, mantığın doğru dallandığını burada görürsünüz.
Derleme hatalarını sievec yakalar. Tipik çıktı:
error: line 7: fileinto is not allowed in this context.
error: line 7: name 'fileinto': not found; forgot to 'require'?Bu mesaj neredeyse her zaman eksik require demektir. Eklentiyi bildirin, hata gider.
Canlı teslimatı izlemek için /var/log/dovecot.log içindeki sieve: ile başlayan satırlara bakın. Daha ayrıntılı iz için sieve_trace_dir tanımlayıp adım adım değerlendirme dökümü alabilirsiniz. Aktif scripti ve ManageSieve üzerinden yüklenmiş scriptleri doveadm ve managesieve istemcisiyle listeleyebilirsiniz.
Deploy öncesi kontrol listesi
- `require` satırları tam mı? Kullandığınız her eklenti (
fileinto,mailbox,envelope,imap4flags,subaddress,regex) bildirilmiş olmalı. - `fileinto :create` var mı? Klasör önceden yoksa
:createolmadan mesaj INBOX'a düşer; sessizce kaybolmaz ama beklediğiniz yerde olmaz. - Her `fileinto`'dan sonra `stop` doğru mu? Birbirini dışlayan kurallarda çift dosyalamayı
stopengeller. - `fileinto` yanında gereksiz `keep` yok, değil mi? Varsa INBOX'ta çift kopya bırakır.
- `envelope` mı `address` mı? Forward ve mailing list senaryolarında doğru olanı seçin; görünen From ile SMTP zarfı farklıdır.
Kapanış notu: bu scripti bir metin dosyası gibi değil, kod gibi görün. ~/.dovecot.sieve ve global scriptlerinizi versiyon kontrolüne alın; bir kural bozulduğunda ne değiştiğini git diff ile görebilmek, üç ay sonra "40 kural neden çalışmıyor" tuzağına düşmemenin en ucuz sigortasıdır.


