Bios.Mail 0.2.0
Bios.Mail
Kurumsal posta için üç parça: mesaj modeli, outbox sözleşmesi ve gönderim kanalları.
Mesaj modeli. EmailMessage düz metni zorunlu tutar, HTML'i seçimlik
bırakır. Yalnız HTML olan bir işlem postası metin istemcide okunamaz, ekran
okuyucuya kapalıdır ve spam filtrelerinde daha kötü puan alır; düz metin asıl
mesajdır, HTML süstür.
Outbox sözleşmesi. IEmailOutbox mesajı, onu doğuran transaction'ın
içinde kuyruğa yazdırır. Gönderim isteğin içinde yapılsaydı SMTP'nin zaman
aşımı, davetiyesi kaydedilmiş ama haberi verilmemiş kullanıcılar bırakırdı.
Gönderim kanalları. SmtpEmailTransport MailKit ile gönderir; framework'ün
kendi SmtpClient'ı bilerek kullanılmaz, çünkü modern TLS'i konuşmaz ve Türkçe
konu satırlarını bozar. LoggingEmailTransport geliştirme içindir: göndermez,
gövdeyi kütüğe yazar.
Ayarların doğrulaması açılışta çalışır ve sessiz kayıp durumlarını reddeder: üretimde Log kanalı, TLS'siz bırakılmış ve bunun bilincinde olunmayan bir aktarıcı, adressiz ya da adsız gönderen gibi.
Bağlama
services.AddBiosMailTransport(configuration); // Mail bolumunu okur
// kuyrugu ve gonderen servisi urun ekler:
services.AddScoped<IEmailOutbox, PostgresEmailOutbox>();
services.AddHostedService<EmailSender>();
Kuyruğa yazmak, işi doğuran transaction'ın içinde olur:
await _outbox.QueueAsync(new EmailMessage
{
ToAddress = "ornek@buro.com.tr",
Subject = "Davetiniz",
BodyText = "Buroya davet edildiniz: ...",
BodyHtml = null,
}, ct);
Gönderen servisin döngüsü sözleşmenin verdiği dört adımdır: ClaimAsync ile
sırası gelenleri al, IEmailTransport.SendAsync ile gönder, sonucuna göre
MarkSentAsync ya da MarkFailedAsync çağır.
Yapılandırma
Bölüm adı: Mail.
| Anahtar | Zorunlu | Varsayılan | Ne işe yarar |
|---|---|---|---|
Transport |
hayır | Log |
Smtp ya da Log. Log göndermez, gövdeyi kütüğe yazar ve Development dışında açılışı durdurur. |
Host |
Smtp'de evet | boş | SMTP sunucusunun adı. |
Port |
hayır | 587 |
1–65535 arası olmalı. |
Username |
hayır | boş | Boş bırakılırsa sunucunun kimlik istemediği varsayılır. Password ile birlikte dolu ya da birlikte boş olmalı. |
Password |
hayır | boş | Yukarıdaki ile aynı kural. |
RequireTls |
hayır | true |
TLS'in yalnız önerilmesi değil, zorunlu olması. Ağdan geçen her bağlantıda doğru cevap budur. |
AcknowledgeInsecureRelay |
RequireTls false ise evet |
false |
TLS'i kapatmanın kaza değil karar olduğunun beyanı. İkisi birden verilmezse açılış durur. |
FromAddress |
evet | boş | Gönderen adresi. Olmadan hiçbir mesaj gönderilemez. |
FromName |
evet | yok | Alıcının adresin yanında okuduğu ad. Aşağıya bak. |
SendingEnabled |
hayır | true |
Kapalıyken mesajlar kuyrukta birikir. Göndereni başka bir yerde koşan kurulumlar için. |
PollSeconds |
hayır | 30 |
Gönderenin kuyruğa iki bakışı arası. Pozitif olmalı. |
BatchSize |
hayır | 20 |
Bir turda kaç mesaj alınacağı. Pozitif olmalı. |
MaxAttempts |
hayır | 5 |
Bir mesajın vazgeçilmeden önce kaç kez denendiği. Pozitif olmalı; sürekli hatalı bir adresin arkasındaki mesajları tıkamaması için sonlu. |
RetryBaseSeconds |
hayır | 60 |
İlk yeniden deneme gecikmesi. Her denemede ikiye katlanır, bir günde durur. |
{
"Mail": {
"Transport": "Smtp",
"Host": "smtp.saglayici.com",
"Port": 587,
"Username": "gonderen@buro.com.tr",
"Password": "...",
"RequireTls": true,
"AcknowledgeInsecureRelay": false,
"FromAddress": "bildirim@buro.com.tr",
"FromName": "Acme Yazilim",
"SendingEnabled": true,
"PollSeconds": 30,
"BatchSize": 20,
"MaxAttempts": 5,
"RetryBaseSeconds": 60
}
}
Geliştirmede yeten en küçük blok şudur; Transport varsayılanı zaten Log:
{
"Mail": {
"FromAddress": "bildirim@localhost",
"FromName": "Acme Yazilim"
}
}
Poll ve RetryBase özellikleri, saniye cinsinden verilen bu iki ayarın
TimeSpan karşılığıdır; ayrıca yapılandırılmazlar.
Dikkat
FromName zorunludur ve varsayılanı yoktur. Verilmezse uygulama açılışta
durur. Sebebi şudur: bu paket birden çok ürün tarafından kullanılır ve
FromName alıcının gelen kutusunda okuduğu addır. Pakete bir varsayılan
konsaydı, o varsayılan hangi ürün önce yazıldıysa onun adı olurdu ve ikinci
ürünün postaları sessizce birinci ürünün adıyla imzalanırdı. Kimse bunu fark
etmez; bir müşteri gelen kutusunda yanlış adı okuyana kadar. Tek satırlık bir
ayar karşılığında bu hata sınıfı tamamen ortadan kalkar.
Bu paket gönderim kanalını taşır, kuyruğu boşaltmaz. Sınır tam olarak şuradadır:
| Bu paketin işi | Ürünün işi |
|---|---|
MailOptions ve açılış doğrulaması |
IEmailOutbox gerçeklemesi (veritabanı tabloları, SQL) |
IEmailTransport seçimi ve kaydı |
Kuyruğu boşaltan arka plan servisi |
EmailMessage, PendingEmail, OutboxRound tipleri |
Döngünün ne zaman ve nasıl koşacağı |
AddBiosMailTransport yalnız ayarları ve kanalı kaydeder. Hiçbir arka plan
servisi başlatmaz. Yani sadece bu çağrıyı yapıp QueueAsync ile mesaj
biriktiren bir ürün, hiçbir posta göndermez ve hiçbir hata da almaz — mesajlar
kuyrukta sessizce bekler. Göndereni ürünün kendisi AddHostedService ile
eklemek zorundadır.
Bunun bir sonucu şudur: SendingEnabled, PollSeconds, BatchSize,
MaxAttempts ve RetryBaseSeconds ayarları burada doğrulanır ama
okunmaz; onları okuyan, ürünün yazdığı gönderen servistir. Kendi göndereni
yazarken bu ayarlara uyman beklenir.
Üretimde Log kanalı açılışı durdurur. Bu, unutulmuş bir ayarın parola
sıfırlama bağlantılarını kütüğe yazıp hiçbir şey göndermemesini önlemek
içindir. Log yalnız IHostEnvironment Development derken kabul edilir —
dolayısıyla doğrulama ortama bakar ve bir birim testinde ortamı taklit etmen
gerekebilir.
TLS'i kapatmak iki ayar ister. RequireTls false, AcknowledgeInsecureRelay
verilmemişse açılış durur. Bunun sebebi, TLS'i kapatmanın çoğu zaman bir
bağlantı hatasını susturmak için yapılması ve sonucun, parola sıfırlama
belirtecinin ağdan açık geçmesi olmasıdır. Meşru durumu — makineden hiç
çıkmayan, loopback üzerindeki bir aktarıcı — kaza eseri yazılamayacak ikinci
bir ayarla ayırıyoruz.
Username ve Password birlikte gider. Yalnız biri doluysa açılış durur;
bu, kimlik istemeyen bir sunucu değil, yarım doldurulmuş bir kasa demektir.
No packages depend on Bios.Mail.
.NET 10.0
- MailKit (>= 4.17.0)