예제 #1
0
def send_email(prefs, report_str):
    recipients = prefs['ADMIN_EMAIL'].split(',')

    msg = dedent("""
        From: %s
        To: %s
        Subject: %s
        Date: %s

        """).lstrip() % (prefs.get('SMTP_FROM'), prefs.get('ADMIN_EMAIL'),
                         prefs.get('SMTP_SUBJECT'),
                         time.strftime(prefs.get('SMTP_DATE_FORMAT')))

    msg += report_str
    try:
        smtp = SMTP()

        if logging.getLogger().isEnabledFor(logging.DEBUG):
            smtp.set_debuglevel(1)

        smtp.connect(prefs.get('SMTP_HOST'), prefs.get('SMTP_PORT'))

        # If the server supports ESMTP and TLS, then convert the message exchange to TLS via the
        # STARTTLS command.
        if smtp.ehlo()[0] == 250:
            if smtp.has_extn('starttls'):
                (code, resp) = smtp.starttls()
                if code != 220:
                    raise SMTPResponseException(code, resp)
                (code, resp) = smtp.ehlo()
                if code != 250:
                    raise SMTPResponseException(code, resp)
        else:
            # The server does not support esmtp.

            # The Python library SMTP class handles executing HELO/EHLO commands inside
            # login/sendmail methods when neither helo()/ehlo() methods have been
            # previously called.  Because we have already called ehlo() above, we must
            # manually fallback to calling helo() here.

            (code, resp) = smtp.helo()
            if not (200 <= code <= 299):
                raise SMTPHeloError(code, resp)

        username = prefs.get('SMTP_USERNAME')
        password = prefs.get('SMTP_PASSWORD')

        if username and password:
            smtp.login(username, password)

        smtp.sendmail(prefs.get('SMTP_FROM'), recipients, msg)
        debug("sent email to: %s" % prefs.get("ADMIN_EMAIL"))
    except Exception, e:
        print "Error sending email"
        print e
        print "Email message follows:"
        print msg
예제 #2
0
def test_custom_smtp_backend(backend: T, from_addr: str) -> None:
    try:
        backend.open()
        backend.connection.ehlo_or_helo_if_needed()
        (code, resp) = backend.connection.mail(from_addr, [])
        if code != 250:
            logger.warning('Error testing mail settings, code %d, resp: %s' % (code, resp))
            raise SMTPResponseException(code, resp)
        (code, resp) = backend.connection.rcpt('*****@*****.**')
        if (code != 250) and (code != 251):
            logger.warning('Error testing mail settings, code %d, resp: %s' % (code, resp))
            raise SMTPResponseException(code, resp)
    finally:
        backend.close()
예제 #3
0
 def test(self, from_addr):
     try:
         self.open()
         self.connection.ehlo_or_helo_if_needed()
         (code, resp) = self.connection.mail(from_addr, [])
         if code != 250:
             logger.warn('Error testing mail settings, code %d, resp: %s' % (code, resp))
             raise SMTPResponseException(code, resp)
         (code, resp) = self.connection.rcpt('*****@*****.**')
         if (code != 250) and (code != 251):
             logger.warn('Error testing mail settings, code %d, resp: %s' % (code, resp))
             raise SMTPResponseException(code, resp)
     finally:
         self.close()
예제 #4
0
    def get_response(self):
        """Get a status reponse from the server.

        Returns a tuple consisting of:

          - server response code (e.g. '250', or such, if all goes well)
            Note: returns -1 if it can't read response code.

          - server response string corresponding to response code (multiline
            responses are converted to a single, multiline string).

        Raises SMTPResponseException for codes > 500.
        """
        code = -1
        response = []
        while True:
            try:
                line = yield from self.reader.readline()
            except ConnectionResetError as exc:
                raise SMTPServerDisconnected(exc)

            if not line:
                break

            if len(line) > MAX_LINE_LENGTH:
                raise SMTPResponseException(500, "Line too long.")

            code = line[:3]
            message = line[4:]
            message = message.strip(b' \t\r\n')  # Strip newlines
            message = message.decode()  # Convert to string
            response.append(message)

            try:
                code = int(code)
            except ValueError:
                code = -1

            if line[3:4] != b"-":
                break

        message = "\n".join(response)
        if self.debug:
            logger.debug("reply: %s %s", code, message)
        if 500 <= code <= 599:
            raise SMTPResponseException(code, message)

        return code, message
예제 #5
0
def test_email_server(ip_address: str) -> None:
    """Attempt to connect to an SMTP server.

    Raises:
        OSError: if a network-related system error occurs, for example if the IP
                 address is a v6 address but the system lacks an IPv6 route, or
                 if the connection times out
        SMTPResponseException: if the server sends an invalid response
        SMTPServerDisconnected: if the server hangs up on us or fails to respond
                                both correctly and quickly enough

    """
    smtp = SMTP(timeout=5.0)
    if website.env.logging_level == 'debug':
        smtp.set_debuglevel(2)
    try:
        code = smtp.connect(ip_address)[0]
        if code < 0:
            raise SMTPResponseException(
                code, "first line received from server is invalid")
    finally:
        try:
            smtp.close()
        except Exception:
            pass
예제 #6
0
 def test_smpt_error_code_500(self):
     # to handle this kind of error
     # http://docs.python.org/2.7/library/smtplib.html#smtplib.SMTPResponseException
     with patch("django.core.mail.EmailMultiAlternatives.send") as send_mail:
         send_mail.side_effect = SMTPResponseException(500, "")
         result_of_sending, fatal_error = self.channel.send(self.outbound_message1)
         self.assertFalse(result_of_sending)
         self.assertTrue(fatal_error)
예제 #7
0
 def __exit__(self, *args):
     try:
         code, message = self.docmd("QUIT")
         if code != 221:
             raise SMTPResponseException(code, message)
     except SMTPServerDisconnected:
         pass
     finally:
         self.close()
예제 #8
0
    def starttls(self, keyfile=None, certfile=None, context=None):
        """Puts the connection to the SMTP server into TLS mode.

        If there has been no previous EHLO or HELO command this session, this
        method tries ESMTP EHLO first.

        If the server supports TLS, this will encrypt the rest of the SMTP
        session. If you provide the keyfile and certfile parameters,
        the identity of the SMTP server and client can be checked. This,
        however, depends on whether the socket module really checks the
        certificates.

        This method may raise the following exceptions:

         SMTPHeloError            The server didn't reply properly to
                                  the helo greeting.
        """
        self.ehlo_or_helo_if_needed()
        if not self.has_extn("starttls"):
            raise SMTPNotSupportedError(
                "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")
            if context is not None and keyfile is not None:
                raise ValueError("context and keyfile arguments are mutually "
                                 "exclusive")
            if context is not None and certfile is not None:
                raise ValueError("context and certfile arguments are mutually "
                                 "exclusive")
            if keyfile is not None or certfile is not None:
                import warnings
                warnings.warn(
                    "keyfile and certfile are deprecated, use a"
                    "custom context instead", DeprecationWarning, 2)
            if context is None:
                context = ssl._create_stdlib_context(certfile=certfile,
                                                     keyfile=keyfile)
            self.sock = context.wrap_socket(self.sock,
                                            server_hostname=self._host)
            self.file = None
            # 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
        else:
            # RFC 3207:
            # 501 Syntax error (no parameters allowed)
            # 454 TLS not available due to temporary reason
            raise SMTPResponseException(resp, reply)
        return (resp, reply)
 def mail(self, sender: str, options: tuple = ()):
     """
     Like `smtplib.SMTP.mail`, but raise an appropriate exception on
     negative SMTP server response.
     A code > 400 is an error here.
     """
     code, message = super().mail(sender=sender, options=options)
     if code >= 400:
         raise SMTPResponseException(code=code, msg=message)
     return code, message
예제 #10
0
def test_get_session_ssl_raisesMessSendErr(get_email, mocker):
    """
    GIVEN an incorrect password in a valid Email object
    WHEN Email.get_session() is called
    THEN assert Exception is raised
    """
    get_ssl_mock = mocker.patch.object(Email, '_get_ssl')
    get_ssl_mock.return_value.login.side_effect = SMTPResponseException(
        code=0, msg=b'')
    e = get_email
    with pytest.raises(MessageSendError):
        e._get_session()
예제 #11
0
    def getreply(self):
        """Get a reply from the server.

        Returns a tuple consisting of:

          - server response code (e.g. '250', or such, if all goes well)
            Note: returns -1 if it can't read response code.

          - server response string corresponding to response code (multiline
            responses are converted to a single, multiline string).

        Raises SMTPServerDisconnected if end-of-file is reached.
        """
        resp = []
        if self.file is None:
            self.file = self.sock.makefile('rb')
        while 1:
            try:
                line = self.file.readline(_MAXLINE + 1)
            except OSError as e:
                self.close()
                raise SMTPServerDisconnected(
                    "Connection unexpectedly closed: " + str(e))
            if not line:
                self.close()
                raise SMTPServerDisconnected("Connection unexpectedly closed")
            if self.debuglevel > 0:
                self._print_debug('reply:', repr(line))
            if len(line) > _MAXLINE:
                self.close()
                raise SMTPResponseException(500, "Line too long.")
            resp.append(line[4:].strip(b' \t\r\n'))
            code = line[:3]
            # Check that the error code is syntactically correct.
            # Don't attempt to read a continuation line if it is broken.
            try:
                errcode = int(code)
            except ValueError:
                errcode = -1
                break
            # Check if multiline response.
            if line[3:4] != b"-":
                break

        errmsg = b"\n".join(resp)
        if self.debuglevel > 0:
            self._print_debug('reply: retcode (%s); Msg: %r' %
                              (errcode, errmsg))
        return errcode, errmsg
 def rcpt(self, recip: str, options: tuple = ()):
     """
     Like `smtplib.SMTP.rcpt`, but handle negative SMTP server
     responses directly.
     """
     code, message = super().rcpt(recip=recip, options=options)
     if code >= 500:
         # Address clearly invalid: issue negative result
         raise AddressNotDeliverableError({
             self._host:
             SMTPMessage(command='RCPT TO',
                         code=code,
                         text=message.decode(errors='ignore'))
         })
     elif code >= 400:
         raise SMTPResponseException(code=code, msg=message)
     return code, message
 def connect(self,
             host: str = 'localhost',
             port: int = 0,
             source_address: str = None) -> Tuple[int, str]:
     """
     Like `smtplib.SMTP.connect`, but raise appropriate exceptions on
     connection failure or negative SMTP server response.
     """
     self.__command = 'connect'  # Used for error messages.
     self._host = host  # Workaround: Missing in standard smtplib!
     try:
         code, message = super().connect(host=host,
                                         port=port,
                                         source_address=source_address)
     except OSError as error:
         raise SMTPServerDisconnected(str(error))
     if code >= 400:
         raise SMTPResponseException(code=code, msg=message)
     return code, message
예제 #14
0
    def test_send(self):
        email_server = EmailServer()
        email_server.server = MagicMock()

        email = MagicMock()
        email.recipients = ['bob', 'betty']
        email.sender = 'ben'
        email.as_string.return_value = 'An email'

        email.should_send.return_value = NoContent("Email was empty")
        response = email_server.send(email)
        self.assertIsInstance(response, NoContent)
        self.assertEqual(response.message, "Email was empty")

        email.should_send.return_value = Failure("Couldn't render email")
        response = email_server.send(email)
        self.assertIsInstance(response, Failure)
        self.assertEqual(response.message, "Couldn't render email")

        email.should_send.return_value = OK("Seems OK to send")
        response = email_server.send(email)
        self.assertIsInstance(response, OK)
        self.assertEqual(response.message, "Sent OK")

        email_server.server.sendmail.assert_called_with(
            'ben', ['bob', 'betty'], 'An email')
        email_server.server.sendmail.reset_mock()

        email_server.server.sendmail.side_effect = SMTPResponseException(
            500, "Fake exception")
        response = email_server.send(email)
        self.assertIsInstance(response, Failure)
        self.assertEqual(response.message, "Problem sending the email")

        email_server.server.sendmail.assert_called_with(
            'ben', ['bob', 'betty'], 'An email')
예제 #15
0
def send_email(prefs, report_str):
    recipients = prefs['ADMIN_EMAIL'].split(',')

    mail_command = prefs["MAIL_COMMAND"]
    if mail_command and recipients:
        err_code = send_mail_by_command(mail_command, recipients, report_str,
                                        debug)
        if err_code != 0:
            logging.getLogger("util").warn("Command %s returned code %s " %
                                           (" ".join(mail_command), err_code))
        return

    msg = dedent("""
        From: {0}
        To: {1}
        Subject: {2}
        Date: {3}

        """).lstrip().format(prefs.get('SMTP_FROM'), prefs.get('ADMIN_EMAIL'),
                             prefs.get('SMTP_SUBJECT'),
                             time.strftime(prefs.get('SMTP_DATE_FORMAT')))

    msg += report_str
    try:
        if is_true(prefs.get('SMTP_SSL')):
            smtp = SMTP_SSL()
        else:
            smtp = SMTP()

        if logging.getLogger().isEnabledFor(logging.DEBUG):
            smtp.set_debuglevel(1)

        smtp.connect(prefs.get('SMTP_HOST'), prefs.get('SMTP_PORT'))

        # If the server supports ESMTP and TLS, then convert the message exchange to TLS via the
        # STARTTLS command.
        if smtp.ehlo()[0] == 250:
            if smtp.has_extn('starttls'):
                (code, resp) = smtp.starttls()
                if code != 220:
                    raise SMTPResponseException(code, resp)
                (code, resp) = smtp.ehlo()
                if code != 250:
                    raise SMTPResponseException(code, resp)
        else:
            # The server does not support esmtp.

            # The Python library SMTP class handles executing HELO/EHLO commands inside
            # login/sendmail methods when neither helo()/ehlo() methods have been
            # previously called.  Because we have already called ehlo() above, we must
            # manually fallback to calling helo() here.

            (code, resp) = smtp.helo()
            if not (200 <= code <= 299):
                raise SMTPHeloError(code, resp)

        username = prefs.get('SMTP_USERNAME')
        password = prefs.get('SMTP_PASSWORD')

        if username and password:
            smtp.login(username, password)

        smtp.sendmail(prefs.get('SMTP_FROM'), recipients, msg)
        debug("sent email to: %s" % prefs.get("ADMIN_EMAIL"))
    except Exception as e:
        print("Error sending email")
        print(e)
        print("Email message follows:")
        print(msg)

    try:
        smtp.quit()
    except Exception:
        pass
예제 #16
0
파일: util.py 프로젝트: zpf5007/denyhosts
def send_email(prefs, report_str):
    recipients = prefs['ADMIN_EMAIL'].split(',')
    msg = dedent("""
    From: {0}
    To: {1}
    Subject: {2}
    Date: {3}

    """).lstrip().format(prefs.get('SMTP_FROM'), prefs.get('ADMIN_EMAIL'),
                         prefs.get('SMTP_SUBJECT'),
                         time.strftime(prefs.get('SMTP_DATE_FORMAT')))

    msg += report_str
    try:
        method = prefs.get('EMAIL_METHOD')
        if is_true(prefs.get('SMTP_SSL')):
            smtp = SMTP_SSL()
        else:
            smtp = SMTP()

        if logging.getLogger().isEnabledFor(logging.DEBUG):
            smtp.set_debuglevel(1)

        smtp.connect(prefs.get('SMTP_HOST'), prefs.get('SMTP_PORT'))

        # If the server supports ESMTP and TLS, then convert the message exchange to TLS via the
        # STARTTLS command.
        if smtp.ehlo()[0] == 250:
            if smtp.has_extn('starttls'):
                (code, resp) = smtp.starttls()
                if code != 220:
                    raise SMTPResponseException(code, resp)
                (code, resp) = smtp.ehlo()
                if code != 250:
                    raise SMTPResponseException(code, resp)
            else:
                # The server does not support esmtp.

                # The Python library SMTP class handles executing HELO/EHLO commands inside
                # login/sendmail methods when neither helo()/ehlo() methods have been
                # previously called.  Because we have already called ehlo() above, we must
                # manually fallback to calling helo() here.

                (code, resp) = smtp.helo()
                if not (200 <= code <= 299):
                    raise SMTPHeloError(code, resp)

            username = prefs.get('SMTP_USERNAME')
            password = prefs.get('SMTP_PASSWORD')

            if username and password:
                smtp.login(username, password)

            smtp.sendmail(prefs.get('SMTP_FROM'), recipients, msg)
            debug("sent email to: %s" % prefs.get("ADMIN_EMAIL"))
        elif method == 'SENDMAIL':
            msg = MIMEText(report_str)
            msg["From"] = prefs.get("SMTP_FROM")
            msg["To"] = prefs.get("ADMIN_EMAIL")
            msg["Subject"] = prefs.get("SMTP_SUBJECT")
            p = Popen(["/usr/sbin/sendmail", "-t", "-oi"], stdin=PIPE)
            p.communicate(msg.as_string())
        elif method == 'MAIL':
            p = Popen(['mail', '-s', prefs.get("SMTP_SUBJECT")] + recipients,
                      stdin=PIPE)
            p.communicate(report_str)
        elif method == 'STDOUT':
            print(report_str)
        else:
            raise Exception("Unknown e-mail method: %s" % method)
    except Exception as e:
        print("Error sending email")
        print(e)
        print("Email message follows:")
        print(report_str)

    try:
        smtp.quit()
    except Exception:
        pass
예제 #17
0
 def fail(a, b):
     raise SMTPResponseException(400, 'Auth denied')