Deneyiminizi geliştirmek için çerezler kullanıyoruz. Bu siteyi ziyaret etmeye devam ederek çerez kullanımımızı kabul etmiş olursunuz.Gizlilik Politikası

EvilMailEvilMail
ÖzelliklerEvilMail ile yapabileceğiniz her şeyŞunlar için Geçici Mail…Discord, ChatGPT ve daha fazlası için geçici mailAğ AraçlarıDNS, WHOIS, port ve ağ araçlarıKarşılaştırEvilMail ile diğer geçici mail servislerinin karşılaştırması
APIREST API referansı ve rehberleriGeçici Mail APIHer dilde kopyala-yapıştır kod
UygulamalarFiyatlarBlog
HakkımızdaBiz kimiz ve neler geliştiriyoruzGüven ve GüvenlikVerilerinizi nasıl koruyoruzSSSSık sorulan soruların yanıtlarıİletişimEkibimizle iletişime geçin
GirişKayıt Ol
EvilMailEvilMail
UygulamalarFiyatlarBlog
GirişKayıt Ol
Ana SayfaBlogDKIM'i Uygulamada mı MTA'da mı İmzalamalı: Mimari Kararın Tuzakları
Geliştiriciler

DKIM'i Uygulamada mı MTA'da mı İmzalamalı: Mimari Kararın Tuzakları

Uygulamanız kusursuz bir DKIM-Signature üretti, Gmail yine de dkim=fail dedi. Sebep neredeyse her zaman aynı: imzayı siz hesapladıktan sonra biri mesajı değiştirdi. İmzayı nereye koyacağınıza mühendislik gerekçesiyle karar verelim.

EvilMail Team
2 Ağustos 2026
12 dk okuma
DKIM'i Uygulamada mı MTA'da mı İmzalamalı: Mimari Kararın Tuzakları
İçindekiler
Kararı belirleyen tek soru: mesajı en son kim değiştiriyor?MTA'da imzalama: son milter olarak en sağlam yolUygulama katmanında imzalama: ne zaman gerçekten gerekirSessiz katiller: imzayı bozan dönüşümlerHibrit: çift imza ve ARCKarar ağacıDoğrulama ve hata ayıklamaÜretime çıkmadan önce kontrol listesi

Uygulamanız kusursuz bir DKIM-Signature başlığı üretti. Anahtar 2048-bit, seçici DNS'te yayında, bh= doğru hesaplandı. Yine de alıcı tarafta Authentication-Results başlığında acı gerçek yazıyor: dkim=fail (body hash did not verify). Sebep neredeyse her zaman aynıdır: imzayı siz hesapladıktan sonra biri mesajı değiştirdi.

DKIM'i nereye koyacağınız — uygulama koduna mı, MTA'ya mı — bir zevk meselesi değil, bir zamanlama meselesidir. Bu yazı "hangisi daha kolay" sorusuna değil, "mesajı telin üzerine çıkmadan önce en son kim değiştiriyor" sorusuna cevap verir. Peşinen net öneri: varsayılan olarak MTA'da, son milter olarak imzalayın. Uygulama katmanına yalnızca somut bir gerekçeniz varsa geçin. Nedenini gösterelim.

Kararı belirleyen tek soru: mesajı en son kim değiştiriyor?

DKIM iki ayrı şey imzalar: seçtiğiniz başlıkların bir hash'i ve gövdenin hash'i (bh= etiketi). Başlık imzası, h= içinde saydığınız başlıkları kriptografik olarak mühürler. Gövde hash'i ise mesaj gövdesinin tek bir byte'ına bile bağlıdır. Bir boşluk, bir satır sonu, bir yeniden kodlama — bh= çöker ve imza baştan geçersizdir.

Bu kırılganlık bir tasarım hatası değil, bütün mekanizmanın amacı. Ama pratik bir sonucu var: imza her zaman tele en yakın noktada, mesaj üzerindeki tüm dönüşümler bittikten sonra hesaplanmalı. Buna "geç imzala, en son imzala" (sign late, sign last) diyorum; bu yazının omurgası bu tek cümle.

Canonicalization (kanonikleştirme) bu kırılganlığı biraz yumuşatır. c= etiketi başlık ve gövde için ayrı ayrı simple ya da relaxed alır. simple neredeyse hiç toleranslı değildir: bir başlığın katlanması (folding) ya da fazladan bir boşluk imzayı bozar. relaxed ise ardışık boşlukları tek boşluğa indirger, satır sonundaki boşlukları kırpar. Modern kurulumların tamamı c=relaxed/relaxed üretmeli. simple/simple üreten bir sistem, yolda mesaja dokunan her ara sunucuda kırılmaya adaydır.

Aşağıdaki diyagram, imzayı nerede hesapladığınızın sonucunu tek bakışta gösteriyor. Kritik olan, imza noktası ile "tel" arasında kalan bölge — orada mesaja dokunan herhangi bir bileşen imzanızı sessizce öldürür.

Mutasyon Bölgesi: imzayı ne zaman hesaplarsan? İmza noktası ile tel arasında mesaja dokunan her şey bh= hash'ini bozar UYGULAMA KATMANINDA İMZA App MIME oluşturur App DKIM imzalar (bh=) MUTASYON BÖLGESİ MTA: CTE yeniden yazar Date + Message-ID ekler Tel dkim= fail MTA KATMANINDA İMZA (son milter) App MIME oluşturur MTA tüm mutasyonları burada yapar MTA son milter olarak imzalar Tel dkim= pass Alt şeritte imza noktası ile tel arasında hiç mutasyon yok — imza ne kadar geç atılırsa o kadar güvenli.

MTA'da imzalama: son milter olarak en sağlam yol

Kendi Postfix'inizi işletiyorsanız ve tek ya da birkaç alan adınız varsa, tartışma burada biter: imzayı MTA'ya bırakın. Mesajı artık değiştirmeyeceği anda imzalar, dolayısıyla mutasyon bölgesi sıfırlanır.

İki yaygın seçenek var: OpenDKIM ve rspamd. OpenDKIM klasiktir, tek işi imzalamaktır. Önce anahtarı üretin:

bash
opendkim-genkey -b 2048 -s mail -d evilmail.pro
# mail.private (özel anahtar) + mail.txt (DNS TXT kaydı) üretir

mail.txt içindeki kaydı DNS'e koyarsınız — dikkat, 2048-bit anahtarın base64'ü 255 karakteri aşar, bu yüzden TXT çok-string olarak bölünmüş gelir:

mail._domainkey.evilmail.pro. IN TXT ( "v=DKIM1; k=rsa; h=sha256; "
  "p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA..."
  "...QIDAQAB" )

DNS panelinizde bunu tek string'e sıkıştırıp 255 karakter sınırını aşarsanız kayıt sessizce kırılır — canlıda en sık gördüğüm hata bu. OpenDKIM tarafında KeyTable, SigningTable ve TrustedHosts üçlüsünü kurar, sonra Postfix'e milter olarak bağlarsınız:

# /etc/postfix/main.cf
smtpd_milters = inet:localhost:8891
non_smtpd_milters = $smtpd_milters
milter_default_action = accept

Kritik nokta milter sırası. Spam filtreniz veya başlık yeniden yazan başka bir milter varsa, bunlar DKIM'den önce gelmeli. smtpd_milters soldan sağa çalışır; DKIM en sonda olmalı ki kendisinden önceki milter'lar mesajı değiştirmeyi bitirsin. Aksi halde tekrar mutasyon bölgesine düşersiniz.

Birden çok alan adı yönetiyorsanız rspamd daha az bakım ister. dkim_signing modülü, From başlığındaki alan adına göre anahtarı otomatik seçer:

# /etc/rspamd/local.d/dkim_signing.conf
path = "/var/lib/rspamd/dkim/$domain.$selector.key";
selector = "mail";
allow_hdrfrom_mismatch = false;
use_domain = "header";

use_domain = "header" satırı DMARC hizalaması için hayati: imzayı gönderen zarf adresine göre değil, From: başlığındaki alan adına göre atar. DMARC tam olarak buna bakar.

Yeni kuruyorsanız Ed25519 + RSA çift seçiciyi de değerlendirin (RFC 8463). Ed25519 anahtarı çok daha kısadır (k=ed25519; p=<base64>), ama eski doğrulayıcılar tanımaz. İki seçiciyle imzalarsınız: yeni doğrulayıcılar Ed25519'a, eskiler RSA'ya düşer.

Uygulama katmanında imzalama: ne zaman gerçekten gerekir

Uygulama katmanı varsayılan değil, istisnadır. Ama gerçek gerekçeler var:

  • Çok kiracılı SaaS. Her müşteri kendi alan adıyla (d=musteri.com) gönderiyor ve her biri için ayrı anahtar tutuyorsunuz. Milter'ı her yeni müşteride yeniden yapılandırmak yerine, imzayı uygulamadan atmak operasyonel olarak daha temiz.
  • Programatik anahtar rotasyonu. Anahtarları bir API üzerinden döndürmek, seçiciyi çalışma anında değiştirmek istiyorsanız, uygulama katmanı bunu milter yeniden başlatmadan yapar.
  • Kontrol etmediğiniz bir relay. SES ya da SendGrid kendi imzasını ekler, ama siz kendi d='nizle de imzalamak isteyebilirsiniz. Mesajı relay'e teslim etmeden önce uygulamada imzalarsınız.

Node tarafında nodemailer'ın yerleşik DKIM desteği var:

js
const transporter = nodemailer.createTransport({
  host: "127.0.0.1",
  port: 25,
  dkim: {
    domainName: "evilmail.pro",
    keySelector: "mail",
    privateKey: fs.readFileSync("/etc/dkim/evilmail.pro.mail.key", "utf8"),
    // headerFieldNames: "from:to:subject:date:message-id",
  },
});

Python tarafında dkimpy aynı işi görür. Ama burada dev bir tuzak var ve doğrudan bir sonraki bölüme köprü kuruyor: nodemailer mesajı imzalayıp 127.0.0.1:25 üzerinden Postfix'e teslim ederse ve Postfix Content-Transfer-Encoding'i yeniden yazarsa (8bit → quoted-printable), bh= anında çöker. Uygulamada imzalıyorsanız, imzalı mesajı Postfix'in dokunmayacağı bir yoldan göndermek zorundasınız — ya da imzayı en baştan MTA'ya bırakmak.

Sessiz katiller: imzayı bozan dönüşümler

dkim=fail gördüğünüzde suçlu genelde şu altı şeyden biridir:

  • Content-Transfer-Encoding yeniden yazımı. 8bit gövdeyi quoted-printable'a çeviren her ara sunucu gövde byte'larını değiştirir, bh= çöker. En yaygın "temiz imza, fail sonuç" nedeni.
  • `always_add_missing_headers = yes`. Postfix eksik Date veya Message-ID başlığını ekler. Uygulama bu başlığı zaten yazdıysa çifte başlık oluşur; From gibi bir başlığı h='e koyup mesaja iki kez sokmak da başlık imzasını bozar.
  • Başlık katlama ve whitespace. simple kanonikleştirmeyle en ufak folding farkı imzayı öldürür. relaxed kullanma sebebiniz bu.
  • `l=` gövde uzunluk etiketi. Gövdenin yalnızca ilk N byte'ını imzalar. Kulağa esnek gelir ama bir güvenlik açığıdır: saldırgan imzalı gövdenin sonuna içerik ekleyebilir (append attack) ve imza hâlâ geçerli görünür. Asla kullanmayın.

Hibrit: çift imza ve ARC

En sofistike kurulum ikisini birden kullanır. Uygulama müşteri alan adıyla imzalar (d=musteri.com), MTA kendi altyapı alan adınızla ikinci bir DKIM-Signature ekler (d=evilmail.pro). Bir mesajın birden çok DKIM imzası taşıması RFC'ce tamamen geçerlidir; doğrulayıcı her birini bağımsız kontrol eder. DMARC için önemli olan, en az bir geçen imzanın From: ile hizalı olması.

Yönlendirme ve mailing-list senaryolarında hikaye değişir. Bir liste sunucusu Subject'e [liste] etiketi ekler ya da altbilgi yapıştırırsa, gövde değiştiği için orijinal DKIM imzası zorunlu olarak kırılır. İşte ARC (Authenticated Received Chain) burada devreye girer: her ara sunucu, mesajı aldığı andaki doğrulama sonucunu kriptografik olarak "mühürler" ve zincire ekler. ARC, DKIM'in yerini almaz; kırılan imzanın olduğu yerde "ben aldığımda bu mesaj geçerliydi" güvencesini taşır. DMARC'ı ARC üzerinden geçirmek alıcının politikasına kalmıştır, ama zinciri hiç sağlamamak forward edilen postanın deliverability'sini öldürür.

Karar ağacı

MTA mı, App mi, Hibrit mi? Tek alan adı + kendi kontrolündeki self-hosted MTA? Evet MTA'da imzala (önerilen) OpenDKIM / rspamd, son milter Hayır Müşteri d= başına ayrı anahtar / programatik rotasyon lazım mı? Evet App katmanında imzala nodemailer / dkimpy Hayır Kontrol etmediğin relay'e mi teslim? Evet App imzalar (d=senin) + relay kendi imzasını ekler = doğal çift imza Yönlendirme/liste Hibrit: çift imza + ARC forward'da zincir korunur Varsayılan yeşildir; sağa gittikçe gerekçeniz somutlaşmalı.

Doğrulama ve hata ayıklama

İmza atmadan önce DNS'in doğru yayınlandığını görün:

bash
dig +short TXT mail._domainkey.evilmail.pro
opendkim-testkey -d evilmail.pro -s mail -vvv
# "key OK" görmek istiyorsunuz; "key not secure" DNSSEC uyarısıdır, sorun değil

Sonra gerçek bir mesaj gönderin ve alıcı tarafta başlığı okuyun:

bash
swaks --to [email protected] --from [email protected] --server 127.0.0.1

Gmail'de "Show original" ile ya da alıcının Authentication-Results başlığında beklediğiniz çıktı:

Authentication-Results: mx.google.com;
  dkim=pass header.d=evilmail.pro header.s=mail;
  spf=pass ...; dmarc=pass

dkim=fail (body hash did not verify) görürseniz teşhis nettir: imzadan sonra gövde değişti — mutasyon bölgesine bakın. dkim=fail (signature did not verify) ise başlık tarafında sorun var ya da DNS'teki p= anahtarı özel anahtarınızla eşleşmiyor. Hızlı bir genel sağlık kontrolü için mail-tester.com da işe yarar, ama nihai gerçek her zaman alıcı MX'in Authentication-Results başlığıdır.

Üretime çıkmadan önce kontrol listesi

  • Anahtar en az 2048-bit RSA; mümkünse Ed25519 ile çift seçici imza kurun.
  • c=relaxed/relaxed üretin; l= etiketi yok; h= içinde From mutlaka var.
  • İmza tüm mesaj dönüşümlerinden sonra, tele en yakın noktada atılıyor.
  • Postfix eksik başlık eklemiyor (always_add_missing_headers durumunu kontrol edin) ya da uygulama Date/Message-ID'yi önceden yazıyor.
  • d= ↔ From: DMARC hizası doğru (use_domain = "header").
  • DNS TXT kaydı 255-karakter parçalara doğru bölünmüş; opendkim-testkey

İmzayı doğru katmana koymak, deliverability'nin en ucuz ama en çok atlanan kazanımıdır. Kural tek cümleye sığıyor: mesaja en son kim dokunuyorsa, imzayı o atmalı.

Paylaş
𝕏 TwitterLinkedInReddit
ÖncekiIMAP'ten Otomasyon Kurmak: Maili Çekmek Kolay, İki Kez İşlememek ZorSonrakiGelen E-postayı Webhook'a Çeviren Boru Hattı: MX'ten Uygulamanıza

İlgili Yazılar

Geliştiriciler

ManageSieve ile Sieve Script'lerini Uzaktan Yönetmek: Merkezi Dağıtım ve Sürümleme

11 dk okuma
Geliştiriciler

SMTP DSN ile Teslim ve Gecikme Bildirimlerini Programatik İşlemek

13 dk okuma
Geliştiriciler

CI/CD Hattında E-postaları Mailpit ile Yakalayıp Otomatik Test Etmek

11 dk okuma
EvilMailEvilMail

EvilMail — ücretsiz temp mail ve geçici e-posta servisi. Kayıt gerektirmez.

Ürün

ÖzelliklerFiyatlarAPITools

Kaynaklar

BlogFAQGlossaryKayıt OlHakkımızda

Yasal

Gizlilik PolitikasıKullanım KoşullarıGüven ve Güvenlikİletişim
© 2026 EvilMail. Tüm hakları saklıdır.
  • `t=` / `x=` saat kayması. Sunucu saatiniz kaymışsa ya da x= ile kısa bir geçerlilik verdiyseniz, imza "gelecekte" ya da "süresi dolmuş" görünebilir. NTP'nizi kontrol edin.
  • DMARC hizalaması. İmza teknik olarak geçse bile, d= alan adı From: başlığıyla hizalı değilse DMARC yine fail verir. relaxed hizalamada organizasyon alan adı eşleşmesi yeter (mail.evilmail.pro ↔ evilmail.pro), strict hizalamada birebir aynı olmalı.
  • "key OK" diyor.
  • Çok kiracılıysanız: seçici/anahtar haritası ve bir rotasyon planı var.
  • Yönlendirme/liste senaryosu için ARC değerlendirildi.
  • swaks + Gmail "Show original" ile prod öncesi dkim=pass bizzat doğrulandı.