Yahoo/AOL Feedback Loop Kurulumu: Şikayeti Aboneye Bağlayıp Otomatik Suppress Etmek
Yahoo Sender Hub'a kaydolmak işin sadece başlangıcı. ARF raporu alıcının adresini redakte ettiği için şikayeti aboneye bağlamak ayrı bir mühendislik işi. FBL kaydından Postfix pipe + parser + suppression tablosuna kadar çalışan gerçek bir hat kuruyoruz.
EvilMail Team14 Temmuz 202613 dk okuma
Bir alıcı Yahoo arayüzünde "Spam" tuşuna bastığında, o tıklama reputation sistemine giden doğrudan bir negatif sinyaldir. Bounce değil, açılmama değil — kullanıcının bilinçli "bunu istemiyorum" beyanı. Yahoo/AOL için complaint oranının pratik eşiği %0.3 civarındadır; %0.1'i geçtiğinizde sarı bölgedesiniz, %0.3 üstü ise klasörlemenin Junk'a kaymasıyla başlayıp reddedilmeye kadar gider.
Somut konuşalım: 50.000'lik bir gönderimde 150 complaint = %0.3. Tek başına felaket değil ama trend yukarıysa ve bir sonraki kampanyada aynı adreslere tekrar vurursanız oran katlanır; IP/domain reputation'ınız günler içinde çöker. Sorun şu ki Gmail bu şikayetleri kişi bazında vermez — Postmaster Tools'ta yalnızca toplu bir oran görürsünüz, kimin şikayet ettiğini bilemezsiniz. Yahoo/AOL ise hâlâ kişi-bazlı FBL veren en büyük oyuncu. Bu yüzden entegrasyon opsiyonel değil: kurmadan şikayet eden aboneyi listenizden çıkaramaz, kör uçarsınız.
Ön koşullar: FBL adrese değil, DKIM'e bağlanır
En sık yapılan hata, FBL'in gönderen e-posta adresine göre çalıştığını sanmaktır. Çalışmaz. Yahoo FBL kaydı DKIM `d=` alanı + selector üzerinden anahtarlanır. Gelen her şikayet, mesajın hangi DKIM alanıyla imzalandığına bakılarak eşleştirilir.
Yahoo/AOL Feedback Loop Kurulumu ve Otomatik Suppress (2026) — EvilMail Blog
Bunun üç pratik sonucu var:
İmzalayan her alan için ayrı kayıt gerekir. evilmail.pro ile imzalıyorsanız onu, alt-alan mail.evilmail.pro ile imzalıyorsanız onu kaydedin. Yanlış alanı kaydederseniz rapor hiç gelmez.
DKIM imzasının aligned olması, SPF ve DMARC'ın yerinde olması şart. Hizalanmamış imzayla kayıt reddedilebilir.
Kayıttan önce imzanın gerçekten doğrulandığını kanıtlayın.
bash
# Selector'ın DNS'te yayınlandığını ve private key ile eşleştiğini doğrula
opendkim-testkey -d evilmail.pro -s mail -vvv
# Beklenen: "key OK"
# TXT kaydını gözle kontrol et
dig +short mail._domainkey.evilmail.pro TXT
Bir test mesajının başlığındaki DKIM-Signature satırında d=evilmail.pro; s=mail; gördüğünüzden emin olun. Kayıtta gireceğiniz domain + selector ile bire bir aynı olmalı.
Yahoo Sender Hub'da kaydı yapmak
Kayıt adresi https://senders.yahooinc.com/complaint-feedback-loop/ (eski adlarıyla yahoo.com/senders, Verizon Media / Oath FBL). Önemli kolaylık: AOL ve Yahoo konsolidedir — tek kayıt her ikisini de kapsar, ayrı AOL FBL başvurusu yapmanıza gerek yok.
Adımlar:
DKIM domain (evilmail.pro) ve selector (mail) girin.
Raporların düşeceği FBL adresini belirtin. [email protected] gibi ayrı bir mailbox verin — bunu gerçek bir insan gelen kutusuna değil, birazdan kuracağımız parser'a pipe edeceğiz.
Yahoo, alan sahipliğini doğrulamak için bir onay e-postasını role adresine gönderir: [email protected] veya [email protected]. Bu adreslerin gerçekten teslim alabildiğinden emin olun; aksi halde doğrulamayı tamamlayamazsınız.
Onaydan sonra kayıt tipik olarak birkaç gün içinde aktifleşir.
Kayıt biter bitmez raporlar akmaya başlar. Asıl mühendislik tam burada devreye giriyor.
ARF raporunun anatomisi ve redaction problemi
Yahoo'nun gönderdiği rapor bir ARF (Abuse Reporting Format, RFC 5965) mesajıdır. Content-Type: multipart/report; report-type=feedback-report zarfı içinde üç parça taşır:
message/rfc822 veya text/rfc822-headers — orijinal mesajın başlıkları (çoğu zaman gövde olmadan, sadece header'lar).
İşte kritik nokta: Yahoo alıcının adresini redakte eder. Raporda To: satırı ve Original-Rcpt-To alanı ya tamamen silinmiş ya da [email protected] gibi maskelenmiş gelir. Yani ham ARF raporuna bakarak *hangi abonenizin* şikayet ettiğini çıkaramazsınız — suppress edecek bir hedef adresiniz yoktur.
Çözüm: mesajı gönderirken, ARF redaction'ından sağ kurtulacak dayanıklı bir kimliği mesaja gömmek.
Şikayeti aboneye geri bağlamak (işin özü)
Amaç: redaction sonrası hayatta kalan, ama içinde açık e-posta adresi taşımayan bir kimlik. Neden açık adres değil? Çünkü ARF raporları üçüncü taraf sistemlerden geçer; bir rapor sızıntısında ham abone e-postalarını başlıklara gömmüş olmanız GDPR/gizlilik açısından ciddi bir PII riskidir. Bunun yerine geri-eşlenebilir ama okunamaz bir HMAC kullanırız.
Üç dayanıklı kimlik stratejisi, dayanıklılık sırasına göre:
VERP Return-Path — bounce+<hmac16>@evilmail.pro. Bu, ARF'te Original-Mail-From olarak korunur, çünkü zarf gönderenidir; redakte edilen alıcı değildir. En güvenilir kancadır.
Özel başlık `X-EM-Subscriber` — base64url(HMAC) değeri. Orijinal başlıklar rapora dahil edildiğinde geri gelir.
`Feedback-ID` başlığı — <senderid>:<campaign>:<sub-hmac> formatı. Hem FBL hem Postmaster Tools tarafında segmentasyona yarar.
HMAC üretimi ve mesaja gömme (gönderim tarafında):
python
import hmac, hashlib, base64
FBL_SECRET = b"rotate-this-64-hex-secret" # env'den; sızarsa rotate et
def sub_tag(subscriber_id: int) -> str:
mac = hmac.new(FBL_SECRET, str(subscriber_id).encode(), hashlib.sha256).digest()
return base64.urlsafe_b64encode(mac[:16]).decode().rstrip("=")
tag = sub_tag(48213)
msg["Return-Path"] = f"<bounce+{tag}@evilmail.pro>"
msg["X-EM-Subscriber"] = tag
msg["Feedback-ID"] = f"evilmail:camp2026q3:{tag}"
HMAC tek yönlü olduğu için düz veritabanında ters çeviremezsiniz; o yüzden gönderim anında subscriber_id -> tag eşlemesini bir lookup tablosuna (fbl_tag_map) da yazın. Rapor geldiğinde tag'i bu tabloda arayıp aboneyi bulursunuz. HMAC, tag'in tahmin edilemez ve tamper-proof olmasını sağlar; tablo ise hızlı geri-eşleme içindir.
Otomatik suppression hattı: Postfix → parser → DB
fbl@ mailbox'ını bir gelen kutusunda bekletmeyin — doğrudan bir script'e pipe edin. Postfix'te master.cf içine bir transport tanımlayın:
# master.cf
fblpipe unix - n n - - pipe
flags=Rq user=fbl argv=/usr/local/bin/parse_fbl.py
Ardından virtual_alias_maps ya da bir transport kuralıyla [email protected] adresini fblpipe: transportuna yönlendirin. (Dovecot kullanıyorsanız Sieve pipe eklentisiyle de aynı sonucu alırsınız.)
Parser'ın işi net: ARF'i ayrıştır, message/feedback-report parçasından Feedback-Type: abuse olduğunu doğrula, gömülü kimliği çıkar, HMAC'i geri-eşle, suppression tablosuna idempotent yaz.
python
#!/usr/bin/env python3
import sys, re, email
from email import policy
raw = sys.stdin.buffer.read()
msg = email.message_from_bytes(raw, policy=policy.default)
fb_type, mail_from, sub_tag = None, None, None
for part in msg.walk():
ct = part.get_content_type()
if ct == "message/feedback-report":
report = email.message_from_bytes(
part.get_payload(0).as_bytes(), policy=policy.default)
fb_type = (report.get("Feedback-Type") or "").lower()
mail_from = report.get("Original-Mail-From")
if ct in ("text/rfc822-headers", "message/rfc822"):
hdrs = part.get_payload(0) if part.is_multipart() else part
sub_tag = sub_tag or hdrs.get("X-EM-Subscriber")
# Return-Path VERP tag'i can simidi: bounce+<tag>@...
if not sub_tag and mail_from:
m = re.search(r"bounce\+([A-Za-z0-9_-]+)@", mail_from)
if m:
sub_tag = m.group(1)
if fb_type == "abuse" and sub_tag:
suppress(sub_tag) # UPSERT: idempotent + audit log
sys.exit(0) # her zaman 0 dön — Postfix'in requeue etmesini engelle
suppress() fonksiyonu şunları yapar: tag'i fbl_tag_map'te arar, subscriber_id'yi bulur, suppression_list'e reason='fbl_complaint' ve source='yahoo' ile UPSERT eder, aktif abonelikleri pasifler, bir audit satırı yazar. UPSERT olduğu için aynı rapor iki kez gelse bile ikinci kez zararsızdır. Parse hatalarında da exit(0) döndürüp hatayı ayrı loglayın — yoksa Postfix mesajı sonsuza kadar requeue eder.
Doğrulama, izleme ve eşikler
Hattı canlıya almadan önce loop'u kendiniz tetikleyin. Bir Yahoo test hesabına imzalı bir mesaj gönderin, arayüzde Spam işaretleyin. ARF raporu genelde 24-48 saat içinde fbl@ mailbox'ına düşer. Parser'ın o test abonesini suppress ettiğini teyit edin.
İzlenecek asıl metrik complaint rate = complaints / delivered, sağlayıcı bazında ayrıştırılmış olarak. Feedback-ID içindeki campaign alanı sayesinde hangi kampanyanın şikayet mıknatısı olduğunu görürsünüz. Postmaster Tools'un toplu oranıyla çapraz kontrol edin; ikisi birbirini tutmalı.
Son ve en önemli guard: suppress edilmiş bir adrese bir daha asla göndermeyin. "Unsubscribe" flag'i yetmez — gönderim motoruna, her mesaj öncesi suppression tablosunu sorgulayan bir hard-block koyun. Yumuşak bir işaret değil, teslimatı fiziksel olarak durduran bir kontrol olmalı.
Devreye alma kontrol listesi
DKIM imzası aligned ve opendkim-testkey ile "key OK" veriyor mu?
İmzalayan her domain/alt-alan için ayrı FBL kaydı açıldı mı?
postmaster@ / abuse@ role adresleri Yahoo doğrulama mailini alabiliyor mu?
fbl@ mailbox'ı fblpipe transportuna bağlı ve parse_fbl.py çalışıyor mu?
Gönderim tarafı VERP Return-Path + X-EM-Subscriber + Feedback-ID basıyor mu?
HMAC secret env'de ve rotasyon prosedürü tanımlı mı?
Suppression, gönderim anında hard-block olarak uygulanıyor mu?
Complaint rate sağlayıcı bazında dashboard'da izleniyor, %0.1 üstünde alarm var mı?
ARF parse hataları ayrı loglanıp alarma bağlı mı?
Referanslar: RFC 5965 (ARF formatı), RFC 6449 (FBL uygulama önerileri), RFC 6650 (ARF raporlarının oluşturulması ve kullanımı). Bu hattı bir kez doğru kurunca, şikayet eden aboneler listenizden otomatik ve sessizce düşer — reputation'ınızı yiyen sızıntı kapanır.