def handle(self, **options):
        if not settings.RETURN_PATH_EMAIL:
            self.stdout.write(
                '\n\nPlease specify a RETURN_PATH_EMAIL in settings\n')
            return

        if not settings.RETURN_PATH_EMAIL_PASSWORD:
            self.stdout.write(
                '\n\nPlease specify a RETURN_PATH_EMAIL_PASSWORD for {} '
                'in settings\n'.format(settings.RETURN_PATH_EMAIL))
            return

        try:
            delete_messages = options['delete_messages']
            self.stdout.write('\n\nLogging into account for {}\n'.format(
                settings.RETURN_PATH_EMAIL))
            with BouncedEmailManager(delete_processed_messages=delete_messages
                                     ) as bounced_manager:

                self.stdout.write('\n\nProcessing Bounces\n')
                self._print_processed_emails(bounced_manager.process_bounces())

                self.stdout.write('\n\nProcessing Complaints\n')
                self._print_processed_emails(
                    bounced_manager.process_complaints())

            self.stdout.write('\nDone\n\n')
        except OSError:
            self.stdout.write('Not able to connect at this time\n')
Пример #2
0
    def handle(self, **options):
        if not settings.RETURN_PATH_EMAIL:
            self.stdout.write(
                '\n\nPlease specify a RETURN_PATH_EMAIL in settings\n')
            return

        if not settings.RETURN_PATH_EMAIL_PASSWORD:
            self.stdout.write(
                '\n\nPlease specify a RETURN_PATH_EMAIL_PASSWORD for {} '
                'in settings\n'.format(settings.RETURN_PATH_EMAIL))
            return

        try:
            delete_messages = options['delete_messages']
            process_aws = options['process_aws']
            self.stdout.write('\n\nLogging into account for {}\n'.format(
                settings.RETURN_PATH_EMAIL))
            with BouncedEmailManager(delete_processed_messages=delete_messages
                                     ) as bounced_manager:
                if process_aws:
                    self.stdout.write('\n\nProcessing AWS Notifications\n')
                    bounced_manager.process_aws_notifications()
                else:
                    self.stdout.write('\n\nProcessing Mailer Daemon Emails\n')
                    bounced_manager.process_daemon_messages()

            self.stdout.write('\nDone\n\n')
        except OSError:
            self.stdout.write('Not able to connect at this time\n')
Пример #3
0
def process_bounced_emails():
    if settings.RETURN_PATH_EMAIL and settings.RETURN_PATH_EMAIL_PASSWORD:
        try:
            with BouncedEmailManager(
                    delete_processed_messages=True) as bounced_manager:
                bounced_manager.process_bounces()
                bounced_manager.process_complaints()
        except Exception as e:
            notify_exception(
                None,
                message="Encountered error while processing bounced emails",
                details={
                    'error': e,
                })
Пример #4
0
def process_bounced_emails():
    if settings.RETURN_PATH_EMAIL and settings.RETURN_PATH_EMAIL_PASSWORD:
        try:
            with BouncedEmailManager(
                    delete_processed_messages=True
            ) as bounced_manager, metrics_track_errors(
                    'process_bounced_emails_task'):
                bounced_manager.process_daemon_messages()
        except Exception as e:
            notify_exception(
                None,
                message="Encountered error while processing bounced emails",
                details={
                    'error': e,
                })
 def setUp(self):
     self.manager = BouncedEmailManager()
class TestBouncedEmailManager(SimpleTestCase, TestFileMixin):
    file_path = ('data', 'email')
    root = os.path.dirname(__file__)

    def setUp(self):
        self.manager = BouncedEmailManager()

    def _get_message(self, filename):
        bounce_file = self.get_path(filename, 'txt')
        with open(bounce_file, "r") as f:
            bounce_email = f.read()
            message = email.message_from_string(bounce_email)
        return message

    def test_recipients_standard_aws_bounce(self):
        aws_bounce = self._get_message('standard_aws_bounce')
        self.assertEqual(self.manager._get_raw_bounce_recipients(aws_bounce), [
            '*****@*****.**',
            '*****@*****.**'
        ])

    def test_recipients_email_delivery_failure(self):
        delivery_failure = self._get_message('email_delivery_failure')
        self.assertEqual(
            self.manager._get_raw_bounce_recipients(delivery_failure),
            ['*****@*****.**'])

    def test_recipients_yahoo_qmail(self):
        yahoo_qmail = self._get_message('yahoo_qmail_failure')
        self.assertEqual(self.manager._get_raw_bounce_recipients(yahoo_qmail),
                         ['*****@*****.**'])

    def test_recipients_forwarded_bounce(self):
        forwarded_bounce = self._get_message('forwarded_bounce')
        self.assertEqual(
            self.manager._get_raw_bounce_recipients(forwarded_bounce),
            ['*****@*****.**'])

    def test_recipients_exchange_bounce(self):
        exchange_bounce = self._get_message('exchange_bounce')
        self.assertEqual(
            self.manager._get_raw_bounce_recipients(exchange_bounce),
            ['*****@*****.**'])

    def test_recipients_auto_reply(self):
        out_of_office = self._get_message('out_of_office')
        self.assertEqual(
            self.manager._get_raw_bounce_recipients(out_of_office), None)

    def test_sns_bounce_suppressed(self):
        sns_bounce_suppressed = self._get_message('sns_bounce_suppressed')
        self.assertEqual(
            self.manager._get_aws_info(sns_bounce_suppressed, 333), [
                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={
                        'from': ['*****@*****.**'],
                        'date': 'Tue, 28 Jan 2020 10:40:04 -0000',
                        'to': ['*****@*****.**'],
                        'messageId': '<redacted>',
                        'subject': 'Late'
                    },
                    timestamp=datetime.datetime(
                        2020, 1, 28, 10, 40, 4, 931000, tzinfo=tzlocal()),
                    destination=['*****@*****.**'])
            ])

    def test_sns_bounce_general(self):
        sns_bounce_general = self._get_message('sns_bounce_general')
        self.assertEqual(self.manager._get_aws_info(sns_bounce_general, 333), [
            AwsMeta(notification_type='Bounce',
                    main_type='Permanent',
                    sub_type='General',
                    email='*****@*****.**',
                    reason="smtp; 550-5.1.1 The email account that you tried "
                    "to reach does not exist. Please try\n550-5.1.1 "
                    "double-checking the recipient's email address for "
                    "typos or\n550-5.1.1 unnecessary spaces. Learn more"
                    " at\n550 5.1.1  https://support.google.com/mail/?p="
                    "NoSuchUser h6si12061056qtp.98 - gsmtp",
                    headers={
                        'returnPath':
                        '*****@*****.**',
                        'from': ['*****@*****.**'],
                        'date': 'Tue, 28 Jan 2020 09:29:02 -0000',
                        'to': ['*****@*****.**'],
                        'messageId': '<redacted>',
                        'subject': 'Activate your CommCare project'
                    },
                    timestamp=datetime.datetime(
                        2020, 1, 28, 9, 29, 3, 30000, tzinfo=tzlocal()),
                    destination=['*****@*****.**'])
        ])

    def test_sns_bounce_transient(self):
        sns_bounce_transient = self._get_message('sns_bounce_transient')
        self.assertEqual(self.manager._get_aws_info(
            sns_bounce_transient, 333), [
                AwsMeta(
                    notification_type='Bounce',
                    main_type='Transient',
                    sub_type='General',
                    email='*****@*****.**',
                    reason=None,
                    headers={
                        'returnPath':
                        '*****@*****.**',
                        'from': ['*****@*****.**'],
                        'date': 'Tue, 28 Jan 2020 13:00:27 -0000',
                        'to': ['*****@*****.**'],
                        'messageId': '<redacted>',
                        'subject': 'Scheduled report from CommCare HQ'
                    },
                    timestamp=datetime.datetime(
                        2020, 1, 28, 13, 0, 35, tzinfo=tzlocal()),
                    destination=['*****@*****.**'])
            ])

    def test_sns_bounce_complaint(self):
        sns_complaint = self._get_message('sns_complaint')
        self.assertEqual(self.manager._get_aws_info(sns_complaint, 333), [
            AwsMeta(notification_type='Complaint',
                    main_type=None,
                    sub_type='',
                    email='*****@*****.**',
                    reason=None,
                    headers={},
                    timestamp=datetime.datetime(
                        2020, 1, 8, 8, 6, 45, tzinfo=tzlocal()),
                    destination=['*****@*****.**'])
        ])