2012-09-14 39 views
11

Chúng tôi đang sử dụng SES AWS để gửi thư. Amazon SES gửi thông báo phản hồi và khiếu nại qua emails or AWS SNS. Chúng tôi muốn tự động xử lý thông báo phản hồi và khiếu nại (đến từ email hoặc AWS SNS) để trích xuất các id email để các email này có thể bị xóa khỏi danh sách gốc.Tự động xử lý các thông báo SES của Amazon về thông báo trả lại và khiếu nại

Một cách để tự động hóa là gửi các thông báo này đến chủ đề trong AWS SNS, sau đó đăng ký chủ đề bằng AWS SQS và cuối cùng đọc các tin nhắn trong AWS SQS. SNS hỗ trợ đăng ký qua các giao thức sau - HTTP/HTTPS/EMail/EMail (JSON)/SMS/SQS. Điều này là khả thi, nhưng tôi thấy nó quá cồng kềnh cho một nhiệm vụ đơn giản tự động xử lý các thông báo bị trả lại và khiếu nại.

Có cách nào thanh lịch để giải quyết vấn đề này không?


Tôi đã tìm thấy blog entry từ Amazon với mã trong C#. Có giải pháp nào tốt hơn không?

Trả lời

2

Tôi nghĩ cách bạn mô tả IS có lẽ là cách thanh lịch nhất. Bạn đã có các dịch vụ rất thích hợp trong SNS và SQS đã liên kết SDK với hầu hết các ngôn ngữ chính để cho phép bạn thực hiện những gì bạn cần một cách dễ dàng. Phần khó nhất là viết mã để cập nhật/xóa các bản ghi trong danh sách gửi thư của bạn.

10

Tôi thấy rằng việc đăng ký trực tiếp SNS bằng cách sử dụng điểm cuối HTTP là cách tiếp cận đơn giản nhất. Bạn nghĩa đen phải viết chỉ một vài dòng mã. Đây là ví dụ django của tôi:

def process(request): 
    json = request.raw_post_data    
    js = simplejson.loads(json) 
    info = simplejson.loads(js["Message"]) 
    type = info["notificationType"]   # "Complaint" or "Bounce" 
    email = info["mail"]["destination"][0] 


    # do whatever you want with the email 
+0

Điều này ít đáng tin cậy hơn khi sử dụng SQS - như thể nó không thành công sẽ không bao giờ thử lại - do đó SQS thích hợp hơn. – niico

1

Gần đây, tôi có thể làm việc này bằng cách sử dụng Điểm cuối HTTP qua SNS. Tôi sử dụng python/django để tiêu thụ thông báo. Bạn phải xử lý thông báo đăng ký trước khi bạn sử dụng các thông báo; bạn có thể đọc về các đăng ký trong tài liệu SNS.

Tôi nghĩ nếu bạn có một ứng dụng nhỏ hơn không gửi nhiều email; http endpoint sẽ hoạt động tốt. Mã này yêu cầu bạn phải tạo một mô hình thông báo.

#process an amazon sns http endpoint notification for amazon ses bounces and complaints 
@csrf_exempt 
def process_ses_notification(request): 

    if request.POST: 

     json_body = request.body 
     #remove this control character(throws an error) thats present inside the test subscription confirmation 
     js = loads(json_body.replace('\n', '')) 

     if js["Type"] == "SubscriptionConfirmation": 

      subscribe_url = js["SubscribeURL"] 
      urllib.urlopen(subscribe_url) 
      return HttpResponse(status=200) 

    elif js["Type"] == "Notification": 

     #process message from amazon sns 
     arg_info = loads(js["Message"]) # may need to use loads(js["Message"]) after testing with amazon 
     arg_notification_type = arg_info["notificationType"] 

     if arg_notification_type == 'Bounce': 
      #required bounce object fields 
      arg_emails=arg_info["bounce"]["bouncedRecipients"] 
      arg_notification_subtype=arg_info["bounce"]["bounceType"] 
      arg_feedback_id=arg_info["bounce"]["feedbackId"] 
      arg_date_recorded=arg_info["bounce"]["timestamp"] 
     elif arg_notification_type == 'Complaint': 
      #required complaint object fields 
      arg_emails=arg_info["complaint"]["complainedRecipients"] 
      arg_feedback_id=arg_info["complaint"]["feedbackId"] 
      arg_date_recorded=arg_info["complaint"]["timestamp"] 
      #check if feedback type is inside optional field name 
      if "complaintFeedbackType" in arg_info["complaint"]: 
       arg_notification_subtype=arg_info["complaint"]["complaintFeedbackType"] 
      else: 
       arg_notification_subtype="" 
     else: 
      HttpResponse(status=400) 

     #save notifications for multiple emails 
     for arg_email in arg_emails: 
      notification = SES_Notification(info=json_body, notification_type=arg_notification_type, 
              email=arg_email["emailAddress"], notification_subtype=arg_notification_subtype, 
              date_recorded=arg_date_recorded, feedback_id=arg_feedback_id) 
      notification.save() 
     return HttpResponse(status=200) 

return HttpResponse(status=400) 
2

Thông qua thử nghiệm một lỗi Tôi đã đưa ra điều này - nó là dành cho Django nhưng có một công việc tốt cho tôi.

Đầu tiên các mô hình, sau đó yêu cầu xử lý ...

class ComplaintType: 
    ABUSE = 'abuse' 
    AUTH_FAILURE = 'auth-failure' 
    FRAUD = 'fraud' 
    NOT_SPAM = 'not-spam' 
    OTHER = 'other' 
    VIRUS = 'virus' 


COMPLAINT_FEEDBACK_TYPE_CHOICES = [ 
    [ComplaintType.ABUSE, _('Unsolicited email or some other kind of email abuse')], 
    [ComplaintType.AUTH_FAILURE, _('Unsolicited email or some other kind of email abuse')], 
    [ComplaintType.FRAUD, _('Some kind of fraud or phishing activity')], 
    [ComplaintType.NOT_SPAM, _('Entity providing the report does not consider the message to be spam')], 
    [ComplaintType.OTHER, _('Feedback does not fit into any other registered type')], 
    [ComplaintType.VIRUS, _('A virus was found in the originating message')] 
] 


class SES_Complaint(models.Model): 
    subject = models.CharField(max_length=255) 
    message = models.TextField() 
    email_address = models.EmailField(db_index=True) 
    user_agent = models.CharField(max_length=255) 
    complaint_feedback_type = models.CharField(max_length=255, choices=COMPLAINT_FEEDBACK_TYPE_CHOICES) 
    arrival_date = models.DateTimeField() 
    timestamp = models.DateTimeField() 
    feedback_id = models.CharField(max_length=255) 

    created = models.DateTimeField(auto_now_add=True) 
    modified = models.DateTimeField(auto_now=True) 

    class Meta: 
     verbose_name = 'SES Complaint' 
     verbose_name_plural = 'SES Complaints' 

    def get_reason(self): 
     return self.get_complaint_feedback_type_display() 


class BounceType: 
    UNDETERMINED = 'Undetermined' 
    PERMANENT = 'Permanent' 
    TRANSIENT = 'Transient' 


class BounceSubType: 
    UNDETERMINED = 'Undetermined' 
    GENERAL = 'General' 
    NO_EMAIL = 'NoEmail' 
    SUPPRESSED = 'Suppressed' 
    MAILBOX_FULL = 'MailboxFull' 
    MESSAGE_TOO_LARGE = 'MessageToolarge' 
    CONTENT_REJECTED = 'ContentRejected' 
    ATTACHMENT_REJECTED = 'AttachmentRejected' 


BOUNCE_TYPE_CHOICES = [ 
    [BounceType.UNDETERMINED, _('Unable to determine a specific bounce reason')], 
    [BounceType.PERMANENT, _('Unable to successfully send')], 
    [BounceType.TRANSIENT, _('All retry attempts have been exhausted')], 
] 

BOUNCE_SUB_TYPE_CHOICES = [ 
    [BounceSubType.UNDETERMINED, _('Unable to determine a specific bounce reason')], 
    [BounceSubType.GENERAL, _('General bounce. You may be able to successfully retry sending to that recipient in the future.')], 
    [BounceSubType.NO_EMAIL, _('Permanent hard bounce. The target email address does not exist.')], 
    [BounceSubType.SUPPRESSED, _('Address has a recent history of bouncing as invalid.')], 
    [BounceSubType.MAILBOX_FULL, _('Mailbox full')], 
    [BounceSubType.MESSAGE_TOO_LARGE, _('Message too large')], 
    [BounceSubType.CONTENT_REJECTED, _('Content rejected')], 
    [BounceSubType.ATTACHMENT_REJECTED, _('Attachment rejected')] 
] 


class SES_Bounce(models.Model): 
    subject = models.CharField(max_length=255) 
    message = models.TextField() 
    bounce_type = models.CharField(max_length=255, choices=BOUNCE_TYPE_CHOICES) 
    bounce_sub_type = models.CharField(max_length=255, choices=BOUNCE_SUB_TYPE_CHOICES) 
    timestamp = models.DateTimeField() 
    feedback_id = models.CharField(max_length=255) 
    status = models.CharField(max_length=255) 
    action = models.CharField(max_length=255) 
    diagnostic_code = models.CharField(max_length=255) 
    email_address = models.EmailField(db_index=True) 

    created = models.DateTimeField(auto_now_add=True) 
    modified = models.DateTimeField(auto_now=True, db_index=True) 

    class Meta: 
     verbose_name = 'SES Bounce' 
     verbose_name_plural = 'SES Bounces' 

    def get_reason(self): 
     return '%s - %s' % (self.get_bounce_type_display(), self.get_bounce_sub_type_display()) 

Và đây là xử lý yêu cầu:

@csrf_exempt 
def aws_sns(request): 
    logger.debug('Incoming SNS') 

    if request.method == 'POST': 

     logger.debug('Incoming SNS is POST') 

     sns_message_type = request.META.get('HTTP_X_AMZ_SNS_MESSAGE_TYPE', None) 

     if sns_message_type is not None: 

      logger.debug('Incoming SNS - %s', sns_message_type) 

      json_body = request.body 
      json_body = json_body.replace('\n', '') 
      js = loads(json_body) 

      if sns_message_type == "SubscriptionConfirmation": 

       subscribe_url = js["SubscribeURL"] 
       logger.debug('Incoming subscription - %s', subscribe_url) 
       urllib.urlopen(subscribe_url) 

      elif sns_message_type == "Notification": 

       message = js.get("Message", None) 
       message = message.replace('\n', '') 
       message = loads(message) 

       notification_type = message.get("notificationType", None) 

       if notification_type == 'AmazonSnsSubscriptionSucceeded': 
        logger.debug('Subscription succeeded') 

       elif notification_type == 'Bounce': 

        logger.debug('Incoming bounce') 

        bounce = message['bounce'] 
        bounce_type = bounce['bounceType'] 
        bounce_sub_type = bounce['bounceSubType'] 
        timestamp = bounce['timestamp'] 
        feedback_id = bounce['feedbackId'] 

        bounce_recipients = bounce['bouncedRecipients'] 

        for recipient in bounce_recipients: 
         status = recipient.get('status') 
         action = recipient.get('action') 
         #diagnostic_code = recipient['diagnosticCode'] 
         email_address = recipient['emailAddress'] 

         SES_Bounce.objects.filter(email_address=email_address).delete() 

         SES_Bounce.objects.create(
          message=message, 
          bounce_type=bounce_type, 
          bounce_sub_type=bounce_sub_type, 
          timestamp=timestamp, 
          feedback_id=feedback_id, 
          status=status, 
          action=action, 
          #diagnostic_code=diagnostic_code, 
          email_address=email_address 
         ) 

       elif notification_type == 'Complaint': 

        logger.debug('Incoming complaint') 

        complaint = message['complaint'] 

        user_agent = complaint.get('userAgent') 
        complaint_feedback_type = complaint.get('complaintFeedbackType') 
        arrival_date = complaint.get('arrivalDate') 

        timestamp = complaint['timestamp'] 
        feedback_id = complaint['feedbackId'] 
        recipients = complaint['complainedRecipients'] 

        for recipient in recipients: 
         email_address = recipient['emailAddress'] 

         SES_Complaint.objects.filter(email_address=email_address).delete() 

         SES_Complaint.objects.create(
          #subject=subject, 
          message=message, 
          email_address=email_address, 
          user_agent=user_agent, 
          complaint_feedback_type=complaint_feedback_type, 
          arrival_date=arrival_date, 
          timestamp=timestamp, 
          feedback_id=feedback_id 
         ) 

       else: 
        logger.exception('Incoming Notification SNS is not supported: %s', notification_type) 

      return HttpResponse() 
     else: 
      logger.exception('Incoming SNS did not have the right header') 

      for key, value in request.META.items(): 
       logger.debug('Key: %s - %s', key, value) 

    else: 
     logger.exception('Incoming SNS was not a POST') 

    return HttpResponseBadRequest() 
0

tất cả các câu trả lời ở trên là rất lớn, nhưng chỉ là một bổ sung nhỏ và quan trọng :

trước tiên bạn cần phải xác minh rằng yêu cầu là từ amazon sns: (như được mô tả tại Verifying the Signatures of Amazon SNS Messages)

cho mã python xác thực chữ ký - ví dụ tốt là here

Các vấn đề liên quan