Amazon SES ve Saygınlık

aws
ses

(Sinan Islekdemir) #1

Hiç internette otel aradınız mı? Ben bunu arayanlar için hizmet veren dünyanın en büyük şirketlerinden birisinde 4.5 yıl hayatta kaldım. Maceram, müşteri destek platformlarını geliştirerek başlamıştı. Günde yüzlerce müşteri talebi, iç süreç takipleri, otomatik sistemlerin ürettiği bilgilendirmeler, yazılım geliştiricilerin debug için en sonsuz döngülerin içine dahi hunharca koydukları eposta gönderimleri. (Pek çoğu “…php: 232 Hit” gibi basit cümleler içeriyordu ve geliştiriciye bir bilgi postası atıyordu)
Her gün onbinlerce epostanın çıktığı bir sistemde hayatta kalmak pek kolay değildi. Bu süreçte öğrendiğim en önemli şey ise Bounce kavramı ve bunun nasıl yönetilmesi gerektiği idi.

Bu yazımı çok uzun tutmak istemiyorum çünkü konu uzun makaleler arasında kaybolmaması gerekecek kadar önemli. Basitçe bir okuyucu davranışı gözüyle bakmam gerekirse, biz artık okumuyor sadece tarıyoruz. Bir makale ne kadar uzunsa o kadar önemsizleşiyor. Yani, olabildiğince kısa tutmaya çalışmamın belirli sebepleri var.

Bounce demek, şu demek: Bir sebepten gönderdiğin eposta geri döndü. Postanı götürdük ama almadılar. Şimdi, gerçek dünyada şunu düşünün. Birisi var, size sürekli posta gönderiyor. Adamın gönderdiği mektuplardan ya reklam çıkıyor, ya güvenemeyeceğiniz ne olduğunu bilmediğiniz mesajlar geliyor, adamı tanımıyorsunuz bile. Sonra, size postayı getiren postacıya diyorsunuz ki, bu adam sapık mıdır nedir, bir daha bu adamdan posta almak istemiyorum. Postacı da bir daha o adamdan size posta getirmiyor. Sonra, sizin gibi başkaları da bu adamdan şikayet etmeye başlıyorlar. Postacı da, senin sapıklıklarınla uğraşamam, senin yüzünden ben laf yiyorum diyerek, toplumun ortak huzuru adına bu garip postaları gönderen adam ile selamı sabahı komple kesiyor. Bir de postacıların kendi aralarında paylaştıkları bir kara liste var, bu sapığı bu kara listeye ekliyor. İşte tam olarak eposta dünyası da bu şekilde işliyor.

Amazon SES ise hikayede tam olarak şöyle yer alıyor. Sizin yüzbin tane müşteriniz var ve yüzbinine birden bildirim göndermek için mektuplara pul yapıştırmak isteseniz muhtemelen pul yapıştırmakla ömrünüz solacak. Amazon SES, sizin yerinize tüm bu zarflama ve postayla gönderme işinin yükünü devralıyor. Tabi bu noktada, postaların göndericisi konumunda olduğu için, insanlar birisine sapık muamelesi yapacaklarsa, Amazon arada kalarak bu muameleye düşüyor. Sonuç olarak, Amazon’un sunucularının saygınlığı azalıyor bu tip sapıklar yüzünden.

Amazon SES burada şunu yapıyor. Eğer sizin gönderdiğiniz bir paket yerine ulaşmazsa, bunu size bildiriyor, buna “bounce” deniyor. Ve sizin gönderim sayınızla bounce adedinizi kıyaslayarak sizi belirli bir güvenli seviyede tutmak için gerekli adımları atmanızı bekliyor. Eğer sizin sapıkça hareket ettiğinize kanaat getirecek olursa, kendisini korumak adına size verdiği bu hizmeti sonlandırma hakkına da doğal olarak sahip. İşte bu noktada “bouce” yönetimi devreye giriyor.

Size verilen bu güzel hizmetin kesintiye uğramaması için çok basit bir önlem alabilirsiniz. Amazon, sizin SES üzerinden gönderdiğiniz her bir eposta için size bir ID verecektir. Öncelikle SES üzerinden gönderdiğiniz her epostayı mümkünse kayıt altına alın. En azından kime gönderdiğinizi ve ID’sinin ne olduğunu ve içinde dosya eki olup olmadığını. Çünkü ileride, bu bilgiye ihtiyacınız olabilir.
Amazon, işler ters gittiği zaman size iki tip bildirim gönderecektir. Bounce (geri dönüş) ve Complaint (şikayet). Complaint’in farkı şu, complaint kişiyi suçlamaya yönelik kasten iletilir. Postanın reddi değil, komple bela okumaktır.

SES bu mesajları size iletmek için bir SNS Topic kullanabilir. Ancak SNS Topic üzerinden bu mesajları yakalayıp kullanmaya çalışmak biraz sağlıksız. Sizin bu bildirimleri alacağınız uygulama her zaman cevap vermeyebilir. Arada gözden kaçan şeyler olabilir. Aynı zamanda, bir şeyler büyük ters gidecek olursa, kaldırabileceğinizden çok daha büyük bir bildirim taaruzuna maruz kalabilirsiniz. O yüzden sağlıklı olan şudur. Bir SQS Kuyruğu oluşturun. (Adına sqs_bounce_queue diyelim) bir de SNS Topic oluşturun (sns_bounce_notifications). SQS’in en verimli özelliklerinden birisi, bir SNS Topic’e yapışıp, oradan gelecek bildirimleri kuyruklayabilmesi. Siz ise SQS’i dinleyip kendi gücünüz yettiğince bu mesajları işleyebilirsiniz.

Gelelim neyi nasıl halledeceğinize.
Öncelikle Queue objeleri 256Kb’tan büyük olamayacağı için bu mesajlarda epostaların full içeriği yer almayacak ama ister Bounce ister Complaint olsun, içerisinde basit bir mail object içerecektir. Aşağı yukarı şuna benzeyecek:

{
  "timestamp":"2016-01-27T14:05:45 +0000",
  "messageId":"000001378603177f-7a5433e7-8edb-42ae-af10-f0181f34d6ee-000000",
  "source":"john@example.com",
  "sourceArn": "arn:aws:ses:us-west-2:888888888888:identity/example.com",
  "sourceIp": "127.0.3.0",
  "sendingAccountId":"123456789012",
  "destination":[
     "jane@example.com"
  ],
  "headersTruncated":false,
  "headers":[
     {
        "name":"From",
        "value":"\"John Doe\" <john@example.com>"
     },
     {
        "name":"To",
        "value":"\"Jane Doe\" <jane@example.com>"
     },
     {
        "name":"Message-ID",
        "value":"custom-message-ID"
     },
     {
        "name":"Subject",
        "value":"Hello"
     },
     {
        "name":"Content-Type",
        "value":"text/plain; charset=\"UTF-8\""
     },
     {
        "name":"Content-Transfer-Encoding",
        "value":"base64"
     },
     {
        "name":"Date",
        "value":"Wed, 27 Jan 2016 14:05:45 +0000"
     }
  ],
  "commonHeaders":{
     "from":[
        "John Doe <john@example.com>"
     ],
     "date":"Wed, 27 Jan 2016 14:05:45 +0000",
     "to":[
        "Jane Doe <jane@example.com>"
     ],
     "messageId":" custom-message-ID",
     "subject":"Hello"
  }
}

Gördüğünüz üzere içerisinde bir messageId bilgisi yer alıyor. Pek çok senaryoda aslında mesajınızın ID’sini saklamanıza gerek yok ancak birazdan anlatacağım senaryolardan birkaçında mesaj ile ilgili daha fazla bilgiye ihtiyaç duyabilirsiniz.

Ama burada uzun uzadıya bunu nasıl kod ile uygulayabileceğinizden bahsetmeyeceğim. AWS’nin dökümantasyonunda konu ile alakalı pek çok dilde SDK örneği görebilirsiniz. Ben neyi nasıl anlamlandırmanız gerektiğinizden bahsedeceğim.

Bir Bounce objesi şu şekilde görünecektir:

{
   "bounceType":"Permanent",
   "bounceSubType": "General",
   "bouncedRecipients":[
      {
         "status":"5.0.0",
         "action":"failed",
         "diagnosticCode":"smtp; 550 user unknown",
         "emailAddress":"recipient1@example.com"
      },
      {
         "status":"4.0.0",
         "action":"delayed",
         "emailAddress":"recipient2@example.com"
      }
   ],
   "reportingMTA": "example.com",
   "timestamp":"2012-05-25T14:59:38.605Z",
   "feedbackId":"000001378603176d-5a4b5ad9-6f30-4198-a8c3-b1eb0c270a1d-000000",
   "remoteMtaIp":"127.0.2.0"
}

Bounce senaryoları temelde ikiye ayrılırlar. Kalıcı ve geçici. (Permanent ve Transient). Bunu bounceType alanında görebilirsiniz.

Permanent bounce: Kalıcıdır. Tekrar denemeyin. Bazı yerlerde Hard Bounce olarak da görebilirisiniz.
Transient bounce: Geçicidir, tekrar denemekte fayda vardır. Buna da Soft Bounce dedikleri olur.

Permanent bounce sebepleri:

  • Undetermined: Amazon sebebini anlayacak kadar bilgi toplayamadı ama bir bildiği var ki, tekrar deneme diyor. Özellikle kötü kodlanmış eposta sunucularından gelen bilgiler bu kategoriye girebilir.

  • General: Hard bounce meydana geldi ama karşı sunucu konuyla ilgili bir detay bildirmedi.

  • NoEmail: Gönderimi denediğiniz eposta hesabı artık kullanılmıyor.

  • Suppressed: Amazon, önceki tecrübelerine dayanarak bu eposta adresinin her zaman hard bounce’a sebep olduğunu biliyor. Bu yüzden denemedi bile.
    Transient bounce sebepleri:

  • MailboxFull: Gönderimi yaptığınız posta kutusu dolu olduğu için eposta ulaşmadı. Kullanıcı eposta kutusunu boşalttığında tekrar denerseniz ulaşacaktır.

  • MessageTooLarge: Gönderdiğiniz eposta, sunucunun izin verdiği boyutun üzerinde. İşte burada messageId ile kendi loglarınızı gözden geçirmenizde fayda var. Bu kadar büyük bir eposta ile ilgili ciddi bir sorun var demektir.

  • ContentRejected: İçerik reddedildi. Tekrar loglara bakıp ne gönderdiğinizi kontrol edin. İçerikte sansürlenmesi gereken kelimeler, ifadeler yer alıyor olabilir. Hassas içerik içeriyor olabilir. Bir şekilde filtrelere takıldı demektir.

  • AttachmentRejected:Ve tekrar gönderim loglarınıza bakın mutlaka. Muhtemelen antivirüs sisteminden ya da başka bir mime tipinden dolayı gönderdiğiniz postadaki eklenti, sunucu tarafından kabul edilmedi.

Gördüğünüz gibi, başlangıçta bahsettiğim messageId’yi ve epostanızla ilgili bilgileri SES gönderimi esnasında kaydedin, lazım olacak dememin sebebi Transient Bounce durumunda problemi gerçekten çözmek istiyorsanız, buradaki bilgiye ihtiyacınız olacak olması.

Sonrasında bir karar almalısınız. Bu karar genellikle hard bounce durumunda gönderim denediğiniz eposta adreslerini bir kara listeye alarak onlara tekrar gönderim denememektir. Transient durumunda ise, tekrar aynı içeriği aynı eposta adreslerine göndermeyi denemeyin. Eğer durum çok yoğunsa, geçici süreyle eposta adreslerini kara listenize ekleyip bir süre gönderimi erteleyebilirsiniz. (MailboxFull senaryosu gibi)

Bir diğer konu da Complaint yani şikayet demiştik. Bu daha ziyade kullanıcı davranışıdır. Kasıtlıdır. Birisi açık bir şekilde sizden gönderim almak istemediğini belirtmiştir. Genellikle buna karşı bir önlem almazsanız, gönderdiğiniz epostalar sistemlerde “spam” kutusuna gitmeye başlayacaktır.

{
   "userAgent":"AnyCompany Feedback Loop (V0.01)",
   "complainedRecipients":[
      {
         "emailAddress":"recipient1@example.com"
      }
   ],
   "complaintFeedbackType":"abuse",
   "arrivalDate":"2009-12-03T04:24:21.000-05:00",
   "timestamp":"2012-05-25T14:59:38.623Z",
   "feedbackId":"000001378603177f-18c07c78-fa81-4a58-9dd1-fedc3cb8f49a-000000"
}

Compaint’in göreceğiniz üzere complaintFeedbackType bilgisi size sebebini anlatacaktır.

  • abuse: Gönderimi yapan kişinin (sizin) kötü niyetli olduğunu belirtir.
  • auth-failure: Bu auth-failure raporudur.
  • fraud: dolandırıcılık şüphesi.
  • not-spam: Gönderdiğiniz epostanın spam olmadığını belirtir. Aslında tam bir complaint sayılmaz, sadece aynı yolla iletilen bir feedback bilgidir.
  • other: diğer
  • virus: virüs.

Not-Spam hariç senaryolarda, complainedRecipients’a tekrar gönderim yapmayı durdurmanız gerekir. Not-Spam ise, kusura bakma yanlışlıkla complaint yaptım, beni kara listeden çıkarabilirsin, eposta almayı isterim demektir.

Peki tüm bunlara uymazsak ne olur? Genellikle bunun sonucu gönderdiğiniz epostaların spam’e gitmesiyle başlar, Amazon’un hizmetinizi sonlandırması ile nirvanaya ulaşır. Aynı zamanda şirket / kurum / kişi saygınlığınızın bir karşılığıdır. Dikkat edilmesi gerekir. Bu yüzden, Amazon şahsi kanaatimce toplu reklam gönderimi yapılacak bir platform asla değildir. Daha amaca yönelik kullanılmalıdır ve reklam gibi toplu umursamaz, hayasızca, utanmaz, kötü, çirkin gönderimler için, özellikle reklam hizmeti veren toplu gönderim hizmetleri seçilebilinir.