def test_limited_to_length(self) -> None: hamlet = self.example_user("hamlet") # This is exactly the max length limit_length_name = "澳" * 61 hamlet.full_name = limit_length_name hamlet.save() mail = build_email( "zerver/emails/password_reset", to_user_ids=[hamlet.id], from_name="Noreply", from_address=FromAddress.NOREPLY, language="en", ) self.assertEqual(mail.to[0], f"{hamlet.full_name} <{hamlet.delivery_email}>") # One more character makes it flip to just the address, with no name hamlet.full_name += "澳" hamlet.save() mail = build_email( "zerver/emails/password_reset", to_user_ids=[hamlet.id], from_name="Noreply", from_address=FromAddress.NOREPLY, language="en", ) self.assertEqual(mail.to[0], hamlet.delivery_email)
def test_build_SES_incompatible_From_field(self) -> None: hamlet = self.example_user("hamlet") mail = build_email( "zerver/emails/password_reset", to_emails=[hamlet], from_name=OVERLY_LONG_NAME, from_address=FromAddress.NOREPLY, language="en", ) self.assertEqual(mail.extra_headers["From"], FromAddress.NOREPLY)
def test_build_SES_incompatible_From_field_limit(self) -> None: hamlet = self.example_user("hamlet") limit_length_name = "a" * (321 - len(sanitize_address(FromAddress.NOREPLY, "utf-8")) - 3) mail = build_email( "zerver/emails/password_reset", to_emails=[hamlet], from_name=limit_length_name, from_address=FromAddress.NOREPLY, language="en", ) self.assertEqual(mail.extra_headers["From"], FromAddress.NOREPLY)
def test_build_SES_compatible_From_field(self) -> None: hamlet = self.example_user("hamlet") from_name = FromAddress.security_email_from_name(language="en") mail = build_email( "zerver/emails/password_reset", to_emails=[hamlet], from_name=from_name, from_address=FromAddress.NOREPLY, language="en", ) self.assertEqual(mail.extra_headers["From"], "{} <{}>".format(from_name, FromAddress.NOREPLY))
def test_send_email_exceptions(self) -> None: hamlet = self.example_user("hamlet") from_name = FromAddress.security_email_from_name(language="en") address = FromAddress.NOREPLY # Used to check the output mail = build_email( "zerver/emails/password_reset", to_emails=[hamlet], from_name=from_name, from_address=address, language="en", ) self.assertEqual(mail.extra_headers["From"], f"{from_name} <{FromAddress.NOREPLY}>") # We test the cases that should raise an EmailNotDeliveredException errors = { f"Unknown error sending password_reset email to {mail.to}": [0], f"Error sending password_reset email to {mail.to}": [SMTPException()], f"Error sending password_reset email to {mail.to}: {{'{address}': (550, b'User unknown')}}": [ SMTPRecipientsRefused( recipients={address: (550, b"User unknown")}) ], f"Error sending password_reset email to {mail.to} with error code 242: From field too long": [SMTPDataError(242, "From field too long.")], } for message, side_effect in errors.items(): with mock.patch.object(EmailBackend, "send_messages", side_effect=side_effect): with self.assertLogs(logger=logger) as info_log: with self.assertRaises(EmailNotDeliveredException): send_email( "zerver/emails/password_reset", to_emails=[hamlet], from_name=from_name, from_address=FromAddress.NOREPLY, language="en", ) self.assert_length(info_log.records, 2) self.assertEqual( info_log.output[0], f"INFO:{logger.name}:Sending password_reset email to {mail.to}", ) self.assertTrue(info_log.output[1].startswith( f"ERROR:zulip.send_email:{message}"))
def test_limited_from_length(self) -> None: hamlet = self.example_user("hamlet") # This is exactly the max length limit_length_name = "a" * ( 320 - len(sanitize_address(FromAddress.NOREPLY, "utf-8")) - 3) mail = build_email( "zerver/emails/password_reset", to_emails=[hamlet], from_name=limit_length_name, from_address=FromAddress.NOREPLY, language="en", ) self.assertEqual(mail.extra_headers["From"], f"{limit_length_name} <{FromAddress.NOREPLY}>") # One more character makes it flip to just the address, with no name mail = build_email( "zerver/emails/password_reset", to_emails=[hamlet], from_name=limit_length_name + "a", from_address=FromAddress.NOREPLY, language="en", ) self.assertEqual(mail.extra_headers["From"], FromAddress.NOREPLY)
def test_send_email_exceptions(self) -> None: hamlet = self.example_user("hamlet") from_name = FromAddress.security_email_from_name(language="en") # Used to check the output mail = build_email( "zerver/emails/password_reset", to_emails=[hamlet], from_name=from_name, from_address=FromAddress.NOREPLY, language="en", ) self.assertEqual(mail.extra_headers["From"], "{} <{}>".format(from_name, FromAddress.NOREPLY)) # We test the two cases that should raise an EmailNotDeliveredException errors = { f"Unknown error sending password_reset email to {mail.to}": [0], f"Error sending password_reset email to {mail.to}": [SMTPException()], } for message, side_effect in errors.items(): with mock.patch.object(EmailBackend, "send_messages", side_effect=side_effect): with self.assertLogs(logger=logger) as info_log: with self.assertRaises(EmailNotDeliveredException): send_email( "zerver/emails/password_reset", to_emails=[hamlet], from_name=from_name, from_address=FromAddress.NOREPLY, language="en", ) self.assert_length(info_log.records, 2) self.assertEqual( info_log.output[0], f"INFO:{logger.name}:Sending password_reset email to {mail.to}", ) self.assertTrue(info_log.output[1].startswith( f"ERROR:zulip.send_email:{message}"))
def test_send_email_exceptions(self) -> None: hamlet = self.example_user("hamlet") from_name = FromAddress.security_email_from_name(language="en") # Used to check the output mail = build_email( "zerver/emails/password_reset", to_emails=[hamlet], from_name=from_name, from_address=FromAddress.NOREPLY, language="en", ) self.assertEqual(mail.extra_headers["From"], "{} <{}>".format(from_name, FromAddress.NOREPLY)) # We test the two cases that should raise an EmailNotDeliveredException side_effect = [0, SMTPException] with mock.patch.object(EmailBackend, "send_messages", side_effect=side_effect): for i in range(len(side_effect)): with self.assertLogs(logger=logger) as info_log: with self.assertRaises(EmailNotDeliveredException): send_email( "zerver/emails/password_reset", to_emails=[hamlet], from_name=from_name, from_address=FromAddress.NOREPLY, language="en", ) self.assertEqual(len(info_log.records), 2) self.assertEqual( info_log.output, [ f"INFO:{logger.name}:Sending password_reset email to {mail.to}", f"ERROR:{logger.name}:Error sending password_reset email to {mail.to}", ], )
def test_build_and_send_SES_incompatible_From_address(self) -> None: hamlet = self.example_user("hamlet") from_name = "Zulip" # Address by itself is > 320 bytes even without the name. Should trigger exception. overly_long_address = "a" * 320 + "@zulip.com" mail = build_email( "zerver/emails/password_reset", to_emails=[hamlet], from_name=from_name, from_address=overly_long_address, language="en", ) self.assertEqual(mail.extra_headers["From"], overly_long_address) self.assertTrue( len(sanitize_address(mail.extra_headers["From"], "utf-8")) > 320) with mock.patch.object(EmailBackend, "send_messages", side_effect=SMTPDataError( 242, "From field too long.")): with self.assertLogs(logger=logger) as info_log: with self.assertRaises(EmailNotDeliveredException): send_email( "zerver/emails/password_reset", to_emails=[hamlet], from_name=from_name, from_address=overly_long_address, language="en", ) self.assertEqual(len(info_log.records), 2) self.assertEqual( info_log.output, [ f"INFO:{logger.name}:Sending password_reset email to {mail.to}", f"ERROR:{logger.name}:Error sending password_reset email to {mail.to}", ], )
def email_page(request): # type: (HttpRequest) -> HttpResponse # write fake data for all variables realm = get_realm('zulip') test_context = { 'user_profile': { 'full_name': 'Wile E. Coyote', 'email': '*****@*****.**', 'realm': { 'uri': realm.uri, 'name': 'Acme Corporation', }, }, 'realm': { 'uri': realm.uri, 'name': 'Acme Corporation', }, 'device_info': { 'login_time': "12/12/12, 12:12:12", 'device_browser': "Firefox", 'device_os': "ZulipOS", 'device_ip': '3.14.15.92', }, 'referrer': { 'full_name': 'Road Runner', 'email': '*****@*****.**', }, 'user': { 'full_name': 'Wile E. Coyote', 'email': '*****@*****.**', }, 'referrer_name': 'Road Runner', 'referrer_email': '*****@*****.**', 'realm_uri': realm.uri, 'server_uri': settings.SERVER_URI, 'old_email': '*****@*****.**', 'new_email': '*****@*****.**', 'activate_url': '%s/accounts/do_confirm/5348720e4af7d2e8f296cbbd04d439489917ddc0' % (settings.SERVER_URI,), 'unsubscribe_link': '%s/accounts/unsubscribe/<type>/cf88931365ef1b0f12eae8d488bbc7af3563d7f0' % (settings.SERVER_URI,), } templates = [ 'confirm_registration', 'invitation', 'invitation_reminder', 'confirm_registration_mit', 'invitation_mit', 'followup_day1', 'followup_day2', 'missed_message', 'digest', 'find_team', 'password_reset', 'confirm_new_email', 'notify_change_in_email', 'notify_new_login'] for f in os.listdir(os.path.join(ZULIP_PATH, 'templates', 'zerver', 'emails')): template = f.split('.')[0] if template not in templates: templates.append(template) # Do not render these templates, # as they are currently unsupported ignore = [ 'email_base', 'digest', 'missed_message', 'password_reset', ] data = [] # type: List[Dict[str, Any]] for template in templates: if template not in ignore: try: email = build_email('zerver/emails/' + template, '*****@*****.**', context=test_context) email_data = { 'template': template, 'subject': email.subject, 'body': email.body, 'html_message': email.alternatives[0][0] if len(email.alternatives) > 0 else 'Missing HTML message'} data.append(email_data) except Exception as e: # nocoverage data.append({'template': template, 'failed': True, 'reason': e}) return render(request, 'zerver/test_emails.html', {'emails': data})
def email_page(request): # type: (HttpRequest) -> HttpResponse # write fake data for all variables realm = get_realm('zulip') test_context = { 'user_profile': { 'full_name': 'Wile E. Coyote', 'email': '*****@*****.**', 'realm': { 'uri': realm.uri, 'name': 'Acme Corporation', }, }, 'realm': { 'uri': realm.uri, 'name': 'Acme Corporation', }, 'device_info': { 'login_time': "12/12/12, 12:12:12", 'device_browser': "Firefox", 'device_os': "ZulipOS", 'device_ip': '3.14.15.92', }, 'referrer': { 'full_name': 'Road Runner', 'email': '*****@*****.**', }, 'user': { 'full_name': 'Wile E. Coyote', 'email': '*****@*****.**', }, 'referrer_name': 'Road Runner', 'referrer_email': '*****@*****.**', 'referrer_realm_name': 'Acme Corporation', 'realm_uri': realm.uri, 'server_uri': settings.SERVER_URI, 'old_email': '*****@*****.**', 'new_email': '*****@*****.**', 'activate_url': '%s/accounts/do_confirm/5348720e4af7d2e8f296cbbd04d439489917ddc0' % (settings.SERVER_URI,), 'unsubscribe_link': '%s/accounts/unsubscribe/<type>/cf88931365ef1b0f12eae8d488bbc7af3563d7f0' % (settings.SERVER_URI,), } templates = [ 'confirm_registration', 'invitation', 'invitation_reminder', 'followup_day1', 'followup_day2', 'missed_message', 'digest', 'find_team', 'password_reset', 'confirm_new_email', 'notify_change_in_email', 'notify_new_login'] for f in os.listdir(os.path.join(ZULIP_PATH, 'templates', 'zerver', 'emails')): template = f.split('.')[0] if template not in templates: templates.append(template) # Do not render these templates, # as they are currently unsupported ignore = [ 'email_base', 'digest', 'missed_message', 'password_reset', ] data = [] # type: List[Dict[str, Any]] for template in templates: if template not in ignore: try: email = build_email('zerver/emails/' + template, '*****@*****.**', context=test_context) email_data = { 'template': template, 'subject': email.subject, 'body': email.body, 'html_message': email.alternatives[0][0] if len(email.alternatives) > 0 else 'Missing HTML message'} data.append(email_data) except Exception as e: # nocoverage data.append({'template': template, 'failed': True, 'reason': e}) return render(request, 'zerver/test_emails.html', {'emails': data})