Exim ile E-posta Başlığı Yeniden Yazma ve Mesaj Manipülasyonu

Mail sunucusu yönetiminde en sık karşılaşılan ihtiyaçlardan biri, gönderilen veya alınan e-postaların header bilgilerini değiştirmek ya da mesaj içeriğini belirli kurallara göre manipüle etmektir. Exim, bu konuda son derece güçlü ve esnek bir yapı sunar. Hem küçük ölçekli hosting ortamlarında hem de kurumsal mail altyapılarında header rewriting ve mesaj manipülasyonu ihtiyacı kaçınılmaz olarak karşınıza çıkar. Bu yazıda Exim’in bu yeteneklerini gerçek dünya senaryolarıyla detaylı biçimde ele alacağız.

Header Rewriting Nedir ve Neden Gerekli?

E-posta header’ları, bir mesajın kim tarafından, nereden, ne zaman gönderildiğini ve hangi sunuculardan geçtiğini tanımlayan metadata alanlarıdır. Bazı durumlarda bu header’ları değiştirmek zorunlu hale gelir.

Yaygın senaryolar şunlardır:

  • Şirket içi kullanıcıların [email protected] gibi internal adresler yerine [email protected] ile dışarıya mail atması
  • Birden fazla domain’i tek Exim instance üzerinden yönetirken doğru From adresinin sağlanması
  • Eski sistemlerden gelen kötü formatlanmış header’ların düzeltilmesi
  • Gizlilik nedeniyle iç altyapı bilgilerinin dışarıya sızmasının engellenmesi
  • Spam filtrelerinde sorun çıkaran eksik ya da hatalı header’ların tamamlanması

Exim’de Header Rewriting Mekanizması

Exim’de header manipulation iki farklı katmanda yapılabilir: router/transport seviyesinde ve global rewrite kuralları aracılığıyla. Her iki yöntemin de kullanım alanları farklıdır.

Global Rewrite Kuralları

/etc/exim4/exim4.conf dosyasında (ya da bölünmüş yapıda /etc/exim4/conf.d/rewrite/) begin rewrite bölümü altında global kurallar tanımlanır. Bu kurallar tüm mesajlara uygulanır.

Temel söz dizimi şöyledir:

begin rewrite

# Kaynak_Pattern  Hedef_Adres  Bayraklar
*@internal.local  ${lookup{${local_part}}lsearch{/etc/exim4/rewrite_map}{$value}{$local_part}@sirket.com}  frFT

Bayrakların anlamları:

  • f: From header’ını yeniden yaz
  • r: Reply-To header’ını yeniden yaz
  • F: Envelope From adresini (MAIL FROM) yeniden yaz
  • T: Envelope To adresini (RCPT TO) yeniden yaz
  • s: Sender header’ını yeniden yaz
  • c: Cc header’larını yeniden yaz
  • b: Bcc header’larını yeniden yaz
  • h: Mesajdaki tüm header adreslerini yeniden yaz

Basit Domain Rewrite Örneği

Bir şirkette sunucunuzun hostname’i mail.internal.local olsun ve kullanıcılar bu domain’den mail atıyor olsun. Dışarıya giden maillerde bu adresi @sirketadi.com olarak göstermek istiyorsunuz:

begin rewrite

# Internal local domain adreslerini public domain'e cevir
*@internal.local   ${local_part}@sirketadi.com   frFTs
*@mail.internal.local  ${local_part}@sirketadi.com  frFTs

Bu kural hem header’lardaki adres bilgisini hem de SMTP envelope adresini dönüştürür. Restart gerekmez, exim -bV ile syntax kontrolü yapabilirsiniz:

exim -bV

Router Seviyesinde Header Manipülasyonu

Router’lar, Exim’in mesajları nereye ileteceğine karar verdiği bileşenlerdir. Bu noktada headers_add, headers_remove ve headers_rewrite direktifleri devreye girer.

headers_add Kullanımı

Bir mesaja yeni header eklemek için headers_add direktifini transport veya router bloğunda kullanabilirsiniz:

# /etc/exim4/conf.d/transport/30_exim4-config_remote_smtp

remote_smtp:
  driver = smtp
  hosts_try_auth = <; $host_address
  headers_add = "X-Mailer-Info: Sent via Corporate Mail Gatewayn
                 X-Organization: Sirket Adi A.S."
  tls_certificate = /etc/ssl/certs/mail.crt
  tls_privatekey = /etc/ssl/private/mail.key

Bu yapılandırma ile her dışa giden maile organizasyon bilgisi içeren custom header’lar eklenir. Özellikle mail tracking veya compliance gereksinimleri için oldukça kullanışlıdır.

headers_remove Kullanımı

Bazı durumlarda iç altyapı bilgilerini açığa çıkaran header’ları silmek istersiniz. Örneğin X-Originating-IP veya iç sunucu adlarını içeren Received header’ları:

remote_smtp_cleanup:
  driver = smtp
  headers_remove = "X-Originating-IP:X-PHP-Originating-Script:X-Source:X-Source-Args:X-Source-Dir"
  hosts_try_auth = <; $host_address
  message_size_limit = 52428800

Dikkat: Received header’larını silmek spam filtreleri açısından şüphe uyandırabilir ve bazı durumlarda SPF/DKIM doğrulamalarını bozabilir. Bu yüzden sadece gerçekten gereksiz olan header’ları kaldırın.

ACL ile Dinamik Header Manipülasyonu

Exim’in ACL (Access Control List) mekanizması, mesajları alış veya gönderim aşamasında koşullu olarak işleme sokmanıza olanak tanır. Bu, en güçlü ve en esnek yöntemdir.

DATA ACL ile Header Ekleme

# /etc/exim4/conf.d/acl/40_exim4-config_check_data

acl_check_data:

  # Spam skorunu header olarak ekle
  warn
    condition = ${if def:spam_score}
    message = X-Spam-Score: $spam_score
    message = X-Spam-Bar: $spam_bar

  # Sirket icinden gelen maillere departman bilgisi ekle
  warn
    condition = ${if match_domain{$sender_address_domain}{+local_domains}}
    set acl_m_dept = ${lookup{$sender_address_local_part}lsearch{/etc/exim4/dept_map}{$value}{Unknown}}
    message = X-Department: $acl_m_dept

  # Gecis zamanini ekle
  warn
    message = X-Processed-By: mailgw01.sirket.com at $tod_full

  accept

Bu ACL bloğu, spam skoru mevcut olan maillere skor bilgisini header olarak ekler, iç kullanıcıların departman bilgisini ekler ve her mesaja işlem zamanı bilgisi yazar.

Koşullu Header Rewrite

Belirli domain’lerden gelen maillerin From adresini değiştirmek isteyebilirsiniz:

# Router tanimlamasi
rewrite_from_router:
  driver = redirect
  condition = ${if match_domain{$sender_address_domain}{eski-sirket.com:eski-domain.net}}
  headers_rewrite = *@eski-sirket.com   ${local_part}@yeni-sirket.com  f
  headers_rewrite = *@eski-domain.net   ${local_part}@yeni-sirket.com  f
  allow_fail
  allow_defer
  data = :

Gerçek Dünya Senaryosu 1: Hosting Ortamında PHP Mail Düzenleme

Paylaşımlı hosting ortamlarında PHP’nin mail() fonksiyonu sıklıkla hatalı veya eksik From adresleriyle mail gönderir. Bu durumda mesajlar spam klasörüne düşer ya da bounce yönetimi zorlaşır. Aşağıdaki yapılandırma bu sorunu çözer:

# Transport tanimlamasi - PHP maillerini yakala ve duzelt
php_mail_transport:
  driver = smtp
  hosts = 127.0.0.1
  port = 25
  # PHP'nin gonderdigi mesajlardaki From adresini duzenle
  headers_rewrite = *@localhost   webmaster@${sender_host_name}  frFTs
  # PHP script bilgilerini gizle
  headers_remove = "X-PHP-Originating-Script:X-Source:X-Source-Args"
  # Organizasyon bilgisi ekle
  headers_add = "X-Mailer: PHP Application Mail"

# Router - localhost'tan gelen mailleri yakala
catch_php_mail:
  driver = accept
  condition = ${if eq{$sender_host_address}{127.0.0.1}}
  transport = php_mail_transport
  no_more

Bu yapılandırmayla PHP uygulamalarından gelen mailllerde localhost domain’i otomatik olarak gerçek hostname ile değiştirilir ve debugging header’ları temizlenir.

Gerçek Dünya Senaryosu 2: Çoklu Domain Yönetimi

Bir hosting firmasında 50 farklı müşterinin mail’ini tek Exim instance üzerinden yönettiğinizi düşünün. Her müşterinin kendi domain’i var ama SMTP auth kullanarak aynı sunucu üzerinden mail atıyorlar.

# /etc/exim4/conf.d/rewrite/50_multidomian_rewrite

begin rewrite

# Kimlik dogrulamis kullanicilarin adreslerini duzelt
# Kullanici veritabanindan gercek From adresini al
*  ${if authenticated{$authenticated_id}
     {${lookup mysql{SELECT email FROM mail_users 
                     WHERE username='${quote_mysql:$authenticated_id}' 
                     LIMIT 1}
               {$value}
               {$sender_address}}}
     {$sender_address}}
   fFs

Bu gelişmiş rewrite kuralı, kimlik doğrulaması yapan kullanıcıların mail adreslerini MySQL veritabanından çekerek otomatik olarak doğru From adresiyle değiştirir.

Gerçek Dünya Senaryosu 3: Mailing List Header Yönetimi

Bir mailing list uygulaması çalıştırıyorsanız, Reply-To header’larını düzenlemek kritik önem taşır:

# Mailing list transport
mailing_list_transport:
  driver = smtp
  # List adresine reply-to ekle
  headers_add = ${if match{$h_To:}{[email protected]}
                  {Reply-To: [email protected]
                   List-Unsubscribe: <mailto:[email protected]>n
                   List-Id: Sirket Listesi <liste.sirket.com>n
                   Precedence: list}
                  {}}
  # Orijinal gondericinin adresini koru ama list bilgisi ekle
  headers_rewrite = *  ${sender_address}  r
  return_path = [email protected]

String Expansion ile Gelişmiş Rewrite

Exim’in string expansion motoru, header rewriting’i son derece dinamik hale getirir. Değişkenler, koşullar ve lookup fonksiyonları bir arada kullanılabilir:

# Zaman bazli header rewrite ornegi
begin rewrite

# Mesai saatleri disinda gelen maillere out-of-office bilgisi ekle
# (Bu ornekte header ekleme yapilir, gercekte auto-reply icin farkli yaklasim gerekir)
*@sirket.com  ${if >{$tod_epoch}{$value}
               {[email protected]}
               {[email protected]}}
              frFT

Daha pratik bir örnek olarak, gelen mail adreslerini normalize etmek (büyük/küçük harf tutarlılığı sağlamak) için:

begin rewrite

# Tum adresleri kucuk harfe donustur (case normalization)
# local part buyuk harf iceriyorsa kucultur
*@sirket.com  ${lc:$local_part}@sirket.com  T
*@*.sirket.com  ${lc:$local_part}@${lc:$domain}  T

Header Rewrite Kurallarını Test Etme

Yazdığınız kuralların doğru çalışıp çalışmadığını production’a almadan önce test etmek kritiktir. Exim bu konuda birkaç yararlı araç sunar:

# Syntax kontrolu
exim -bV

# Belirli bir adres icin rewrite sonucunu goster
exim -brw [email protected]

# Test mesaji gondererek header'lari incele
echo "Test mesaji" | exim -v -f [email protected] [email protected] 2>&1 | head -50

# Mail queue'daki bir mesajin header'larini goster
exim -Mvh MESAJ_ID

# Routing kararini goster (rewrite dahil)
exim -bt [email protected]

exim -brw komutu özellikle değerlidir, çünkü sadece rewrite sonucunu gösterir ve neyin nasıl değiştiğini açıkça ortaya koyar. Bir adres için birden fazla kural varsa hangisinin uygulandığını da görebilirsiniz.

Güvenlik Konuları ve Best Practice’ler

Header manipülasyonu güçlü bir araç olduğu kadar yanlış kullanıldığında ciddi güvenlik sorunlarına da yol açabilir.

Dikkat edilmesi gereken konular:

  • DKIM imzalama ile çakışma: Header rewrite DKIM imzalamadan önce mi sonra mı yapıldığına dikkat edin. İmzaladıktan sonra From veya Subject gibi imzalanmış header’ları değiştirirseniz DKIM doğrulaması başarısız olur. Exim’de imzalama genellikle transport aşamasında yapıldığından rewrite önce gerçekleşir, ama bunu mutlaka test edin.
  • SPF uyumu: Envelope From adresini değiştirirken SPF kayıtlarınızın yeni adresi kapsadığından emin olun.
  • Loop detection: Rewrite kuralları yanlış yazılırsa mail loop’larına neden olabilir. exim -bt ile routing’i mutlaka test edin.
  • Logging: Header değişikliklerini log’a almak için log_selector = +all_parents +subject ayarını kullanabilirsiniz.
# Exim log ayarlari - header degisikliklerini takip icin
log_selector = +all_parents +subject +sender_on_delivery 
               +incoming_interface +received_sender

Performans Optimizasyonu

Büyük ölçekli ortamlarda çok sayıda rewrite kuralı performansı olumsuz etkileyebilir. Bunu minimize etmek için birkaç öneri:

  • Rewrite kurallarını en spesifik’ten en genel’e doğru sıralayın, böylece early match gerçekleşir
  • lsearch yerine mümkünse dbm veya cdb format lookup dosyaları kullanın, bunlar çok daha hızlıdır
  • MySQL lookup kullanıyorsanız bağlantı sayısını mysql_servers ile sınırlandırın
  • Gereksiz regex kullanmaktan kaçının, sabit string eşleştirmeleri çok daha hızlıdır
# Yavaş lsearch yerine cdb (Constant Database) kullan
# Once cdb olustur:
# makemap cdb /etc/exim4/rewrite_map.cdb < /etc/exim4/rewrite_map.txt

begin rewrite
*@internal.local  ${lookup cdb{/etc/exim4/rewrite_map.cdb}{$local_part}{$local_part}@sirket.com}  frFTs

Troubleshooting: Yaygın Sorunlar ve Çözümleri

Problem: Rewrite kuralı çalışıyor ama DKIM doğrulaması başarısız oluyor.

Çözüm: DKIM imzalamayı rewrite’tan sonra gerçekleştirdiğinizden emin olun. Exim’de bu genellikle transport seviyesinde dkim_domain ve dkim_selector direktifleriyle yönetilir. Rewrite kuralları DKIM imzalamadan önce uygulandığı için sorun genellikle yanlış header’ın imzalanmasından kaynaklanır.

Problem: headers_remove ile sildiğiniz header hala görünüyor.

Çözüm: Header adının büyük/küçük harf duyarlılığını kontrol edin. exim -Mvh MESAJ_ID ile ham header’ları görüntüleyip tam adı kopyalayın.

Problem: Rewrite sonrası bounce mailleri yanlış adrese gidiyor.

Çözüm: Envelope From (F bayrağı) ve From header (f bayrağı) arasındaki farkı gözden geçirin. Bounce’lar envelope adresine döner, görünen adrese değil.

# Detayli debug modu ile problemi tespit et
exim -d+rewrite -v -f [email protected] [email protected] < /dev/null 2>&1 | grep -i rewrite

Sonuç

Exim’in header rewriting ve mesaj manipülasyonu yetenekleri, mail altyapısı yöneticilerine son derece geniş bir kontrol imkanı sunar. Global rewrite kurallarından ACL tabanlı dinamik manipülasyona, basit header ekleme/silme işlemlerinden veritabanı destekli karmaşık dönüşümlere kadar neredeyse her senaryo için bir çözüm mevcuttur.

Bu yazıda ele aldığımız konuların özeti şöyle sıralanabilir:

  • begin rewrite bölümü global adres dönüşümleri için temel araçtır ve bayrak sistemi esneklik sağlar
  • headers_add ve headers_remove transport ve router seviyesinde ince ayar yapmanıza olanak tanır
  • ACL’ler koşullu ve dinamik manipülasyon için en güçlü yöntemdir
  • String expansion motoru rewrite kurallarını programatik hale getirir
  • Test araçları özellikle exim -brw production’a geçmeden önce mutlaka kullanılmalıdır

Mail sunucusu yönetiminde en kritik kural her zaman geçerlidir: değişikliklerinizi test ortamında doğrulayın, log’ları aktif tutun ve özellikle DKIM/SPF gibi authentication mekanizmalarıyla etkileşimi göz ardı etmeyin. İyi yapılandırılmış bir Exim kurulumu, karmaşık mail akış gereksinimlerini zarif biçimde karşılayabilir.

Yorum yapın