def handle_bounce(request): """ Handle a bounced email via an SNS webhook. Parse the bounced message and send the appropriate signal. For bounce messages the bounce_received signal is called. For complaint messages the complaint_received signal is called. See: http://docs.aws.amazon.com/sns/latest/gsg/json-formats.html#http-subscription-confirmation-json See: http://docs.amazonwebservices.com/ses/latest/DeveloperGuide/NotificationsViaSNS.html In addition to email bounce requests this endpoint also supports the SNS subscription confirmation request. This request is sent to the SNS subscription endpoint when the subscription is registered. See: http://docs.aws.amazon.com/sns/latest/gsg/Subscribe.html For the format of the SNS subscription confirmation request see this URL: http://docs.aws.amazon.com/sns/latest/gsg/json-formats.html#http-subscription-confirmation-json SNS message signatures are verified by default. This funcionality can be disabled by setting AWS_SES_VERIFY_BOUNCE_SIGNATURES to False. However, this is not recommended. See: http://docs.amazonwebservices.com/sns/latest/gsg/SendMessageToHttp.verify.signature.html """ # For Django >= 1.4 use request.body, otherwise # use the old request.raw_post_data if hasattr(request, "body"): raw_json = request.body else: raw_json = request.raw_post_data try: notification = json.loads(raw_json) except ValueError as e: # TODO: What kind of response should be returned here? logger.warning('Recieved bounce with bad JSON: "%s"', e) return HttpResponseBadRequest() # Verify the authenticity of the bounce message. if settings.VERIFY_BOUNCE_SIGNATURES and not utils.verify_bounce_message(notification): # Don't send any info back when the notification is not # verified. Simply, don't process it. logger.info( "Recieved unverified notification: Type: %s", notification.get("Type"), extra={"notification": notification} ) return HttpResponse() if notification.get("Type") in ("SubscriptionConfirmation", "UnsubscribeConfirmation"): # Process the (un)subscription confirmation. logger.info( "Recieved subscription confirmation: TopicArn: %s", notification.get("TopicArn"), extra={"notification": notification}, ) # Get the subscribe url and hit the url to confirm the subscription. subscribe_url = notification.get("SubscribeURL") try: urlopen(subscribe_url).read() except URLError as e: # Some kind of error occurred when confirming the request. logger.error('Could not confirm subscription: "%s"', e, extra={"notification": notification}, exc_info=True) elif notification.get("Type") == "Notification": try: message = json.loads(notification["Message"]) except ValueError as e: # The message isn't JSON. # Just ignore the notification. logger.warning('Recieved bounce with bad JSON: "%s"', e, extra={"notification": notification}) else: mail_obj = message.get("mail") notification_type = message.get("notificationType") if notification_type == "Bounce": # Bounce bounce_obj = message.get("bounce", {}) # Logging feedback_id = bounce_obj.get("feedbackId") bounce_type = bounce_obj.get("bounceType") bounce_subtype = bounce_obj.get("bounceSubType") logger.info( "Recieved bounce notification: feedbackId: %s, bounceType: %s, bounceSubType: %s", feedback_id, bounce_type, bounce_subtype, extra={"notification": notification}, ) signals.bounce_received.send( sender=handle_bounce, mail_obj=mail_obj, bounce_obj=bounce_obj, raw_message=raw_json ) elif notification_type == "Complaint": # Complaint complaint_obj = message.get("complaint", {}) # Logging feedback_id = complaint_obj.get("feedbackId") feedback_type = complaint_obj.get("complaintFeedbackType") logger.info( "Recieved complaint notification: feedbackId: %s, feedbackType: %s", feedback_id, feedback_type, extra={"notification": notification}, ) signals.complaint_received.send( sender=handle_bounce, mail_obj=mail_obj, complaint_obj=complaint_obj, raw_message=raw_json ) else: # We received an unknown notification type. Just log and # ignore it. logger.warning("Recieved unknown notification", extra={"notification": notification}) else: logger.info( "Recieved unknown notification type: %s", notification.get("Type"), extra={"notification": notification} ) # AWS will consider anything other than 200 to be an error response and # resend the SNS request. We don't need that so we return 200 here. return HttpResponse()
# use the old request.raw_post_data if hasattr(request, 'body'): raw_json = request.body else: raw_json = request.raw_post_data try: notification = json.loads(raw_json) except ValueError, e: # TODO: What kind of response should be returned here? logger.warning('Recieved bounce with bad JSON: "%s"', e) return HttpResponseBadRequest() # Verify the authenticity of the bounce message. if (settings.VERIFY_BOUNCE_SIGNATURES and not utils.verify_bounce_message(notification)): # Don't send any info back when the notification is not # verified. Simply, don't process it. logger.info('Recieved unverified notification: Type: %s', notification.get('Type'), extra={ 'notification': notification, }, ) return HttpResponse() if notification.get('Type') in ('SubscriptionConfirmation', 'UnsubscribeConfirmation'): # Process the (un)subscription confirmation. logger.info('Recieved subscription confirmation: TopicArn: %s',
def handle_bounce(request): """ Handle a bounced email via an SNS webhook. Parse the bounced message and send the appropriate signal. For bounce messages the bounce_received signal is called. For complaint messages the complaint_received signal is called. See: http://docs.aws.amazon.com/sns/latest/gsg/json-formats.html#http-subscription-confirmation-json See: http://docs.amazonwebservices.com/ses/latest/DeveloperGuide/NotificationsViaSNS.html In addition to email bounce requests this endpoint also supports the SNS subscription confirmation request. This request is sent to the SNS subscription endpoint when the subscription is registered. See: http://docs.aws.amazon.com/sns/latest/gsg/Subscribe.html For the format of the SNS subscription confirmation request see this URL: http://docs.aws.amazon.com/sns/latest/gsg/json-formats.html#http-subscription-confirmation-json SNS message signatures are verified by default. This funcionality can be disabled by setting AWS_SES_VERIFY_BOUNCE_SIGNATURES to False. However, this is not recommended. See: http://docs.amazonwebservices.com/sns/latest/gsg/SendMessageToHttp.verify.signature.html """ raw_json = request.body try: notification = json.loads(raw_json.decode('utf-8')) except ValueError as e: # TODO: What kind of response should be returned here? logger.warning(u'Received bounce with bad JSON: "%s"', e) return HttpResponseBadRequest() # Verify the authenticity of the bounce message. if (settings.VERIFY_BOUNCE_SIGNATURES and not utils.verify_bounce_message(notification)): # Don't send any info back when the notification is not # verified. Simply, don't process it. logger.info(u'Received unverified notification: Type: %s', notification.get('Type'), extra={ 'notification': notification, }, ) return HttpResponse() if notification.get('Type') in ('SubscriptionConfirmation', 'UnsubscribeConfirmation'): # Process the (un)subscription confirmation. logger.info(u'Received subscription confirmation: TopicArn: %s', notification.get('TopicArn'), extra={ 'notification': notification, }, ) # Get the subscribe url and hit the url to confirm the subscription. subscribe_url = notification.get('SubscribeURL') try: urlopen(subscribe_url).read() except URLError as e: # Some kind of error occurred when confirming the request. logger.error(u'Could not confirm subscription: "%s"', e, extra={ 'notification': notification, }, exc_info=True, ) elif notification.get('Type') == 'Notification': try: message = json.loads(notification['Message']) except ValueError as e: # The message isn't JSON. # Just ignore the notification. logger.warning(u'Received bounce with bad JSON: "%s"', e, extra={ 'notification': notification, }) else: mail_obj = message.get('mail') notification_type = message.get('notificationType') if notification_type == 'Bounce': # Bounce bounce_obj = message.get('bounce', {}) # Logging feedback_id = bounce_obj.get('feedbackId') bounce_type = bounce_obj.get('bounceType') bounce_subtype = bounce_obj.get('bounceSubType') logger.info( u'Received bounce notification: feedbackId: %s, bounceType: %s, bounceSubType: %s', feedback_id, bounce_type, bounce_subtype, extra={ 'notification': notification, }, ) signals.bounce_received.send( sender=handle_bounce, mail_obj=mail_obj, bounce_obj=bounce_obj, raw_message=raw_json, ) elif notification_type == 'Complaint': # Complaint complaint_obj = message.get('complaint', {}) # Logging feedback_id = complaint_obj.get('feedbackId') feedback_type = complaint_obj.get('complaintFeedbackType') logger.info(u'Received complaint notification: feedbackId: %s, feedbackType: %s', feedback_id, feedback_type, extra={ 'notification': notification, }, ) signals.complaint_received.send( sender=handle_bounce, mail_obj=mail_obj, complaint_obj=complaint_obj, raw_message=raw_json, ) elif notification_type == 'Delivery': # Delivery delivery_obj = message.get('delivery', {}) # Logging feedback_id = delivery_obj.get('feedbackId') feedback_type = delivery_obj.get('deliveryFeedbackType') logger.info(u'Received delivery notification: feedbackId: %s, feedbackType: %s', feedback_id, feedback_type, extra={ 'notification': notification, }, ) signals.delivery_received.send( sender=handle_bounce, mail_obj=mail_obj, delivery_obj=delivery_obj, raw_message=raw_json, ) else: # We received an unknown notification type. Just log and # ignore it. logger.warning(u"Received unknown notification", extra={ 'notification': notification, }) else: logger.info(u'Received unknown notification type: %s', notification.get('Type'), extra={ 'notification': notification, }, ) # AWS will consider anything other than 200 to be an error response and # resend the SNS request. We don't need that so we return 200 here. return HttpResponse()
# use the old request.raw_post_data if hasattr(request, 'body'): raw_json = request.body else: raw_json = request.raw_post_data try: notification = json.loads(raw_json) except ValueError, e: # TODO: What kind of response should be returned here? logger.warning('Recieved bounce with bad JSON: "%s"', e) return HttpResponseBadRequest() # Verify the authenticity of the bounce message. if (settings.VERIFY_BOUNCE_SIGNATURES and not utils.verify_bounce_message(notification)): # Don't send any info back when the notification is not # verified. Simply, don't process it. logger.info( 'Recieved unverified notification: Type: %s', notification.get('Type'), extra={ 'notification': notification, }, ) return HttpResponse() if notification.get('Type') in ('SubscriptionConfirmation', 'UnsubscribeConfirmation'): # Process the (un)subscription confirmation.