Example #1
0
    def test_blast_hash_start(self, mock_hasher: mock.MagicMock,
                              mock_logging: mock.MagicMock) -> None:
        """Send mail to users with given hash start."""

        mock_user_db = pymongo.MongoClient(
            'mongodb://myprivatedata.com/user_test').user_test
        mock_user_db.user.drop()
        hash_values = ['12345', '01234']
        mock_hasher.reset_mock()
        mock_hasher().hexdigest.side_effect = hash_values

        mock_user_db.user.insert_many([{
            'registeredAt': '2017-04-15T00:00:00Z',
            'profile': {
                'name': f'user {hash_value}',
                'email': f'email{hash_value}@corpet.net',
            },
        } for hash_value in hash_values])

        mail_blast.main([
            'fake-user-campaign', 'send', '--registered-from', '2017-04-01',
            '--registered-to', '2017-07-10', '--disable-sentry', '--user-hash',
            '1'
        ])

        sent_messages = mailjetmock.get_all_sent_messages()
        self.assertEqual(
            1,
            len(sent_messages),
            msg=
            f'1 email expected: only for the user whith hash starting with 1\n{sent_messages}'
        )
        mock_logging.assert_any_call('Email sent to %s',
                                     '*****@*****.**')
Example #2
0
 def _assert_user_receives_campaign(self,
                                    mock_mail=None,
                                    should_be_sent=True):
     json_user = json_format.MessageToDict(self.user)
     json_user['_id'] = mongomock.ObjectId(json_user.pop('userId'))
     self._user_database.user.insert_one(json_user)
     mock_mail().status_code = 200
     mock_mail().json.return_value = {
         'Sent': [{
             'MessageID': 18014679230180635
         }]
     }
     mock_mail.reset_mock()
     year = self.user.registered_at.ToDatetime().year
     mail_blast.main([
         self._campaign_id,
         'send',
         '--disable-sentry',
         '--registered-from',
         str(year),
         '--registered-to',
         str(year + 1),
     ])
     if not should_be_sent:
         self.assertFalse(mock_mail.called)
         return
     mock_mail.assert_called_once()
     self._variables = mock_mail.call_args[0][2]
Example #3
0
    def test_list(self, mock_logging: mock.MagicMock) -> None:
        """Test a list for documents blast."""

        mail_blast.main(['fake-document', 'list'])
        messages = mailjetmock.get_all_sent_messages()
        self.assertFalse(messages)
        mock_logging.assert_any_call('%s: %s %s', 'fake-document',
                                     '5b2173b9362bf80840db6c2a',
                                     '*****@*****.**')
Example #4
0
    def test_send(self) -> None:
        """Test really sending to a document owner."""

        mail_blast.main(['fake-document', 'send', '--disable-sentry'])
        messages = mailjetmock.get_all_sent_messages()
        self.assertTrue(messages)
        self.assertEqual(1, len(messages))
        message = messages.pop()
        self.assertEqual('Nathalie ', message.recipient['Name'])
        self.assertEqual('*****@*****.**', message.recipient['Email'])
Example #5
0
    def test_missing_sentry_dsn(self, mock_error: mock.MagicMock) -> None:
        """Log an error when used without SENTRY_DSN env var."""

        mail_blast.main([
            'focus-network', 'send', '--registered-from', '2017-04-01',
            '--registered-to', '2017-07-10'
        ])

        self.assertFalse(mailjetmock.get_all_sent_messages())
        mock_error.assert_called_with(
            'Please set SENTRY_DSN to enable logging to Sentry, or use --disable-sentry option'
        )
Example #6
0
    def test_dry_run(self) -> None:
        """Test a dry run for documents."""

        mail_blast.main([
            'fake-document', 'dry-run', '--dry-run-email', '*****@*****.**'
        ])
        messages = mailjetmock.get_all_sent_messages()
        self.assertTrue(messages)
        self.assertEqual(1, len(messages))
        message = messages.pop()
        self.assertEqual('Nathalie ', message.recipient['Name'])
        self.assertEqual('*****@*****.**', message.recipient['Email'])
Example #7
0
    def test_stop_seeking(self, mock_user_db, mock_db, mock_mail,
                          mock_logging):
        """Basic test."""

        mock_mail().status_code = 200
        mock_mail().json.return_value = {
            'Sent': [{
                'MessageID': 18014679230180635
            }]
        }
        mock_mail.reset_mock()
        mock_db.job_group_info.insert_one({
            '_id': 'A1234',
            'inDomain': 'dans la vie',
        })
        mock_user_db.user.insert_many([{
            '_id':
            '%s' % seeking,
            'registeredAt':
            '2017-04-15T00:00:00Z',
            'profile': {
                'name': '{} user'.format(seeking),
                'email': 'email{}@corpet.net'.format(seeking),
            },
            'projects': [
                {
                    'networkEstimate': 1,
                    'targetJob': {
                        'jobGroup': {
                            'romeId': 'A1234'
                        }
                    }
                },
            ],
            'employmentStatus': [{
                'seeking': seeking,
                'createdAt': '2017-06-15T00:00:00Z'
            }]
        } for seeking in ('STILL_SEEKING', 'STOP_SEEKING')])

        mail_blast.main([
            'focus-network', 'send', '--registered-from', '2017-04-01',
            '--registered-to', '2017-07-10', '--disable-sentry'
        ])

        self.assertEqual(
            1,
            mock_mail.call_count,
            msg='1 email expected: only for the user who is still seeking\n{}'.
            format(mock_mail.call_args_list))
        mock_logging.assert_any_call('Email sent to %s',
                                     '*****@*****.**')
Example #8
0
    def test_change_policy(self, mock_user_db, mock_mail, mock_now,
                           unused_mock_db):
        """Test with non-default emailing policy."""

        mock_mail().status_code = 200
        mock_mail().json.return_value = {
            'Sent': [{
                'MessageID': 18014679230180635
            }]
        }
        mock_mail.reset_mock()
        mock_now.return_value = datetime.datetime(2017, 5, 24)
        mock_user_db.user.insert_many([
            {
                'registeredAt':
                '2017-05-15T00:00:00Z',
                'profile': {
                    'name': 'Sent other mail recently',
                    'email': '*****@*****.**',
                    'frustrations': ['MOTIVATION'],
                },
                'projects': [{}],
                'emailsSent': [{
                    'campaignId': 'focus-network',
                    'sentAt': '2017-05-15T00:00:00Z',
                }],
            },
            {
                'registeredAt':
                '2017-04-15T00:00:00Z',
                'profile': {
                    'name': 'Sent other mail less recently',
                    'email': '*****@*****.**',
                    'frustrations': ['MOTIVATION'],
                },
                'projects': [{}],
                'emailsSent': [{
                    'campaignId': 'focus-network',
                    'sentAt': '2017-04-15T00:00:00Z',
                }],
            },
        ])
        mail_blast.main([
            'galita-1', 'send', '--registered-from', '2017-04-01',
            '--registered-to', '2017-07-10', '--days-since-any-email', '10',
            '--disable-sentry'
        ])

        self.assertEqual(1,
                         mock_mail.call_count,
                         msg='1 emails expected:\n{}'.format(
                             mock_mail.call_args_list))
Example #9
0
    def test_incoherent_policy_durations(self,
                                         mock_error: mock.MagicMock) -> None:
        """Log an error when flags to define policy are not coherent."""

        mail_blast.main([
            'focus-network', 'send', '--registered-from', '2017-04-01',
            '--registered-to', '2017-07-10', '--disable-sentry',
            '--days-since-same-campaign', '7',
            '--days-since-same-campaign-unread', '15'
        ])

        self.assertFalse(mailjetmock.get_all_sent_messages())
        mock_error.assert_called_with(
            'Please use coherent values in the policy durations.')
Example #10
0
    def test_fake_secret_salt(self) -> None:
        """Raise an error when using the fake secret salt when trying to send."""

        auth = mail_blast.auth

        with mock.patch(auth.__name__ + '.SECRET_SALT',
                        new=auth.FAKE_SECRET_SALT):
            with self.assertRaises(ValueError):
                mail_blast.main([
                    'focus-network', 'send', '--registered-from', '2017-04-01',
                    '--registered-to', '2017-07-10', '--disable-sentry'
                ])

        self.assertFalse(mailjetmock.get_all_sent_messages())
Example #11
0
    def test_error_while_sending(self, mock_warning: mock.MagicMock,
                                 mock_send_template: mock.MagicMock) -> None:
        """Error when sending an email get caught and logged as warning."""

        mock_send_template(
        ).raise_for_status.side_effect = requests.exceptions.HTTPError

        mock_db = pymongo.MongoClient('mongodb://mydata.com/test').test
        mock_user_db = pymongo.MongoClient(
            'mongodb://myprivatedata.com/user_test').user_test
        mock_db.job_group_info.drop()
        mock_db.job_group_info.insert_one({
            '_id': 'A1234',
            'inDomain': 'dans la vie',
        })
        mock_user_db.user.drop()
        mock_user_db.user.insert_one({
            'registeredAt':
            '2017-05-15T00:00:00Z',
            'profile': {
                'name': 'The user',
                'email': '*****@*****.**',
            },
            'projects': [
                {
                    'networkEstimate': 1,
                    'targetJob': {
                        'jobGroup': {
                            'romeId': 'A1234'
                        }
                    }
                },
            ],
        })

        mail_blast.main([
            'focus-network', 'send', '--registered-from', '2017-04-01',
            '--registered-to', '2017-07-10', '--disable-sentry'
        ])

        self.assertFalse(mailjetmock.get_all_sent_messages())
        user = mock_user_db.user.find_one({})
        assert user
        self.assertEqual(
            [], [e.get('campaignId') for e in user.get('emailsSent', [])])

        mock_warning.assert_called_once()
        self.assertEqual('Error while sending an email: %s',
                         mock_warning.call_args[0][0])
Example #12
0
    def test_bounced(self) -> None:
        """Do not send emails if the user had a bounce."""

        mock_db = pymongo.MongoClient('mongodb://mydata.com/test').test
        mock_user_db = pymongo.MongoClient(
            'mongodb://myprivatedata.com/user_test').user_test
        mock_db.job_group_info.drop()
        mock_db.job_group_info.insert_one({
            '_id': 'A1234',
            'inDomain': 'dans la vie',
        })
        mock_user_db.user.drop()
        mock_user_db.user.insert_one({
            'registeredAt':
            '2017-05-15T00:00:00Z',
            'profile': {
                'name': 'The user',
                'email': '*****@*****.**',
            },
            'projects': [
                {
                    'networkEstimate': 1,
                    'targetJob': {
                        'jobGroup': {
                            'romeId': 'A1234'
                        }
                    }
                },
            ],
            'emailsSent': [{
                'campaignId': 'other-email',
                'status': 'EMAIL_SENT_BOUNCE'
            }],
        })
        mail_blast.main([
            'focus-network', 'send', '--registered-from', '2017-04-01',
            '--registered-to', '2017-07-10', '--disable-sentry'
        ])

        self.assertFalse(mailjetmock.get_all_sent_messages())
        user = mock_user_db.user.find_one({})
        assert user
        self.assertEqual(
            ['other-email'],
            [e.get('campaignId') for e in user.get('emailsSent', [])])
Example #13
0
    def test_stop_seeking(self, mock_logging: mock.MagicMock) -> None:
        """Basic test."""

        mock_db = pymongo.MongoClient('mongodb://mydata.com/test').test
        mock_user_db = pymongo.MongoClient(
            'mongodb://myprivatedata.com/user_test').user_test
        mock_db.job_group_info.drop()
        mock_db.job_group_info.insert_one({
            '_id': 'A1234',
            'inDomain': 'dans la vie',
        })
        mock_user_db.user.drop()
        mock_user_db.user.insert_many([{
            'registeredAt':
            '2017-04-15T00:00:00Z',
            'profile': {
                'name': f'{seeking} user',
                'email': f'email{seeking}@corpet.net',
            },
            'projects': [
                {
                    'networkEstimate': 1,
                    'targetJob': {
                        'jobGroup': {
                            'romeId': 'A1234'
                        }
                    }
                },
            ],
            'employmentStatus': [{
                'seeking': seeking,
                'createdAt': '2017-06-15T00:00:00Z'
            }]
        } for seeking in ('STILL_SEEKING', 'STOP_SEEKING')])

        mail_blast.main([
            'focus-network', 'send', '--registered-from', '2017-04-01',
            '--registered-to', '2017-07-10', '--disable-sentry'
        ])

        self.assertEqual(['*****@*****.**'], [
            m.recipient['Email'] for m in mailjetmock.get_all_sent_messages()
        ])
        mock_logging.assert_any_call('Email sent to %s',
                                     '*****@*****.**')
Example #14
0
    def test_change_policy(self, mock_now: mock.MagicMock) -> None:
        """Test with non-default emailing policy."""

        mock_user_db = pymongo.MongoClient(
            'mongodb://myprivatedata.com/user_test').user_test
        mock_user_db.user.drop()
        mock_now.return_value = datetime.datetime(2017, 5, 24)
        mock_user_db.user.insert_many([
            {
                'registeredAt':
                '2017-05-15T00:00:00Z',
                'profile': {
                    'name': 'Sent other mail recently',
                    'email': '*****@*****.**',
                    'frustrations': ['MOTIVATION'],
                },
                'projects': [{}],
                'emailsSent': [{
                    'campaignId': 'focus-network',
                    'sentAt': '2017-05-15T00:00:00Z',
                }],
            },
            {
                'registeredAt':
                '2017-04-15T00:00:00Z',
                'profile': {
                    'name': 'Sent other mail less recently',
                    'email': '*****@*****.**',
                    'frustrations': ['MOTIVATION'],
                },
                'projects': [{}],
                'emailsSent': [{
                    'campaignId': 'focus-network',
                    'sentAt': '2017-04-15T00:00:00Z',
                }],
            },
        ])
        mail_blast.main([
            'galita-1', 'send', '--registered-from', '2017-04-01',
            '--registered-to', '2017-07-10', '--days-since-any-email', '10',
            '--disable-sentry'
        ])

        emails_sent = mailjetmock.get_all_sent_messages()
        self.assertEqual(1, len(emails_sent), msg=emails_sent)
Example #15
0
    def test_days_from(self) -> None:
        """Compute from and to date relatively to today."""

        mock_db = pymongo.MongoClient('mongodb://mydata.com/test').test
        mock_user_db = pymongo.MongoClient(
            'mongodb://myprivatedata.com/user_test').user_test
        mock_db.job_group_info.drop()
        mock_db.job_group_info.insert_one({
            '_id': 'A1234',
            'inDomain': 'dans la vie',
        })
        mock_user_db.user.drop()
        mock_user_db.user.insert_one({
            'registeredAt':
            '2017-05-15T00:00:00Z',
            'profile': {
                'name': 'The user',
                'email': '*****@*****.**',
            },
            'projects': [
                {
                    'networkEstimate': 1,
                    'targetJob': {
                        'jobGroup': {
                            'romeId': 'A1234'
                        }
                    }
                },
            ],
        })
        with mock.patch(mail_blast.now.__name__ + '.get') as mock_now:
            mock_now.return_value = datetime.datetime(2017, 7, 11, 12, 0, 0, 0)
            mail_blast.main([
                'focus-network', 'send', '--registered-from-days-ago', '90',
                '--registered-to-days-ago', '1', '--disable-sentry'
            ])

        self.assertEqual(['*****@*****.**'], [
            m.recipient['Email'] for m in mailjetmock.get_all_sent_messages()
        ])
        user = mock_user_db.user.find_one({})
        assert user
        self.assertEqual(
            ['focus-network'],
            [e.get('campaignId') for e in user.get('emailsSent', [])])
Example #16
0
    def _assert_user_receives_campaign(self,
                                       should_be_sent: bool = True) -> None:
        json_user = json_format.MessageToDict(self.user)
        json_user['_id'] = mongomock.ObjectId(json_user.pop('userId'))
        self._user_database.get_collection(
            self.mongo_collection).insert_one(json_user)
        if self.mongo_collection == 'cvs_and_cover_letters':
            # This is not actually needed, we just need to avoid calling self.user.registered_at.
            year = 2018
        else:
            year = self.user.registered_at.ToDatetime().year
        mail_blast.main([
            self.campaign_id,
            'send',
            '--disable-sentry',
            '--registered-from',
            str(year),
            '--registered-to',
            str(year + 1),
        ])
        all_sent_messages = mailjetmock.get_all_sent_messages()
        if not should_be_sent:
            self.assertFalse(all_sent_messages)
            return
        self.assertEqual(1, len(all_sent_messages), msg=all_sent_messages)
        self.assertEqual(self.campaign_id,
                         all_sent_messages[0].properties['CustomCampaign'])
        self._variables = all_sent_messages[0].properties['Variables']

        # Test that variables used in the template are populated.
        template_id = str(all_sent_messages[0].properties['TemplateID'])
        template_path = campaign.get_template_folder(template_id)
        self.assertTrue(template_path,
                        msg=f'No template for campaign "{self.campaign_id}"')
        assert template_path
        with open(os_path.join(template_path, 'vars.txt'), 'r') as vars_file:
            template_vars = {v.strip() for v in vars_file}
        for template_var in template_vars:
            self.assertIn(
                template_var,
                self._variables,
                msg=f'Template error for campaign {self.campaign_id}, see '
                f'https://app.mailjet.com/template/{template_id}/build')
Example #17
0
    def test_blast_campaign(self, mock_db, mock_user_db, mock_mail,
                            mock_logging):
        """Basic test."""

        mock_mail().status_code = 200
        mock_mail().json.return_value = {
            'Sent': [{
                'MessageID': 18014679230180635
            }]
        }
        mock_mail.reset_mock()
        mock_db.job_group_info.insert_one({
            '_id': 'A1234',
            'inDomain': 'dans la vie',
        })
        mock_user_db.user.insert_many([{
            '_id':
            '%d' % month,
            'registeredAt':
            '2017-%02d-15T00:00:00Z' % month,
            'profile': {
                'name': '{} user'.format(month),
                'email': 'email{}@corpet.net'.format(month),
            },
            'projects': [
                {
                    'networkEstimate': 1,
                    'targetJob': {
                        'jobGroup': {
                            'romeId': 'A1234'
                        }
                    }
                },
            ],
        } for month in range(2, 9)])
        mock_user_db.user.insert_many([
            {
                'registeredAt':
                '2017-05-15T00:00:00Z',
                'profile': {
                    'name': 'Already sent',
                    'email': '*****@*****.**',
                },
                'projects': [
                    {
                        'networkEstimate': 1,
                        'targetJob': {
                            'jobGroup': {
                                'romeId': 'A1234'
                            }
                        }
                    },
                ],
                'emailsSent': [{
                    'campaignId': 'focus-network'
                }],
            },
            {
                'registeredAt':
                '2017-05-15T00:00:00Z',
                'profile': {
                    'name': 'Test user',
                    'email': '*****@*****.**',
                },
                'projects': [
                    {
                        'networkEstimate': 1,
                        'targetJob': {
                            'jobGroup': {
                                'romeId': 'A1234'
                            }
                        }
                    },
                ],
            },
            {
                'registeredAt':
                '2017-05-15T00:00:00Z',
                'profile': {
                    'name': 'REDACTED',
                    'email': 'REDACTED',
                },
                'projects': [
                    {
                        'networkEstimate': 1,
                        'targetJob': {
                            'jobGroup': {
                                'romeId': 'A1234'
                            }
                        }
                    },
                ],
            },
        ])
        mail_blast.main([
            'focus-network', 'send', '--registered-from', '2017-04-01',
            '--registered-to', '2017-07-10', '--disable-sentry'
        ])

        self.assertEqual(
            3,
            mock_mail.call_count,
            msg='3 emails expected: one per month from April to June\n{}'.
            format(mock_mail.call_args_list))
        self.assertEqual(
            {
                'sender_email': '*****@*****.**',
                'sender_name': 'Margaux de Bob'
            }, mock_mail.call_args[1])
        february_user = mock_user_db.user.find_one({'_id': '2'})
        self.assertFalse(february_user.get('emailsSent'))

        april_user = mock_user_db.user.find_one({'_id': '4'})
        self.assertEqual(
            [{'sentAt', 'mailjetTemplate', 'campaignId', 'mailjetMessageId'}],
            [e.keys() for e in april_user.get('emailsSent', [])])
        self.assertEqual('focus-network',
                         april_user['emailsSent'][0]['campaignId'])
        self.assertEqual(18014679230180635,
                         int(april_user['emailsSent'][0]['mailjetMessageId']))

        mock_logging.assert_any_call('Email sent to %s', '*****@*****.**')
        mock_logging.assert_called_with('%d emails sent.', 3)
Example #18
0
    def test_wrong_id(self) -> None:
        """Filter based on ID."""

        mock_db = pymongo.MongoClient('mongodb://mydata.com/test').test
        mock_user_db = pymongo.MongoClient(
            'mongodb://myprivatedata.com/user_test').user_test
        mock_db.job_group_info.drop()
        mock_db.job_group_info.insert_one({
            '_id': 'A1234',
            'inDomain': 'dans la vie',
        })
        mock_user_db.user.drop()
        mock_user_db.user.insert_many([
            {
                '_id':
                objectid.ObjectId('444444444444444444444444'),
                'registeredAt':
                '2017-05-15T00:00:00Z',
                'profile': {
                    'name': 'The user',
                    'email': '*****@*****.**',
                },
                'projects': [
                    {
                        'networkEstimate': 1,
                        'targetJob': {
                            'jobGroup': {
                                'romeId': 'A1234'
                            }
                        }
                    },
                ],
            },
            {
                '_id':
                objectid.ObjectId('5b2173b9362bf80840db6c2a'),
                'registeredAt':
                '2017-05-15T00:00:00Z',
                'profile': {
                    'name': 'The filtered user',
                    'email': '*****@*****.**',
                },
                'projects': [
                    {
                        'networkEstimate': 1,
                        'targetJob': {
                            'jobGroup': {
                                'romeId': 'A1234'
                            }
                        }
                    },
                ],
            },
        ])
        mail_blast.main([
            'focus-network', 'send', '--registered-from', '2017-04-01',
            '--registered-to', '2017-07-10', '--disable-sentry',
            '--user-id-start', '44'
        ])

        self.assertEqual(['*****@*****.**'], [
            m.recipient['Email'] for m in mailjetmock.get_all_sent_messages()
        ])
        users = mock_user_db.user.find({})
        self.assertEqual(
            {
                '*****@*****.**': ['focus-network'],
                '*****@*****.**': [],
            }, {
                u['profile']['email']:
                [e.get('campaignId') for e in u.get('emailsSent', [])]
                for u in users
            })
Example #19
0
    def test_blast_campaign(self, mock_logging: mock.MagicMock) -> None:
        """Basic test."""

        mock_db = pymongo.MongoClient('mongodb://mydata.com/test').test
        mock_user_db = pymongo.MongoClient(
            'mongodb://myprivatedata.com/user_test').user_test
        mock_db.job_group_info.drop()
        mock_db.job_group_info.insert_one({
            '_id': 'A1234',
            'inDomain': 'dans la vie',
        })
        mock_user_db.user.drop()
        mock_user_db.user.insert_many([{
            '_id':
            objectid.ObjectId('7b18313aa35d807e631ea3d%d' % month),
            'registeredAt':
            '2017-%02d-15T00:00:00Z' % month,
            'profile': {
                'name': f'{month} user',
                'email': f'email{month}@corpet.net',
            },
            'projects': [
                {
                    'networkEstimate': 1,
                    'targetJob': {
                        'jobGroup': {
                            'romeId': 'A1234'
                        }
                    }
                },
            ],
        } for month in range(2, 9)])
        mock_user_db.user.insert_many([
            {
                'registeredAt':
                '2017-05-15T00:00:00Z',
                'profile': {
                    'name': 'Already sent',
                    'email': '*****@*****.**',
                },
                'projects': [
                    {
                        'networkEstimate': 1,
                        'targetJob': {
                            'jobGroup': {
                                'romeId': 'A1234'
                            }
                        }
                    },
                ],
                'emailsSent': [{
                    'campaignId': 'focus-network'
                }],
            },
            {
                'registeredAt':
                '2017-05-15T00:00:00Z',
                'profile': {
                    'name': 'Test user',
                    'email': '*****@*****.**',
                },
                'projects': [
                    {
                        'networkEstimate': 1,
                        'targetJob': {
                            'jobGroup': {
                                'romeId': 'A1234'
                            }
                        }
                    },
                ],
            },
            {
                'registeredAt':
                '2017-05-15T00:00:00Z',
                'profile': {
                    'name': 'REDACTED',
                    'email': 'REDACTED',
                },
                'projects': [
                    {
                        'networkEstimate': 1,
                        'targetJob': {
                            'jobGroup': {
                                'romeId': 'A1234'
                            }
                        }
                    },
                ],
            },
        ])
        mail_blast.main([
            'focus-network', 'send', '--registered-from', '2017-04-01',
            '--registered-to', '2017-07-10', '--disable-sentry'
        ])

        mails_sent = mailjetmock.get_all_sent_messages()
        self.assertEqual(
            ['*****@*****.**', '*****@*****.**', '*****@*****.**'],
            sorted(m.recipient['Email'] for m in mails_sent),
            msg=
            f'3 emails expected: one per month from April to June\n{mails_sent}'
        )
        self.assertEqual({'*****@*****.**'},
                         {m.properties['From']['Email']
                          for m in mails_sent})
        february_user = mock_user_db.user.find_one(
            {'_id': objectid.ObjectId('7b18313aa35d807e631ea3d2')})
        assert february_user
        self.assertFalse(february_user.get('emailsSent'))

        april_user = mock_user_db.user.find_one(
            {'_id': objectid.ObjectId('7b18313aa35d807e631ea3d4')})
        assert april_user
        self.assertEqual(
            [{'sentAt', 'mailjetTemplate', 'campaignId', 'mailjetMessageId'}],
            [e.keys() for e in april_user.get('emailsSent', [])])
        self.assertEqual('focus-network',
                         april_user['emailsSent'][0]['campaignId'])
        self.assertEqual(
            next(mailjetmock.get_messages_sent_to(
                '*****@*****.**')).message_id,
            int(april_user['emailsSent'][0]['mailjetMessageId']))

        mock_logging.assert_any_call('Email sent to %s', '*****@*****.**')
        mock_logging.assert_called_with('%d emails sent.', 3)