def connect_to_exchange_as_current_user(self, smtp): # Send the SMTP EHLO command code, response = smtp.ehlo() if code != self._config.SMTP_EHLO_OKAY: raise SMTPException( "Server did not respond as expected to EHLO command") sspiclient = sspi.ClientAuth('NTLM') # Generate the NTLM Type 1 message sec_buffer = None err, sec_buffer = sspiclient.authorize(sec_buffer) ntlm_message = self.asbase64(sec_buffer[0].Buffer) # Send the NTLM Type 1 message -- Authentication Request code, response = smtp.docmd("AUTH", "NTLM " + ntlm_message) # Verify the NTLM Type 2 response -- Challenge Message if code != self._config.SMTP_AUTH_CHALLENGE: raise SMTPException( "Server did not respond as expected to NTLM negotiate message") # Generate the NTLM Type 3 message err, sec_buffer = sspiclient.authorize(base64.decodestring(response)) ntlm_message = self.asbase64(sec_buffer[0].Buffer) # Send the NTLM Type 3 message -- Response Message #code, response = smtp.docmd("", ntlm_message) code, response = smtp.docmd(ntlm_message) if code != self._config.SMTP_AUTH_OKAY: raise SMTPAuthenticationError(code, response)
def connect_to_exchange_as_current_user(smtp): """Example: >>> import smtplib >>> smtp = smtplib.SMTP("mail.huajingsec.com") >>> connect_to_exchange_as_current_user(smtp) """ # Send the SMTP EHLO command code, response = smtp.ehlo() if code != SMTP_EHLO_OKAY: raise SMTPException( "Server did not respond as expected to EHLO command") sspiclient = sspi.ClientAuth('NTLM') # Generate the NTLM Type 1 message sec_buffer = None err, sec_buffer = sspiclient.authorize(sec_buffer) print(sec_buffer) ntlm_message = asbase64(sec_buffer[0].Buffer) # Send the NTLM Type 1 message -- Authentication Request code, response = smtp.docmd("AUTH", "NTLM " + ntlm_message) # Verify the NTLM Type 2 response -- Challenge Message if code != SMTP_AUTH_CHALLENGE: raise SMTPException( "Server did not respond as expected to NTLM negotiate message") # Generate the NTLM Type 3 message err, sec_buffer = sspiclient.authorize( base64.b64decode(response.encode(encoding='utf-8'))) ntlm_message = asbase64(sec_buffer[0].Buffer) # Send the NTLM Type 3 message -- Response Message code, response = smtp.docmd(ntlm_message) # code, response = smtp.docmd("", ntlm_message) if code != SMTP_AUTH_OKAY: raise SMTPAuthenticationError(code, response)
def __connect_to_exchange(self, smtp): ''' Connects to an exchange server for SMTP authentication. This uses NTLM method which attempts to authenticate as the currently logged in user. This means whatever account is used to run this process must have access to the exchange server for sending email. Example: >>> import smtplib >>> smtp = smtplib.SMTP("my.smtp.server") >>> __connect_to_exchange(smtp) ''' # NTLM Guide -- http://curl.haxx.se/rfc/ntlm.html # Send the SMTP EHLO command code, response = smtp.ehlo() if code != SMTP_EHLO_OKAY: raise SMTPException( "Server did not respond as expected to EHLO command") sspiclient = sspi.ClientAuth('NTLM') # login as current user # Generate the NTLM Type 1 message sec_buffer = None err, sec_buffer = sspiclient.authorize(sec_buffer) ntlm_message = self.__asbase64(sec_buffer[0].Buffer) # Send the NTLM Type 1 message -- Authentication Request code, response = smtp.docmd("AUTH", "NTLM " + ntlm_message) # Verify the NTLM Type 2 response -- Challenge Message if code != SMTP_AUTH_CHALLENGE: raise SMTPException( "Server did not respond as expected to NTLM negotiate message") # Generate the NTLM Type 3 message err, sec_buffer = sspiclient.authorize(base64.decodestring(response)) ntlm_message = self.__asbase64(sec_buffer[0].Buffer) if err: self.__root_logger.warning(('Error while authenticating to ' 'exchange server')) # Send the NTLM Type 3 message -- Response Message code, response = smtp.docmd("", ntlm_message) if code != SMTP_AUTH_OKAY: raise SMTPAuthenticationError(code, response)
def test_send_email_smtp_exception_return_false(self): """Should return False if EmailMultiAlternatives instance's save method raise SMTPException. """ # send() will raise SMTPException self.email_instance_mock.send.side_effect = SMTPException() self.assertFalse(self.send_email())
def test_logging_when_sending_cr_attachment_available_email_raise_error( self, mock_send_email, mock_logger): mock_send_email.side_effect = SMTPException('Sending failed') EmailTemplateFactory( subject='To {name}', body='This message is related to crid {pk} with url {url}', from_email='*****@*****.**', type=CR_ATTACHMENT_AVAILABLE) allegation_123 = AllegationFactory(crid='123') AttachmentRequestFactory(allegation=allegation_123, email='*****@*****.**', noti_email_sent=False) AttachmentFileFactory(allegation=allegation_123) new_attachments = AttachmentFile.objects.all() send_cr_attachment_available_email(new_attachments) expect(AttachmentRequest.objects.filter( noti_email_sent=True).count()).to.eq(0) expect( AttachmentRequest.objects.filter( noti_email_sent=False).count()).to.eq(1) expect(mock_logger.info).to.be.called_with( 'Cannot send notification email for crid 123 to [email protected]' )
def login_fips_safe(self, user, password, *, initial_response_ok=True): """Log in on an SMTP server that requires authentication. The arguments are: - user: The user name to authenticate with. - password: The password for the authentication. Keyword arguments: - initial_response_ok: Allow sending the RFC 4954 initial-response to the AUTH command, if the authentication methods supports it. If there has been no previous EHLO or HELO command this session, this method tries ESMTP EHLO first. This method will return normally if the authentication was successful. This method may raise the following exceptions: SMTPHeloError The server didn't reply properly to the helo greeting. SMTPAuthenticationError The server didn't accept the username/ password combination. SMTPNotSupportedError The AUTH command is not supported by the server. SMTPException No suitable authentication method was found. """ self.ehlo_or_helo_if_needed() if not self.has_extn("auth"): raise SMTPNotSupportedError( "SMTP AUTH extension not supported by server.") # Authentication methods the server claims to support advertised_authlist = self.esmtp_features["auth"].split() # Authentication methods we can handle in our preferred order: preferred_auths = ["PLAIN", "LOGIN"] # We try the supported authentications in our preferred order, if # the server supports them. authlist = [ auth for auth in preferred_auths if auth in advertised_authlist ] if not authlist: raise SMTPException("No suitable authentication method found.") # Some servers advertise authentication methods they don't really # support, so if authentication fails, we continue until we've tried # all methods. self.user, self.password = user, password for authmethod in authlist: method_name = "auth_" + authmethod.lower().replace("-", "_") try: (code, resp) = self.auth(authmethod, getattr(self, method_name), initial_response_ok=initial_response_ok) # 235 == 'Authentication successful' # 503 == 'Error: already authenticated' if code in (235, 503): return (code, resp) except SMTPAuthenticationError as e: last_exception = e # We could not login successfully. Return result of last attempt. raise last_exception
def test_add_master_course_staff_to_ccx_with_exception(self): """ When exception raise from ``enroll_email`` assert that enrollment skipped for that staff or instructor. """ staff = self.make_staff() assert CourseStaffRole(self.course.id).has_user(staff) # adding instructor to master course. instructor = self.make_instructor() assert CourseInstructorRole(self.course.id).has_user(instructor) with mock.patch.object(CourseEnrollment, 'enroll_by_email', side_effect=CourseEnrollmentException()): add_master_course_staff_to_ccx(self.course, self.ccx_locator, self.ccx.display_name) assert not CourseEnrollment.objects.filter( course_id=self.ccx_locator, user=staff).exists() assert not CourseEnrollment.objects.filter( course_id=self.ccx_locator, user=instructor).exists() with mock.patch.object(CourseEnrollment, 'enroll_by_email', side_effect=SMTPException()): add_master_course_staff_to_ccx(self.course, self.ccx_locator, self.ccx.display_name) assert not CourseEnrollment.objects.filter( course_id=self.ccx_locator, user=staff).exists() assert not CourseEnrollment.objects.filter( course_id=self.ccx_locator, user=instructor).exists()
def sendmail(from_address, dest_addresses, msg): if from_address == "invalid1": raise SMTPException("SMTP Error") if from_address == "invalid2": raise BaseException("Generic Error") fpath = "/logs/mock.mail.lastsent.json" data = {"from": from_address, "cc": dest_addresses, "msg": msg} log.info("Mail mock sending email from {} to {}", from_address, dest_addresses) with open(fpath, "w+") as file: file.write(json.dumps(data)) log.info("Mail mock sent email from {} to {}", from_address, dest_addresses) log.info("Mail mock mail written in {}", fpath) log.info("Extracting body") fpath = "/logs/mock.mail.lastsent.body" b = email.message_from_string(msg) if b.is_multipart(): # get the first payload (the non html version) first_payload = b.get_payload()[0] payload = first_payload.get_payload() else: payload = b.get_payload() with open(fpath, "w+") as file: file.write(payload) log.info("Mail body written in {}", fpath)
def send_lost_mail(self, request, email): # """ Generate an UUID64 and store it in redis """ reset_key = Uuid4().generate() redis_key = 'password_reset_' + reset_key """ Store the reset-key in Redis """ # The 'a' is for Redis stats, to make a distinction with Token entries self.redis_base.hmset(redis_key, {'email': email, 'a': 1}) """ The key will expire in 10 minutes """ self.redis_base.expire(redis_key, 600) """ Send the email with the link """ reset_link = self.application.get_redirect_uri() + str( self.token_name) + '/self/change?rdm=' + reset_key msg = MIMEMultipart('alternative') email_from = self.application.template.email_from msg['From'] = email_from msg['To'] = email obj = { 'name': self.application.name, 'url': self.application.get_redirect_uri() } env = Environment( loader=FileSystemLoader("/home/vlt-gui/vulture/portal/templates/")) msg['subject'] = env.get_template( "portal_%s_email_subject.conf" % (str(self.application.template.id))).render({'app': obj}) email_body = env.get_template( "portal_%s_email_body.conf" % (str(self.application.template.id))).render({ 'resetLink': reset_link, 'app': obj }) msg.attach(MIMEText(email_body, "html")) node = self.cluster.get_current_node() if hasattr(node.system_settings, 'smtp_settings') and getattr( node.system_settings, 'smtp_settings'): settings = getattr(node.system_settings, 'smtp_settings') else: """ Not found, use cluster settings for configuration """ settings = getattr(self.cluster.system_settings, 'smtp_settings') try: logger.debug("Sending link '{}' to '{}'".format(reset_link, email)) smtpObj = SMTP(settings.smtp_server) # message = "Subject: " + unicode (email_subject) + "\n\n" + unicode (email_body) smtpObj.sendmail(email_from, email, msg.as_string()) except Exception as e: logger.error( "SELF::Lost: Failed to send email to '{}' : ".format(email)) logger.exception(e) raise SMTPException( "<b>Send mail failure</b> <br> Please contact your administrator" ) return "Mail successfully sent to '{}'".format(email)
def test_send_email_smtp_exception_log_warning(self): """Should log exception as warning if EmailMultiAlternatives instance's save method raise SMTPException. """ self.email_instance_mock.send.side_effect = SMTPException() self.send_email() self.logger_mock.warning.assert_called_with( self.email_instance_mock.send.side_effect)
def test_user_register_email_send_failure(self, mock_mail_managers): """Test that a registration email send failure logs the correct error message.""" mock_mail_managers.side_effect = SMTPException('exception content') with self.assertLogs('tom_registration.registration_flows.approval_required.views', level='ERROR') as logs: self.client.post(reverse('registration:register'), data=self.user_data) self.assertIn( 'ERROR:tom_registration.registration_flows.approval_required.views:' 'Unable to send email: exception content', logs.output)
def test_email_dependency_send_email_raise_error(self, mock_container): dependency_provider = EmailDependency().bind(mock_container, "email") worker_ctx = None with patch("users.dependencies.email.smtplib"): email = dependency_provider.get_dependency(worker_ctx) email.smtp_obj.sendmail.side_effect = SMTPException() with pytest.raises(EmailSendError): email.send("email_receiver", "email_subject", "email_content")
def fake_send_email_with_exception(subject, message, from_email, recipient_list, fail_silently=False, auth_user=None, auth_password=None, connection=None, html_message=None): from smtplib import SMTPException raise SMTPException('Something really bad happened!')
def test_send_test_email_returns_error_for_send_mail_exception( self, send_mail): send_mail.side_effect = SMTPException() url = reverse('des-test-email') email = '*****@*****.**' response = self.client.post(url, {'email': email}) self.assertIsNotNone(response.wsgi_request._messages) messages = list(response.wsgi_request._messages) self.assertTrue('messages' in response.cookies) self.assertEqual(len(messages), 1) self.assertIn('Could not send email', messages[0].message)
def test_if_smtp_exception_adds_error_message_only(self, mock_send_mail): mock_send_mail.side_effect = SMTPException() response = self.client.post('/accounts/send_login_email', data={ 'email': '*****@*****.**' }, follow=True) self.assertEqual(len(response.context['messages']), 1) message = list(response.context['messages'])[0] self.assertEqual( message.message, "Sorry, can't connect to email server. Please try again after few minutes." ) self.assertEqual(message.tags, 'error')
def test_email_error(self, mass_mail): data = {'title': 'yeah', 'content': 'message'} form = UserQueryForm(data) user_1 = User(email='*****@*****.**') view = EmailInterface() view.users_result = [user_1] mass_mail.side_effect = SMTPException('fail') view.email_users(form) self.assertEquals(form.errors['__all__'], 'error sending email: fail')
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_failed_email_doesnt_create_notification(self): self.assertEqual(Notification.objects.count(), 0) self.mock_send_mail.side_effect = SMTPException() tasks.send_review_email_task( self.user.id, self.experiment.name, self.experiment.experiment_url, False, ) self.mock_send_mail.assert_called() self.assertEqual(Notification.objects.count(), 0)
def ntlm_authenticate(smtp, username, password): """Example: >>> import smtplib >>> smtp = smtplib.SMTP("my.smtp.server") >>> smtp.ehlo() >>> ntlm_authenticate(smtp, r"DOMAIN\username", "password") """ code, response = smtp.docmd("AUTH", "NTLM " + asbase64(ntlm.create_NTLM_NEGOTIATE_MESSAGE(username))) if code != 334: raise SMTPException("Server did not respond as expected to NTLM negotiate message") challenge, flags = ntlm.parse_NTLM_CHALLENGE_MESSAGE(decodestring(response)) user_parts = username.split("\\", 1) code, response = smtp.docmd("", asbase64(ntlm.create_NTLM_AUTHENTICATE_MESSAGE(challenge, user_parts[1], user_parts[0], password, flags))) if code != 235: raise SMTPAuthenticationError(code, response)
def test_user_approve_email_send_failure(self, mock_send_mail): """Test that an approval email send failure logs the correct error message.""" self.client.force_login(self.superuser) test_user_data = copy.copy(self.user_data) test_user_data['password'] = test_user_data.pop('password1') test_user_data.pop('password2') user = User.objects.create(**test_user_data, is_active=False) mock_send_mail.side_effect = SMTPException('exception content') with self.assertLogs('tom_registration.registration_flows.approval_required.views', level='ERROR') as logs: self.client.post(reverse('registration:approve', kwargs={'pk': user.id}), data=test_user_data) self.assertIn( 'ERROR:tom_registration.registration_flows.approval_required.views:' 'Unable to send email: exception content', logs.output)
def test_send_email_with_send_error(self): """ Check exception message is sent when a mail server is not configured. """ projectbuild, build = self.create_build_data(email="*****@*****.**") with mock.patch.object(User, "email_user", side_effect=SMTPException()) as mock_send: with mock.patch("projects.tasks.logging") as mock_logging: send_email(build, "") self.assertEqual(0, len(mail.outbox)) self.assertTrue(mock_send.called) mock_logging.exception.assert_called_once_with( "Error sending Email: %s", mock_send.side_effect)
def test_send_email_to_user_raises_exception(self, mock_mail, mock_logger): user = MoodyUtil.create_user() user.email = '*****@*****.**' user.save() exc = SMTPException() mock_mail.side_effect = exc call_command('accounts_recover_user_account', user.username) mock_logger.assert_called_with( 'Unable to send password reset email to user {}'.format( user.username), output_stream='stderr', log_level=logging.ERROR, extra={'exc': exc})
def test_generate_email_token_mail_server_not_working(self): data = { 'email': '*****@*****.**', 'callback': 'http://dominio.prueba/callback' } with mock.patch.object(EmailMultiAlternatives, 'send') as mock_method: mock_method.side_effect = SMTPException() response = self.client.post( '/authentication/email-generate-token/', data, format='json') self.assertEqual(response.status_code, 500) self.assertEqual( EmailOTPCode.objects.filter(user__username='******').count(), 1) self.assertEqual(len(mail.outbox), 0)
def sendmail(from_address: str, dest_addresses: str, msg: str) -> None: if from_address == "invalid1": raise SMTPException("SMTP Error") if from_address == "invalid2": raise Exception("Generic Error") json_fpath = LOGS_FOLDER.joinpath("mock.mail.lastsent.json") body_fpath = LOGS_FOLDER.joinpath("mock.mail.lastsent.body") json_fpath_prev = LOGS_FOLDER.joinpath("mock.mail.prevsent.json") body_fpath_perv = LOGS_FOLDER.joinpath("mock.mail.prevsent.body") if json_fpath.exists(): json_fpath.rename(json_fpath_prev) if body_fpath.exists(): body_fpath.rename(body_fpath_perv) data = {"from": from_address, "cc": dest_addresses, "msg": msg} log.info("Mail mock sending email from {} to {}", from_address, dest_addresses) with open(json_fpath, "w+") as file: file.write(orjson.dumps(data).decode("UTF-8")) log.info("Mail mock sent email from {} to {}", from_address, dest_addresses) log.info("Mail mock mail written in {}", json_fpath) log.info("Extracting body") b = email.message_from_string(msg) if b.is_multipart(): # get the first payload (the non html version) first_payload = b.get_payload()[0] # This is enough when the message is not based64-encoded payload = first_payload.get_payload() # Otherwise this is needed: payload = first_payload.get_payload(decode=True).decode("utf-8") else: # This is enough when the message is not based64-encoded # payload = b.get_payload() # Otherwise this is needed: payload = b.get_payload(decode=True).decode("utf-8") with open(body_fpath, "w+") as file: file.write(payload) log.info("Mail body written in {}", body_fpath)
def test_send_mail_fails(self, send_mail_func): email_object = Email.objects.create( email_recipient="*****@*****.**", from_address="*****@*****.**", email_subject="hi", email_body="hello", ) self.assertIsNone(email_object.sent_timestamp) send_mail_func.side_effect = SMTPException("Test exception") result = email_object.send() self.assertEqual(result, False) self.assertEqual(email_object.last_error_message, "Test exception") self.assertIsNone(email_object.sent_timestamp) email_object.refresh_from_db() self.assertEqual(email_object.last_error_message, "Test exception") self.assertIsNone(email_object.sent_timestamp)
def test_email_dashboard_report_fails( screenshot_mock, email_mock, create_report_email_dashboard ): """ ExecuteReport Command: Test dashboard email report schedule notification fails """ # setup screenshot mock from smtplib import SMTPException screenshot_mock.return_value = SCREENSHOT_FILE email_mock.side_effect = SMTPException("Could not connect to SMTP XPTO") with pytest.raises(ReportScheduleNotificationError): AsyncExecuteReportScheduleCommand( TEST_ID, create_report_email_dashboard.id, datetime.utcnow() ).run() assert_log(ReportState.ERROR, error_message="Could not connect to SMTP XPTO")
def __init__(self, smtpserver, user=None, password=None, senderAddress=None, replytoAddress=None): self.smtpserver = smtpserver self.user = user self.password = password self.sender = senderAddress self.replyto = replytoAddress try: # validate the smtp connection smtp = SMTP(self.smtpserver) if self.user: smtp.login(self.user, self.password) smtp.quit() except socket.error, x: raise SMTPException("could not connect to smtp server")
def starttls(self, keyfile=None, certfile=None, **kwargs): self.ehlo_or_helo_if_needed() if not self.has_extn("starttls"): raise SMTPException("STARTTLS extension not supported by server.") (resp, reply) = self.docmd("STARTTLS") if resp == 220: if not _have_ssl: raise RuntimeError("No SSL support included in this Python") self.sock = ssl.wrap_socket(self.sock, keyfile, certfile, **kwargs) self.file = SSLFakeFile(self.sock) # RFC 3207: # The client MUST discard any knowledge obtained from # the server, such as the list of SMTP service extensions, # which was not obtained from the TLS negotiation itself. self.helo_resp = None self.ehlo_resp = None self.esmtp_features = {} self.does_esmtp = 0 return (resp, reply)
def handle(self, *args, **options): csvfile = io.StringIO() writer = csv.writer(csvfile) writer.writerow([ 'Col A', 'Col B', ]) email = EmailMessage( utils.format_mail_subject( "Démarrage de l'application - mail test"), "Test de l'envoi des mails depuis l'application BVC.", settings.EMAIL_HOST_USER, [settings.EMAIL_HOST_USER], [], ) email.attach('test.csv', csvfile.getvalue(), 'text/csv') if not email.send(): raise SMTPException()
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}"))