def test_invalid_receiver_some(self) -> None: """Mail sent, invalid recipients in response""" EmailSettings.connection_security = "NONE" EmailSettings.port = 25 handler = AIOHandler() with AiosmtpdServerManager(handler): with EmailMixin.get_mail_connection() as mail_client: receivers = self.receivers + ["invalidQexample1.com"] response = EmailMixin.send_email( mail_client, self.sender, receivers, subject="A mail from intevation-test: plain text", content= "Hi you\r\nThis is a nice content line with only plain text!", html=False, ) self.assertEqual( response.get("invalidQexample1.com", tuple()), (550, b"invalid eMail address"), ) self.assertEqual("250 Message accepted for delivery", handler.ret_status) self.assertEqual(len(handler.emails), 1) self.assertEqual(handler.emails[0]["from"], self.sender) self.assertEqual(handler.emails[0]["to"], self.receivers) self.assertNotEqual(handler.emails[0]["to"], receivers)
def test_modified_body_with_unknown_keyword(self) -> None: self.set_models({ "meeting/1": { "users_email_subject": "Invitation for Openslides '{xevent_name}'", "users_email_body": "event name: {yevent_name}", } }) handler = AIOHandler() with AiosmtpdServerManager(handler): response = self.request( "user.send_invitation_email", { "id": 2, "meeting_id": 1, }, ) self.assert_status_code(response, 200) self.assertEqual(response.json["results"][0][0]["sent"], True) self.assertIn( "Subject: Invitation for Openslides ''xevent_name''", handler.emails[0]["data"], ) self.assertIn( "event name: 'yevent_name'", handler.emails[0]["data"], )
def test_correct_organization_send(self) -> None: self.set_models({ "organization/1": { "name": "test orga name", "users_email_subject": "Invitation for Openslides '{event_name}'", "users_email_body": "event name: {event_name}", }, }) handler = AIOHandler() with AiosmtpdServerManager(handler): response = self.request( "user.send_invitation_email", { "id": 2, }, ) self.assert_status_code(response, 200) print(response.json["results"]) self.assertEqual(response.json["results"][0][0]["sent"], True) self.assertIn( "Subject: Invitation for Openslides 'test orga name'", handler.emails[0]["data"], ) self.assertIn( "event name: test orga name", handler.emails[0]["data"], )
def test_sender_with_name(self) -> None: EmailSettings.connection_security = "NONE" EmailSettings.port = 25 sender = Address("Name of sender", addr_spec=self.sender) handler = AIOHandler() with AiosmtpdServerManager(handler): with EmailMixin.get_mail_connection() as mail_client: response = EmailMixin.send_email( mail_client, sender, self.receivers, subject="Test-email", content="Hi\r\nThis is some plain text content!", html=False, ) self.assertEqual(len(response), 0) self.assertEqual("250 Message accepted for delivery", handler.ret_status) self.assertEqual(len(handler.emails), 1) self.assertEqual(handler.emails[0]["from"], self.sender) self.assertEqual(handler.emails[0]["to"], self.receivers) self.assertIn( f"From: Name of sender <{self.sender}>", handler.emails[0]["data"], ) self.assertNotIn( 'Content-Type: text/html; charset="utf-8"', handler.emails[0]["data"], )
def test_correct_organization_send_no_permission(self) -> None: self.set_models({ "user/1": { "organization_management_level": None }, "user/2": { "group_$1_ids": [] }, "organization/1": { "name": "test orga name", "users_email_subject": "Invitation for Openslides '{event_name}'", "users_email_body": "event name: {event_name}", }, }) handler = AIOHandler() with AiosmtpdServerManager(handler): response = self.request( "user.send_invitation_email", { "id": 2, }, ) self.assert_status_code(response, 200) self.assertEqual(response.json["results"][0][0]["sent"], False) self.assertEqual( response.json["results"][0][0]["message"], "Missing OrganizationManagementLevel: can_manage_users", )
def test_forget_password_no_user_found(self) -> None: self.set_models({"organization/1": {"url": None}}) handler = AIOHandler() with AiosmtpdServerManager(handler): response = self.request("user.forget_password", {"email": "*****@*****.**"}) self.assert_status_code(response, 200) assert not handler.emails
def test_connection_wrong_port(self) -> None: """Server started on 25, client tries on 26""" EmailSettings.connection_security = "NONE" EmailSettings.port = 25 handler = AIOHandler() with AiosmtpdServerManager(handler): EmailSettings.port = 26 with pytest.raises(ConnectionRefusedError): EmailMixin.get_mail_connection().__enter__()
def test_self_signed_not_accepted(self) -> None: EmailSettings.connection_security = "STARTTLS" EmailSettings.port = 587 EmailSettings.accept_self_signed_certificate = False with AiosmtpdServerManager(AIOHandler()): with pytest.raises( ssl.SSLCertVerificationError, match="certificate verify failed: self signed certificate", ): EmailMixin.get_mail_connection().__enter__()
def test_sender_with_wrong_sender_name(self) -> None: """wrong name in meeting 1, but okay in meeting 4""" self.create_meeting(4) self.set_models( { "meeting/1": { "users_email_sender": "x]x" }, "meeting/4": { "users_email_sender": "Openslides" }, "user/3": { "username": "******", "first_name": "Jim3", "email": "*****@*****.**", "group_$1_ids": [1], "group_$4_ids": [4], "meeting_ids": [1, 4], }, }, ) handler = AIOHandler() with AiosmtpdServerManager(handler): response = self.request_multi( "user.send_invitation_email", [ { "id": 3, "meeting_id": 1 }, { "id": 3, "meeting_id": 4 }, ], ) self.assert_status_code(response, 200) self.assertEqual(len(handler.emails), 1) self.assertEqual(response.json["results"][0][0]["sent"], False) self.assertEqual(response.json["results"][0][0]["recipient_user_id"], 3) self.assertEqual( response.json["results"][0][0]["recipient_meeting_id"], 1) self.assertIn( 'Invalid characters in the sender name configuration of meeting_id "1". Not allowed chars: "[", "]", "\\"', response.json["results"][0][0]["message"], ) self.assertEqual(response.json["results"][0][1]["sent"], True) self.assertEqual(response.json["results"][0][1]["recipient_user_id"], 3) self.assertEqual( response.json["results"][0][1]["recipient_meeting_id"], 4)
def test_correct_subject_and_body_from_default(self) -> None: response = self.request("meeting.create", { "committee_id": 60, "name": "Test Meeting" }) meeting_id = response.json["results"][0][0]["id"] self.set_models({ "user/2": { "title": "Dr.", f"group_${meeting_id}_ids": [4], "meeting_ids": [meeting_id], } }) handler = AIOHandler() with AiosmtpdServerManager(handler): response = self.request( "user.send_invitation_email", { "id": 2, "meeting_id": meeting_id, }, ) self.assert_status_code(response, 200) self.assertEqual(response.json["results"][0][0]["sent"], True) self.assertIn( 'Content-Type: text/plain; charset="utf-8"', handler.emails[0]["data"], ) self.assertNotIn( 'Content-Type: text/html; charset="utf-8"', handler.emails[0]["data"], ) self.assertIn( "Subject: OpenSlides access data", handler.emails[0]["data"], ) self.assertIn( "Username: Testuser 2", handler.emails[0]["data"], ) self.assertIn( "Dear Dr. Jim Beam", handler.emails[0]["data"], ) self.assertIn( "Password: secret", handler.emails[0]["data"], ) self.assertIn( "https://example.com", handler.emails[0]["data"], )
def test_ConnectionRefusedError_wrong_port(self) -> None: EmailSettings.timeout = 1 handler = AIOHandler() with AiosmtpdServerManager(handler): EmailSettings.port = 26 response = self.request( "user.send_invitation_email", {}, ) self.assert_status_code(response, 200) self.assertIn( "ConnectionRefusedError: [Errno 111] Connection refused", response.json["results"][0][0]["message"], )
def test_connection_interrupted(self) -> None: EmailSettings.connection_security = "NONE" handler = AIOHandler() with AiosmtpdServerManager(handler) as server: with EmailMixin.get_mail_connection() as mail_client: with pytest.raises(smtplib.SMTPServerDisconnected): server.stop() EmailMixin.send_email( mail_client, self.sender, self.receivers, subject="Test-email", content="Hi\r\nThis is some plain text content!", html=False, )
def test_SMTPAuthentificationError_wrong_password(self) -> None: EmailSettings.password = "******" EmailSettings.user = "******" handler = AIOHandler() with AiosmtpdServerManager(handler, auth=True): response = self.request( "user.send_invitation_email", {}, ) self.assert_status_code(response, 200) self.assertIn( "SMTPAuthenticationError: (535, b'5.7.8 Authentication credentials invalid')", response.json["results"][0][0]["message"], )
def test_send_correct(self) -> None: start_time = int(time()) handler = AIOHandler() with AiosmtpdServerManager(handler): response = self.request( "user.send_invitation_email", { "id": 2, "meeting_id": 1, }, ) self.assert_status_code(response, 200) user2 = self.get_model("user/2") self.assertIsInstance(user2.get("last_email_send"), int) self.assertGreaterEqual(user2.get("last_email_send"), start_time)
def test_sender_with_wrong_sender(self) -> None: EmailSettings.default_from_email = "wrong_sender@email" handler = AIOHandler() with AiosmtpdServerManager(handler): response = self.request( "user.send_invitation_email", {}, ) self.assert_status_code(response, 200) self.assertEqual(response.json["results"][0][0]["sent"], False) self.assertEqual(len(handler.emails), 0) self.assertIn( "email wrong_sender@email is not a valid sender email address.", response.json["results"][0][0]["message"], )
def test_SMTPSenderRefused_not_authenticated(self) -> None: handler = AIOHandler() with AiosmtpdServerManager(handler, auth=True): response = self.request( "user.send_invitation_email", { "id": 2, "meeting_id": 1, }, ) self.assert_status_code(response, 200) self.assertIn( f"SMTPSenderRefused: (530, b'5.7.0 Authentication required', '{EmailSettings.default_from_email}')", response.json["results"][0][0]["message"], )
def test_permission_error(self) -> None: """allowed for meeting/1, forbidden for meeting 4""" self.create_meeting(4) self.set_models( { "user/1": { "organization_management_level": None, "group_$1_ids": [2], # admin group "group_$4_ids": [4], # default group without rights "meeting_ids": [1, 4], }, "user/2": { "group_$4_ids": [4], "meeting_ids": [1, 4], }, }, ) handler = AIOHandler() with AiosmtpdServerManager(handler): response = self.request_multi( "user.send_invitation_email", [ { "id": 2, "meeting_id": 1 }, { "id": 2, "meeting_id": 4 }, ], ) self.assert_status_code(response, 200) self.assertEqual(len(handler.emails), 1) self.assertEqual(response.json["results"][0][0]["sent"], True) self.assertEqual(response.json["results"][0][0]["recipient_user_id"], 2) self.assertEqual( response.json["results"][0][0]["recipient_meeting_id"], 1) self.assertEqual(response.json["results"][0][1]["sent"], False) self.assertEqual(response.json["results"][0][1]["recipient_user_id"], 2) self.assertEqual( response.json["results"][0][1]["recipient_meeting_id"], 4) self.assertIn( "Missing Permission: user.can_manage", response.json["results"][0][1]["message"], )
def test_authentication_wrong_credentials(self) -> None: EmailSettings.connection_security = "NONE" EmailSettings.port = 25 EmailSettings.user = self.sender EmailSettings.password = "******" handler = AIOHandler() with AiosmtpdServerManager(handler, auth=True): with pytest.raises(smtplib.SMTPAuthenticationError) as e: with EmailMixin.get_mail_connection(): pass self.assertEqual(e.value.smtp_code, 535) self.assertEqual(e.value.smtp_error, b"5.7.8 Authentication credentials invalid") self.assertEqual(len(handler.emails), 0)
def test_SSLCertVerificationError_self_signed(self) -> None: EmailSettings.connection_security = "STARTTLS" EmailSettings.port = 587 EmailSettings.accept_self_signed_certificate = False handler = AIOHandler() with AiosmtpdServerManager(handler): response = self.request( "user.send_invitation_email", {}, ) self.assert_status_code(response, 200) self.assertIn( "SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self signed certificate", response.json["results"][0][0]["message"], )
def test_reply_to_correct(self) -> None: self.set_models( {"meeting/1": { "users_email_replyto": "*****@*****.**" }}, ) handler = AIOHandler() with AiosmtpdServerManager(handler): response = self.request( "user.send_invitation_email", { "id": 2, "meeting_id": 1, }, ) self.assert_status_code(response, 200) self.assertEqual(response.json["results"][0][0]["sent"], True) self.assertIn("Reply-To: [email protected]", handler.emails[0]["data"])
def test_forget_password_two_users_with_email(self) -> None: self.set_models({ "organization/1": { "url": "https://openslides.example.com" }, "user/1": { "email": "*****@*****.**" }, "user/2": { "email": "*****@*****.**", "username": "******" }, "user/3": { "email": "*****@*****.**", "username": "******" }, }) start_time = int(time()) handler = AIOHandler() with AiosmtpdServerManager(handler): response = self.request("user.forget_password", {"email": "*****@*****.**"}) self.assert_status_code(response, 200) user = self.get_model("user/1") assert user.get("last_email_send", 0) >= start_time user2 = self.get_model("user/2") assert user2.get("last_email_send", 0) >= start_time user3 = self.get_model("user/3") assert user3.get("last_email_send", 0) == 0 assert handler.emails[0]["from"] == EmailSettings.default_from_email assert handler.emails[0]["to"][0] == "*****@*****.**" assert ("For completeness your username: admin" in handler.emails[0]["data"] or "For completeness your username: test2" in handler.emails[0]["data"]) assert "https://openslides.example.com" in handler.emails[0]["data"] assert handler.emails[1]["from"] == EmailSettings.default_from_email assert handler.emails[1]["to"][0] == "*****@*****.**" assert ("For completeness your username: test2" in handler.emails[1]["data"] or "For completeness your username: admin" in handler.emails[1]["data"]) assert "https://openslides.example.com" in handler.emails[1]["data"]
def test_forget_password_send_mail_correct(self) -> None: self.set_models({ "organization/1": { "url": None }, "user/1": { "email": "*****@*****.**" } }) start_time = int(time()) handler = AIOHandler() with AiosmtpdServerManager(handler): response = self.request("user.forget_password", {"email": "*****@*****.**"}) self.assert_status_code(response, 200) user = self.get_model("user/1") assert user.get("last_email_send", 0) >= start_time assert handler.emails[0]["from"] == EmailSettings.default_from_email assert "Reset your OpenSlides password" in handler.emails[0]["data"]
def test_reply_to_error(self) -> None: self.set_models( {"meeting/1": { "users_email_replyto": "reply@example" }}, ) handler = AIOHandler() with AiosmtpdServerManager(handler): response = self.request( "user.send_invitation_email", { "id": 2, "meeting_id": 1, }, ) self.assert_status_code(response, 200) self.assertEqual(response.json["results"][0][0]["sent"], False) self.assertIn( "The given reply_to address 'reply@example' is not valid.", response.json["results"][0][0]["message"], )
def test_authentication_ssl_tls(self) -> None: EmailSettings.connection_security = "SSL/TLS" EmailSettings.accept_self_signed_certificate = True EmailSettings.port = 465 EmailSettings.user = self.sender EmailSettings.password = self.password handler = AIOHandler() with AiosmtpdServerManager(handler, auth=True): with EmailMixin.get_mail_connection() as mail_client: EmailMixin.send_email( mail_client, self.sender, self.receivers, subject="Test-email", content="Hi\r\nThis is some plain text content!", html=False, ) self.assertEqual("250 Message accepted for delivery", handler.ret_status) self.assertEqual(len(handler.emails), 1)
def test_forget_password_wrong_email_password(self) -> None: EmailSettings.password = "******" EmailSettings.user = "******" self.set_models({ "organization/1": { "url": None }, "user/1": { "email": "*****@*****.**" } }) handler = AIOHandler() with AiosmtpdServerManager(handler): response = self.request("user.forget_password", {"email": "*****@*****.**"}) self.assert_status_code(response, 400) assert ( "The server was configured improperly. Please contact your administrator." in response.json["message"])
def test_authentication_not_authenticated(self) -> None: EmailSettings.connection_security = "NONE" EmailSettings.port = 25 handler = AIOHandler() with AiosmtpdServerManager(handler, auth=True): with EmailMixin.get_mail_connection() as mail_client: with pytest.raises(smtplib.SMTPSenderRefused) as e: EmailMixin.send_email( mail_client, self.sender, self.receivers, subject="Test-email", content="Hi\r\nThis is some plain text content!", html=False, ) self.assertEqual(e.value.sender, "*****@*****.**") self.assertEqual(e.value.smtp_code, 530) self.assertEqual(e.value.smtp_error, b"5.7.0 Authentication required") self.assertEqual(len(handler.emails), 0)
def test_authentication_no_encryption(self) -> None: EmailSettings.connection_security = "NONE" EmailSettings.port = 25 EmailSettings.user = self.sender EmailSettings.password = self.password handler = AIOHandler() with AiosmtpdServerManager(handler, auth=True): with EmailMixin.get_mail_connection() as mail_client: response = EmailMixin.send_email( mail_client, self.sender, self.receivers, subject="Test-email", content="Hi\r\nThis is some plain text content!", html=False, ) self.assertEqual(len(response), 0) self.assertEqual("250 Message accepted for delivery", handler.ret_status) self.assertEqual(len(handler.emails), 1)
def test_sender_with_sender_name(self) -> None: handler = AIOHandler() with AiosmtpdServerManager(handler): response = self.request( "user.send_invitation_email", { "id": 2, "meeting_id": 1, }, ) self.assert_status_code(response, 200) self.assertEqual(response.json["results"][0][0]["sent"], True) self.assertEqual(response.json["results"][0][0]["recipient"], "*****@*****.**") meeting = self.get_model("meeting/1") self.assertEqual(response.json["results"][0][0]["recipient_user_id"], 2) self.assertEqual(handler.emails[0]["from"], EmailSettings.default_from_email) self.assertIn( f"From: {meeting.get('users_email_sender')} <{EmailSettings.default_from_email}>", handler.emails[0]["data"], )
def test_send_html_email(self) -> None: EmailSettings.connection_security = "NONE" EmailSettings.port = 25 handler = AIOHandler() with AiosmtpdServerManager(handler): with EmailMixin.get_mail_connection() as mail_client: response = EmailMixin.send_email( mail_client, self.sender, self.receivers, subject= "A mail from intevation-test: html with generated plain", content=""" <html> <body> <p>Hello dear customer,<br> really nice to meet <strong>you</strong> in html with a <strong>strong you</strong></p> <p>Besides the HTML there is also an auto-generated plain text version</p> </body> </html> """, ) self.assertEqual(len(response), 0) self.assertEqual("250 Message accepted for delivery", handler.ret_status) self.assertEqual(len(handler.emails), 1) self.assertEqual(handler.emails[0]["from"], self.sender) self.assertEqual(handler.emails[0]["to"], self.receivers) self.assertIn( 'Content-Type: text/plain; charset="utf-8"', handler.emails[0]["data"], ) self.assertIn( 'Content-Type: text/html; charset="utf-8"', handler.emails[0]["data"], )
def test_send_starttls(self) -> None: EmailSettings.connection_security = "STARTTLS" EmailSettings.accept_self_signed_certificate = True EmailSettings.port = 587 handler = AIOHandler() with AiosmtpdServerManager(handler): with EmailMixin.get_mail_connection() as mail_client: response = EmailMixin.send_email( mail_client, self.sender, self.receivers, subject="Test-email", content="Hi\r\nThis is some plain text content!", html=False, ) self.assertEqual(len(response), 0) self.assertEqual("250 Message accepted for delivery", handler.ret_status) self.assertEqual(len(handler.emails), 1) self.assertEqual(handler.emails[0]["from"], self.sender) self.assertEqual(handler.emails[0]["to"], self.receivers) self.assertIn("Hi\r\nThis is some plain text content!", handler.emails[0]["data"])