Kategoriler

SMTP Eposta Gönderimi

C# ile Template Kullanarak SMTP Gönderimi

SMTP(Simple Mail Transfer Protocol) programlarımız içerisinden otomatik yada isteğe göre doldurularak eposta göndermemizi sağlar.

SMTP, Explicit(açık) ve Implicit(örtük) olarak gönderilir. Bu yöntemler bizim back-end'imizin çalıştığı web sunucumuz ile SMTP sunucularına erişimde kullandığımız bağlantı şekilleridir. Kodlama yaparken çok az farklılıklarla aynı eposta gönderimi yapılır. Kabaca sunucu ile smtp iletişimini şifreleme ile alakalıdır.

Örneğin bir sunucuda SMTP mail server olsun. Aynı localhost'ta web server'ımız ile iletişim halinde iken ekstra protokollere ihtiyaç duymadan standart explicit bağlantı kullanırız. SMTP mail server'ımızın başka sunuculardan, yani dış kaynaklardan eposta göndermesini de isteyebiliriz. Burada ise en doğru bağlantı şekli şifrelenmiş olan implicit yöntem olacaktır.


Gösterilen başlıklar

  1. Kullandığım Template (Şablon)
  2. Eposta Gönderiminde Kullandığım Sınıf
  3. Email Template Almakta Kullandığım Sınıf
  4. Explicit SMTP
  5. Implicit SMTP
  6. Sonuç

1. Kullandığım Template (Şablon)

Burada kastetdiğim şablon-template düz html dosyası aslında. https://github.com/leemunroe/responsive-html-email-template  adresinde örnekleri görebilirsiniz. İnternet üzerinde de 'free email template' şeklinde arama yapabilirsiniz. İçerisinde aşağıda gösterildiği gibi yerine istediğimiz değerleri koyduğumuz alanları mevcut.

<h1>{Title}</h1>

Yukarıdaki örnekte gördüğünüz h1 etiketi içerisinde {Title} değerini istediğimiz bir değer ile c# içerisinde değiştiriyoruz. Burada çeşitli html şablonları kullanabiliriz. Aslında template ile ilgili yapacağımız tüm işlem bu değiştirme işi...


2. Eposta Gönderiminde Kullandığım Sınıf

[ValidateInput(false)]
[HttpPost]
[ValidateAntiForgeryToken]
[Obsolete]
public ActionResult EpostaGonder(string eposta, string tip)
{
    //parametre de gelen eposta ile ilgili bir kullanıcı var mı?
    if(!_context.Kullanicilar.Any(a => a.Eposta == eposta))
    {
        //Olmaması durumunda Bu kişi bulunamadı olarak geri bilgi döndediyoruz.
        TempData["Toastr"] = Bildirim.Toastr("warning", "Böyle bir kullanıcı bulunamadı!");
        return View();
    }

    //Kullanıcı bilgilerini veritabanından alıyoruz
    var kullanici = _context.Kullanicilar.SingleOrDefault(s => s.Eposta == eposta)

    #region EPOSTA GÖNDER

    //alınan bilgilerle gönderimde gerekli olacak postatip değişkeni tanımlıyoruz.
    var postaTip = new Models.Eposta.PostaTip() 
                                        {   Tip = tip, //template seçiminde kullanılacak
                                            Kullanici = kullanici.Username, // bulunan kullanıcı bilgileri
                                            KullaniciAdSoyad = kullanici.Ad + " " + kullanici.Soyad, // Eposta da ismine yer vermek için
                                            Link = System.Configuration.ConfigurationManager.AppSettings["butonUrl"], // Email içinde yer alacak olan link için
                                        };

    var posta = new Posta()
    {
        Kime = kullanici.Eposta,
        Konu = "Bilgilendirme",
        Mesaj = EpostaIslem.TemplateVer(postaTip), // oluşturduğumuz posta tipi ile template i doldurarak geri alıyoruz.
    };

    //Email Class ile yeni bir nesne oluşturuyoruz
    var emailClass = new EmailClass();

    //Burada posta değikenimiz ile önce Explicit denemesi yapıyoruz, olmaması durumunda implicit denemesi yapıyoruz.
    var explicitSonuc = emailClass.ExplicitEpostaGonder(posta);
    if (explicitSonuc.BasariliMi)
    {
        TempData["Toastr"] = Bildirim.Toastr("success", "Başarılı", "Eposta gönderildi.");
    }
    else
    {
        var implicitSonuc = emailClass.ImplicitEpostaGonder(posta);
        if (implicitSonuc.BasariliMi)
        {
            TempData["Toastr"] = Bildirim.Toastr("success", "Başarılı", "Eposta gönderildi.");
        }
        else
        {
            TempData["Toastr"] = Bildirim.Toastr("error", "Eposta gönderilirken bir hata oluştu!");
        }
    }
    #endregion

    return View();
}

Yukarıdaki kodumuz bir Asp.Net Framework ile yazılmış MVC yapısındaki bir action örneğidir. Bu örnekte; POST ile gelen bir istekte, eposta ve tip beklenmektedir. Burada eposta kullanıcı tespiti için, tip ise html template'in hangisi olduğunu anlamamız ve ilgili dosyayı çekebilmemiz için gerekli. Önce eposta ya bağlı bir kullanıcı var mı, kontrolünü veritabanı bağlantımızdan yapıyoruz. Eposta ile ilişkili kullanıcı bulamazsa, bir uyarı ile geri dönderiyoruz. Devamında, email şablonumuzu istediğimiz bilgilerle doldurmak için bir postatip değişkeni oluşturup içeriğini kullanıcı ve eposta tip bilgileri ile dolduruyoruz. Bu model'imiz, bir çok şablona erişim ve içeriğini doldurma amaçlı kullandığımız bir yapı.

public class PostaTip
{
    public string Tip { get; set; }
    public string Link { get; set; }
    public string ProjeLink { get; set; }
    public string KullaniciAd { get; set; }
    public string KullaniciAdSoyad { get; set; }
    public string Sifre { get; set; }
    public string Mesaj { get; set; }
}

Devamında, posta değişkeni tanımlıyoruz. Bu değişkende ise eposta'nın kime gideceğini, Konusunu ve Mesaj'ımızı içeriyor. Burada ki mesaj string bir mesaj, içeriğini direk kendimiz belirtebileceğimiz gibi, aynı mantıkla şablon içerisinden de aktarabiliriz. Eposta şablonlarımı okuyup, içlerini doldurduğum bir TemplateVer fonksiyonunu kullandığımı görebilirsiniz. Bu fonksiyon içeriğine bakalım.


3. Email Template Almakta Kullandığım Sınıf

//posta tip dosyaya erişip istediğim noktaları değiştiriyorum.
public static string TemplateVer(PostaTip postaTip)
{
    // geri dönderilecek olan boş bir string oluşturuyoruz.
    string body = string.Empty;

    // Burada posta tip bilgisi benim için şablonlarımın arasındaki dosya adı
    // Hangi dosyayı seçeceğimize yönleniyoruz.
    if (postaTip.Tip == "SifreVer")
    {
        //burada dosya yolunda body değişkenimize aktarımını yapıyoruz
        using (StreamReader reader = new StreamReader(HttpContext.Current.Server.MapPath("~/App_Data/emailtemplate/" + postaTip.Tip + ".html")))
        {
            body = reader.ReadToEnd();
        }

        //html de bulunan değişmesi gereken alanları posta tip gelen bilgilerle değiştiriyoruz.
        body = body.Replace("{Title}", "Başlık");
        body = body.Replace("{Url}", postaTip.Link);
        body = body.Replace("{ProjeLink}", postaTip.ProjeLink);
        body = body.Replace("{KullaniciAd}", postaTip.KullaniciAd);
        body = body.Replace("{KullaniciAdSoyad}", postaTip.KullaniciAdSoyad);
        body = body.Replace("{Sifre}", postaTip.Sifre);
    }
    else if (postaTip.Tip == "OzelPosta")
    {
        using (StreamReader reader = new StreamReader(HttpContext.Current.Server.MapPath("~/App_Data/emailtemplate/" + postaTip.Tip + ".html")))
        {
            body = reader.ReadToEnd();
        }

        body = body.Replace("{Title}", "---gönderen adınız---");
        body = body.Replace("{Url}", postaTip.Link);
        body = body.Replace("{ProjeLink}", postaTip.ProjeLink);
        body = body.Replace("{Mesaj}", postaTip.Mesaj);
    }
    else
    {
        body = "Oluşturulurken bir hata oluştu. Mesaj alınamadı...";
    }

    return body;

}

Bu fonksiyonumuz bize hangi şablonu alacağımızı ve hangi bilgileri değiştireceğimizi gösteriyor. if-else if -else yapısı ile dosya yönelimini tamamlayıp, posta tip içerisinde bulunan diğer ihtiyaç duyulan verilerle "Replace" yani yer değiştirme yaparak, mesaj içeriğini oluşturan body değişkenini geri döndediriyorum.


4. Explicit SMTP İç Yapısı

public PostaSonuc ExplicitEpostaGonder(Posta data)
{
    try
    {
        //ConfigurationManager.AppSettings olarak görülen yerlerden her biri web.config dosyam içerisinde yer alan key'lerdir.
        MailAddress gonderenAdresi = new MailAddress(ConfigurationManager.AppSettings["smtpUser"], "Gönderen Ad Soyad vb.");

        MailAddress alanAdresi = new MailAddress(data.Kime);

        MailMessage posta = new MailMessage();

        SmtpClient sunucu = new SmtpClient();

        //SMTP Sunucu adresiniz string olarak
        sunucu.Host = "--smtp.domain.com--- gibi";
        sunucu.Credentials = new NetworkCredential(ConfigurationManager.AppSettings["smtpUser"], ConfigurationManager.AppSettings["smtpPass"]);

        posta.From = gonderenAdresi;
        posta.To.Add(alanAdresi);
        posta.Subject = data.Konu;
        posta.Body = data.Mesaj;
        posta.IsBodyHtml = true;

        sunucu.Send(posta);


        return new PostaSonuc() { BasariliMi = true, Hata = "Yok" };

    }
    catch (Exception ex)
    {
        return new PostaSonuc() { BasariliMi = false, Hata = ex.ToString() };
    }
}

Yukarıda gösterilen ExpliciEpostaGonder fonksiyonu Posta sınıflı bir parametre bekliyor ve karşılığında da PostaSonuc dönderiyor. Burada MailAddress sınıfı System.Net.Mail içerisinde bulunuyor. Gönderen ve kime gönderileceği bildirildikten sonra boş bir MailMessage oluşturuluyor. SmtpClient ile sunucu bağlantıları tamamlandıktan sonra paratemetrede gelen Posta verisi ile eposta'nın konusu, içeriği dolduruluyor. Dikkat ettiyseniz template aldığımızda string olarak alıyoruz. String olan html kodunu belirtmek ve düzgün gösterilmesi için "IsBodyHtml" seçimini true olarak işaretliyoruz. "Send" işlemi ile postayı gönderiyoruz. Tüm bu işlemleri try catch bloğunda yer alıyor. Her hangi hata olması durumunda geriye false ve hata dönüyor. Yoksa başarılı bir şekilde gönderiliyor. Bu gönderimler garanti edilmez, mail sunucunuzun o anki durumuna göre gecikmeler olabilir. Bu işlemin dönüşü başarısız olduğunda hemen altında bulunan Implicit göndermeye geçiş yapıyor. Implicit aşağıda inceleyelim.


5. Implicit SMTP İç Yapısı

public PostaSonuc ImplicitEpostaGonder(Posta posta)
{
    try
    {
        //web config üzeirnden gerekli sunucu bilgileri alınıyor.
        var host = ConfigurationManager.AppSettings["smtpHost"];
        var port = int.Parse(ConfigurationManager.AppSettings["smtpPort"]);

        //Mailkit ile yeni bir istemci tanımlıyoru ve bilgilerimizle bağlantı kurmayı deniyoruz.
        var client = new MailKit.Net.Smtp.SmtpClient();
        client.Connect(host, port, bool.Parse(ConfigurationManager.AppSettings["enableSsl"]));

        client.AuthenticationMechanisms.Remove("XOAUTH2");

        client.Authenticate(ConfigurationManager.AppSettings["smtpUser"], ConfigurationManager.AppSettings["smtpPass"]);

        var msg = new MimeMessage();
        msg.From.Add(new MailboxAddress("--gönderen adı--", ConfigurationManager.AppSettings["adminEmail"]));
        msg.To.Add(new MailboxAddress(posta.Kime));
        msg.Subject = posta.Konu;


        var bodyBuilder = new BodyBuilder();
        bodyBuilder.HtmlBody = posta.Mesaj;
        msg.Body = bodyBuilder.ToMessageBody();

        client.Send(msg);
        client.Disconnect(true);

        return new PostaSonuc() { BasariliMi = true, Hata = "Yok" };
    }
    catch (Exception ex)
    {
        return new PostaSonuc() { BasariliMi = false, Hata = ex.ToString() };
    }
}

 

Implicit kullanım için MailKit kütüphanesini kullanıyorum. İhtiyaç duyduğunuz kütüphaneleri "nuget package manager" ile yükleyebilirsiniz. Temel mantık olarak Explicit ile aynı çalışıyor aslında. Burada önce bağlanıp, kimliğimizi doğruluyoruz, sonrasında benzer şekilde mesaj içeriğini dolduruyoruz. Send işleminden sonra istemciyi kapatıyoruz. Farklı kaynaklardan smtp kullanacaksınız bu yöntem daha güvenli diyebiliriz. Burada da süreç try catch yapısı içerisinde olumlu ya da olumsuz dönüş sağlıyor.


6. Sonuç

Çalışır durumdaki kodunu örnek olarak ayırdıktan sonra burada paylaşımını yapacağım. Süreçler ilk bakışta kafa karıştırıcı gelsede, dikkatli bakarsanız kolayca anlayabilirsiniz. Normalde birini kullansak yetmez mi? diye düşünebilirsiniz. Doğru genelde yeteceği durumlarla karşılaşırsınız. Benim karşılaştığım bir problem sonucu bu şekilde bir tasarım yaptım. Yani sistem ilk olarak explicit deneyip sonra olmazsa implicit gönderimi yapmaya çalışıyor. Bulunduğum sunucuda dış kaynaklı olarakta gönderim ihtiyacım doğduğundan implicit yapmak durumunda kaldım. İhtiyacınıza göre bunun birini ya da buradaki gibi ikisini birden kullanabilirsiniz. 

ConfigurationManager.AppSettings olarak gördüğünüz alanlar tekrar hatırlatayım web.config dosyanızdan geliyor. Örnek olarak;

  <!--  Configuration altında yer alacak olan -->
  <appSettings>
   
    <!-- BEGIN:: EPOSTA BİLGİLERİ -->
    <add key="smtpHost" value="---smtp.mail.host.tr---" />
    <add key="enableSsl" value="true" />
    <add key="smtpPort" value="587" />
    <add key="smtpUser" value="---buhosttaki eposta adrsiniz---" />
    <add key="smtpPass" value="---sunucu bağlantı şifreniz---" />
    <add key="adminEmail" value="---buhosttaki eposta adrsiniz---" />
    <!-- END:: EPOSTA BİLGİLERİ-->
   
  </appSettings>

Başarılar dilerim. İyi çalışmalar :)

 

 

 

 

logo
Erdi Kalleci
Programlardan istediğimiz şablonları kullanarak eposta gönderimine yer verdim.