Ejemplo n.º 1
0
def log_email_event(request, secret):
    # From Amazon SNS:
    # https://docs.aws.amazon.com/ses/latest/DeveloperGuide/event-publishing-retrieving-sns-examples.html

    if secret != settings.SNS_EMAIL_EVENT_SECRET:
        return HttpResponse("Incorrect secret", status=403, content_type='text/plain')

    request_json = json.loads(request.body)

    if request_json['Type'] == "SubscriptionConfirmation":
        # When creating an SNS topic, the first message is a subscription
        # confirmation, where we need to access the subscribe URL to confirm we
        # are able to receive messages at this endpoint
        subscribe_url = request_json['SubscribeURL']
        requests.get(subscribe_url)
        return HttpResponse()

    message = json.loads(request_json['Message'])
    headers = message.get('mail', {}).get('headers', [])

    for header in headers:
        if header["name"] == COMMCARE_MESSAGE_ID_HEADER:
            if Invitation.EMAIL_ID_PREFIX in header["value"]:
                handle_email_invite_message(message, header["value"].split(Invitation.EMAIL_ID_PREFIX)[1])
            else:
                subevent_id = header["value"]
                handle_email_messaging_subevent(message, subevent_id)
            break

    handle_email_sns_event(message)

    return HttpResponse()
Ejemplo n.º 2
0
    def test_scheduled_transient_bounce(self):
        transient_message = self._get_message('scheduled_transient_bounce')
        transient_email = '*****@*****.**'
        self.assertEqual(
            get_relevant_aws_meta(transient_message),
            [
                AwsMeta(
                    notification_type='Bounce',
                    main_type='Transient',
                    sub_type='General',
                    email='*****@*****.**',
                    reason='smtp; 554 4.4.7 Message expired: unable to deliver in 840 minutes.<421 4.4.0 Unable to lookup DNS for company.org>',
                    headers={
                        'returnPath': '*****@*****.**',
                        'from': ['*****@*****.**'],
                        'date': 'Fri, 31 Jul 2020 06:01:50 -0000',
                        'to': ['*****@*****.**'],
                        'messageId': '<redacted>',
                        'subject': 'Scheduled report from CommCare HQ'
                    },
                    timestamp=datetime.datetime(2020, 7, 31, 21, 8, 57, 723000,
                                                tzinfo=datetime.timezone.utc),
                    destination=['*****@*****.**']
                )
            ]
        )

        handle_email_sns_event(transient_message)

        bounced_email = BouncedEmail.objects.filter(email=transient_email)
        self.assertFalse(bounced_email.exists())

        transient_info = TransientBounceEmail.objects.filter(email=transient_email)
        self.assertTrue(transient_info.exists())
Ejemplo n.º 3
0
    def test_send_event(self):
        send_event = self._get_message('send_event')
        sender_email = "*****@*****.**"
        self.assertEqual(get_relevant_aws_meta(send_event), [])

        handle_email_sns_event(send_event)

        bounced_email = BouncedEmail.objects.filter(email=sender_email)
        self.assertFalse(bounced_email.exists())

        transient_info = TransientBounceEmail.objects.filter(email=sender_email)
        self.assertFalse(transient_info.exists())
Ejemplo n.º 4
0
    def test_scheduled_suppressed_bounce(self):
        bounce_message = self._get_message('scheduled_suppressed_bounce')
        self.assertEqual(get_relevant_aws_meta(bounce_message), [
            AwsMeta(
                notification_type='Bounce',
                main_type='Permanent',
                sub_type='Suppressed',
                email='*****@*****.**',
                reason=
                'Amazon SES has suppressed sending to this address because '
                'it has a recent history of bouncing as an invalid address. '
                'For more information about how to remove an address from the '
                'suppression list, see the Amazon SES Developer Guide: '
                'http://docs.aws.amazon.com/ses/latest/DeveloperGuide/remove-from-suppressionlist.html ',
                headers={
                    'returnPath': '*****@*****.**',
                    'from': ['*****@*****.**'],
                    'date': 'Tue, 28 Jul 2020 00:28:28 -0000',
                    'to': ['*****@*****.**'],
                    'cc': ['*****@*****.**'],
                    'messageId': '<redacted@server-name>',
                    'subject': 'Invitation from John Doe to join CommCareHQ'
                },
                timestamp=datetime.datetime(2020,
                                            7,
                                            28,
                                            0,
                                            28,
                                            28,
                                            622000,
                                            tzinfo=datetime.timezone.utc),
                destination=[
                    '*****@*****.**', '*****@*****.**'
                ])
        ])
        handle_email_sns_event(bounce_message)

        bounced_email = BouncedEmail.objects.filter(
            email='*****@*****.**')
        self.assertTrue(bounced_email.exists())

        permanent_meta = PermanentBounceMeta.objects.filter(
            bounced_email=bounced_email.first())
        self.assertTrue(permanent_meta.exists())
        self.assertEqual(permanent_meta.first().sub_type,
                         BounceSubType.SUPPRESSED)
Ejemplo n.º 5
0
    def test_scheduled_general_bounce(self):
        bounce_message = self._get_message('scheduled_general_bounce')
        self.assertEqual(get_relevant_aws_meta(bounce_message), [
            AwsMeta(
                notification_type='Bounce',
                main_type='Permanent',
                sub_type='General',
                email='*****@*****.**',
                reason=
                'smtp; 550 5.4.1 Recipient address rejected: Access denied. AS(redacted) [redacted.outlook.com]',
                headers={
                    'returnPath': '*****@*****.**',
                    'from': ['*****@*****.**'],
                    'date': 'Fri, 31 Jul 2020 20:09:55 -0000',
                    'to': ['*****@*****.**'],
                    'cc': ['*****@*****.**'],
                    'messageId': '<redacted@server-name>',
                    'subject': 'Invitation from John Doe to join CommCareHQ'
                },
                timestamp=datetime.datetime(2020,
                                            7,
                                            31,
                                            20,
                                            9,
                                            56,
                                            637000,
                                            tzinfo=datetime.timezone.utc),
                destination=[
                    '*****@*****.**',
                    '*****@*****.**'
                ])
        ])
        handle_email_sns_event(bounce_message)

        bounced_email = BouncedEmail.objects.filter(
            email='*****@*****.**')
        self.assertTrue(bounced_email.exists())

        permanent_meta = PermanentBounceMeta.objects.filter(
            bounced_email=bounced_email.first())
        self.assertTrue(permanent_meta.exists())
        self.assertEqual(permanent_meta.first().sub_type,
                         BounceSubType.GENERAL)
Ejemplo n.º 6
0
    def test_scheduled_complaint(self):
        complaint_message = self._get_message('scheduled_complaint')
        self.assertEqual(
            get_relevant_aws_meta(complaint_message),
            [
                AwsMeta(
                    notification_type='Complaint',
                    main_type=None,
                    sub_type=None,
                    email='*****@*****.**',
                    reason=None,
                    headers={
                        'returnPath': '*****@*****.**',
                        'from': ['*****@*****.**'],
                        'date': 'Thu, 16 Jul 2020 03:02:22 -0000',
                        'to': ['*****@*****.**'],
                        'cc': ['*****@*****.**'],
                        'messageId': '<redacted@server-name>',
                        'subject': 'Invitation from Alice Doe to join CommCareHQ'
                    },
                    timestamp=datetime.datetime(2020, 7, 16, 3, 16, 55, 129000,
                                                tzinfo=datetime.timezone.utc),
                    destination=[
                        '*****@*****.**',
                        '*****@*****.**'
                    ]
                ),
                AwsMeta(
                    notification_type='Complaint',
                    main_type=None,
                    sub_type=None,
                    email='*****@*****.**',
                    reason=None,
                    headers={
                        'returnPath': '*****@*****.**',
                        'from': ['*****@*****.**'],
                        'date': 'Thu, 16 Jul 2020 03:02:22 -0000',
                        'to': ['*****@*****.**'],
                        'cc': ['*****@*****.**'],
                        'messageId': '<redacted@server-name>',
                        'subject': 'Invitation from Alice Doe to join CommCareHQ'
                    },
                    timestamp=datetime.datetime(2020, 7, 16, 3, 16, 55, 129000,
                                                tzinfo=datetime.timezone.utc),
                    destination=[
                        '*****@*****.**',
                        '*****@*****.**'
                    ]
                ),
            ]
        )
        handle_email_sns_event(complaint_message)

        first_bounced_email = BouncedEmail.objects.filter(email='*****@*****.**')
        second_bounced_email = BouncedEmail.objects.filter(email='*****@*****.**')
        self.assertTrue(first_bounced_email.exists())
        self.assertTrue(second_bounced_email.exists())

        self.assertTrue(
            ComplaintBounceMeta.objects.filter(
                bounced_email=first_bounced_email.first()
            ).exists()
        )
        self.assertTrue(
            ComplaintBounceMeta.objects.filter(
                bounced_email=second_bounced_email.first()
            ).exists()
        )