示例#1
0
    def mail_send(self, message, extra_to=list(), extra_cc=list(), attach=list()):
        """
        send message to mail server

        :param message: TEXT message to be send
        :param extra_to: Extra user to be send, param is a list
        :param extra_cc: Extra user to be copy, param is a list
        :param attach: Attachment file to be send, param is a list
        :return: None
        """

        if not isinstance(message, email.message.Message):
            logger.debug("parameter of message is not a valid email context.")
            raise smtplib.SMTPDataError(
                0, "parameter of message is not a valid email context.")

        if extra_to is not None and len(extra_to) > 0:
            extra_to = [v.strip(' ') for v in extra_to]
            self.user_to += extra_to

        if extra_cc is not None and len(extra_cc) > 0:
            extra_cc = [v.strip(' ') for v in extra_cc]
            self.user_cc += extra_cc

        if self.smtp_address == "" or len(self.user_to) == 0:
            raise smtplib.SMTPDataError(
                1, "sender address or destination address is invalid.")

        self._connect()

        try:
            msg = email.mime.multipart.MIMEMultipart()
            msg['Subject'] = message['Subject']
            msg['From'] = self.smtp_address
            msg['To'] = email.utils.COMMASPACE.join(self.user_to)
            msg['Cc'] = email.utils.COMMASPACE.join(self.user_cc)
            users = self.user_to + self.user_cc
            msg.attach(message)

            for attachment in attach:
                mtype = attachment.get('type', "txt")
                mcmd = attachment.get('title', "cmd")
                attachment.add_header('Content-Disposition', 'attachment',
                                      filename=mcmd + '.' + mtype)
                msg.attach(attachment)

            self.smtp_obj.sendmail(self.smtp_address, users, msg.as_string())
        finally:
            self._disconnec()
示例#2
0
 def sendmail(self, from_address, to_addresses, message):
     if self.reject_mail_to in from_address:
         raise smtplib.SMTPSenderRefused(
             -1, 'Failed successfuly', from_address)
     rejected_recipients = dict([
         (addr, 'Fail') for addr in to_addresses
         if self.reject_mail_to in addr])
     if rejected_recipients:
         if len(rejected_recipients) == to_addresses:
             raise smtplib.SMTPRecipientsRefused(rejected_recipients)
         else:
             return rejected_recipients
     if self.host == 'reject_malformed':
         raise smtplib.SMTPDataError(-1, 'I pretend that this is bad data')
示例#3
0
    def sendmail(self,
                 from_addr,
                 to_addrs,
                 msg,
                 mail_options=[],
                 rcpt_options=[]):

        yield self.ehlo_or_helo_if_needed()
        esmtp_opts = []
        if isinstance(msg, str):
            msg = smtplib._fix_eols(msg).encode('ascii')
        if self.does_esmtp:

            if self.has_extn('size'):
                esmtp_opts.append("size=%d" % len(msg))
            for option in mail_options:
                esmtp_opts.append(option)

        (code, resp) = yield self.mail(from_addr, esmtp_opts)
        if code != 250:
            if code == 421:
                self.close()
            else:
                yield self._rset()
            raise smtplib.SMTPSenderRefused(code, resp, from_addr)
        senderrs = {}
        if isinstance(to_addrs, str):
            to_addrs = [to_addrs]
        for each in to_addrs:
            (code, resp) = yield self.rcpt(each, rcpt_options)
            if (code != 250) and (code != 251):
                senderrs[each] = (code, resp)
            if code == 421:
                self.close()
                raise smtplib.SMTPRecipientsRefused(senderrs)
        if len(senderrs) == len(to_addrs):
            # the server refused all our recipients
            yield self._rset()
            raise smtplib.SMTPRecipientsRefused(senderrs)
        (code, resp) = yield self.data(msg)
        if code != 250:
            if code == 421:
                self.close()
            else:
                yield self._rset()
            raise smtplib.SMTPDataError(code, resp)
        #if we got here then somebody got our mail
        return senderrs
示例#4
0
 def test_fallimento_data(self, mock_smtp):
     """
     In caso di fallimento durante il comando data  il messaggio viene rimesso in coda,
     tranne che in caso di errore 5XX che è permanente
     """
     codici = (451, 554, 500, 501, 503, 421, 552, 451, 452)
     for codice in codici:
         msg = 'code {}'.format(codice)
         instance = mock_smtp.return_value
         instance.sendmail.side_effect = smtplib.SMTPDataError(code=codice,
                                                               msg=msg)
         self._invia_msg_singolo()
         if codice == 501:
             self.assertEqual(Messaggio.in_coda().count(), 0)
         else:
             self.assertEqual(Messaggio.in_coda().count(), 1)
         self._reset_coda()
示例#5
0
    def data(self, msg):
        """SMTP 'DATA' command -- sends message data to server. """

        (code, repl) = yield self.docmd(b"data")

        if code != 354:
            raise smtplib.SMTPDataError(code, repl)
        else:
            if isinstance(msg, str):
                msg = _fix_eols(msg)
            q = _quote_periods(msg)
            if q[-2:] != CRLF:
                q = q + CRLF
            q = q + b"." + CRLF
            #self.send(q)
            yield self.send(q)
            (code, msg) = yield self.getreply()
            raise gen.Return((code, msg))
示例#6
0
    def data(self, msg):
        """
        SMTP 'DATA' command -- sends message data to server.

        Automatically quotes lines beginning with a period per rfc821.
        Raises SMTPDataError if there is an unexpected reply to the
        DATA command; the return value from this method is the final
        response code received when the all data is sent.

        msg:      Message in a string buffer or a filename referring to
                  a file containin the data to be send (string).

        Returns:  Tuple with the status code + a message from the SMTP
                  host (tuple/integer, string).
        """
        self.putcmd("data")
        (code, repl) = self.getreply()
        if self.debuglevel > 0:
            print("data:", (code, repl))
        if code != 354:
            raise smtplib.SMTPDataError(code, repl)
        else:
            if (not self.__msgInFile):
                # Data contained in the message in memory.
                q = smtplib.quotedata(msg)
                if q[-2:] != smtplib.CRLF: q = q + smtplib.CRLF
                q = q + "." + smtplib.CRLF
                self.send(q)
            else:
                # Data to send is contained in a file.
                fo = open(msg)
                while (1):
                    buf = fo.read(16384)
                    if (buf == ""): break
                    qBuf = smtplib.quotedata(buf)
                    self.send(buf)
                fo.close()
                self.send(smtplib.CRLF + "." + smtplib.CRLF)

            (code, msg) = self.getreply()
            if (self.debuglevel > 0):
                print("data:", (code, msg))
            return (code, msg)
示例#7
0
 async def send(to_addrs, subject, mail_msg, attachs=None):
     if isinstance(to_addrs, str):
         to_addrs = [to_addrs]
     logging.debug(('邮件收件人:', to_addrs))
     message = await EmailSender._make_email(to_addrs, subject, mail_msg,
                                             attachs)
     # with open('send_email.eml', 'wb') as fd:
     #     logging.debug('邮件已经保存到本地文件')
     #     fd.write(message.as_bytes())
     #     return
     # noinspection PyBroadException
     try:
         await EmailSender._send_direct(message, to_addrs)
     except Exception:
         logging.error(f'邮件直接投递失败')
         try:
             await EmailSender._send_proxy(message, to_addrs)
         except Exception as err:
             logging.error(f'邮件中转投递失败')
             logging.exception(err)
             raise smtplib.SMTPDataError(-1, b'Unknown Error')
示例#8
0
 async def _send_proxy(message, to_addrs):
     if not EmailSender.servers:
         logging.error(f'可用邮件发送服务器为空')
         raise Exception(b'Email server is empty.')
     for server in EmailSender.servers:
         try:
             logging.debug('使用中转邮件服务器:' + server['host'])
             with SmtpProxyServer(server['host'], 25, server['user'],
                                  server['pass']) as smtp_server:
                 send_errs = smtp_server.sendmail(EmailSender.sender,
                                                  to_addrs,
                                                  message.as_string())
                 if not send_errs:
                     logging.debug('中转邮件发送成功')
                     return
                 else:
                     logging.error('中转邮件发送失败')
                     logging.error(send_errs)
         except Exception as e:
             logging.fatal('中转邮件发送异常')
             logging.exception(e)
     raise smtplib.SMTPDataError(-1, b'Unknown Error')
示例#9
0
 def send_email(self, msg):
     smtp = smtplib.SMTP(host=CONF.get("email", "host"),
                         port=CONF.get("email", "port"))
     smtp.ehlo()
     try:
         code, err = smtp.mail(CONF.get("email", "sender"))
         if code != 250:
             raise smtplib.SMTPSenderRefused(code, err,
                                             CONF.get("email", "sender"))
         rcpterrs = {}
         for rcpt in CONF.get("email", "recipients").split(","):
             code, err = smtp.rcpt(rcpt)
             if code not in (250, 251):
                 rcpterrs[rcpt] = (code, err)
         if rcpterrs:
             raise smtplib.SMTPRecipientsRefused(rcpterrs)
         code, err = smtp.data(msg.as_string())
         if code != 250:
             raise smtplib.SMTPDataError(code, err)
     finally:
         try:
             smtp.quit()
         except smtplib.SMTPServerDisconnected:
             pass
示例#10
0
def sendmail(server, from_addr, to_addrs, msg):
    server.ehlo_or_helo_if_needed()
    esmtp_opts = []
    if server.does_esmtp and server.has_extn('size'):
        esmtp_opts.append("size=%d" % len(msg))
    (code, resp) = server.mail(from_addr, esmtp_opts)
    if code != 250:
        server.rset()
        raise smtplib.SMTPSenderRefused(code, resp, from_addr)
    senderrs = {}
    if isinstance(to_addrs, basestring):
        to_addrs = [to_addrs]
    for each in to_addrs:
        (code, resp) = server.rcpt(each)
        if (code != 250) and (code != 251):
            senderrs[each] = (code, resp)
    if len(senderrs) == len(to_addrs):
        server.rset()
        raise smtplib.SMTPRecipientsRefused(senderrs)
    (code, resp) = server.data(msg)
    if code != 250:
        server.rset()
        raise smtplib.SMTPDataError(code, resp)
    return resp
示例#11
0
def test_email_plugin(mock_smtp, mock_smtpssl):
    """
    API: NotifyEmail Plugin()

    """
    # Disable Throttling to speed testing
    plugins.NotifyBase.NotifyBase.request_rate_per_sec = 0

    # iterate over our dictionary and test it out
    for (url, meta) in TEST_URLS:

        # Our expected instance
        instance = meta.get('instance', None)

        # Our expected server objects
        self = meta.get('self', None)

        # Our expected Query response (True, False, or exception type)
        response = meta.get('response', True)

        test_smtplib_exceptions = meta.get('test_smtplib_exceptions', False)

        # Our mock of our socket action
        mock_socket = mock.Mock()
        mock_socket.starttls.return_value = True
        mock_socket.login.return_value = True

        # Create a mock SMTP Object
        mock_smtp.return_value = mock_socket
        mock_smtpssl.return_value = mock_socket

        if test_smtplib_exceptions:
            # Handle exception testing; first we turn the boolean flag ito
            # a list of exceptions
            test_smtplib_exceptions = (
                smtplib.SMTPHeloError(0,
                                      'smtplib.SMTPHeloError() not handled'),
                smtplib.SMTPException(0,
                                      'smtplib.SMTPException() not handled'),
                RuntimeError(0, 'smtplib.HTTPError() not handled'),
                smtplib.SMTPRecipientsRefused(
                    'smtplib.SMTPRecipientsRefused() not handled'),
                smtplib.SMTPSenderRefused(
                    0, 'smtplib.SMTPSenderRefused() not handled',
                    '*****@*****.**'),
                smtplib.SMTPDataError(0,
                                      'smtplib.SMTPDataError() not handled'),
                smtplib.SMTPServerDisconnected(
                    'smtplib.SMTPServerDisconnected() not handled'),
            )

        try:
            obj = Apprise.instantiate(url, suppress_exceptions=False)

            if obj is None:
                # We're done (assuming this is what we were expecting)
                assert instance is None
                continue

            if instance is None:
                # Expected None but didn't get it
                print('%s instantiated %s (but expected None)' %
                      (url, str(obj)))
                assert (False)

            assert (isinstance(obj, instance))

            if isinstance(obj, plugins.NotifyBase.NotifyBase):
                # We loaded okay; now lets make sure we can reverse this url
                assert (isinstance(obj.url(), six.string_types) is True)

                # Instantiate the exact same object again using the URL from
                # the one that was already created properly
                obj_cmp = Apprise.instantiate(obj.url())

                # Our object should be the same instance as what we had
                # originally expected above.
                if not isinstance(obj_cmp, plugins.NotifyBase.NotifyBase):
                    # Assert messages are hard to trace back with the way
                    # these tests work. Just printing before throwing our
                    # assertion failure makes things easier to debug later on
                    print('TEST FAIL: {} regenerated as {}'.format(
                        url, obj.url()))
                    assert (False)

            if self:
                # Iterate over our expected entries inside of our object
                for key, val in self.items():
                    # Test that our object has the desired key
                    assert (hasattr(key, obj))
                    assert (getattr(key, obj) == val)

            try:
                if test_smtplib_exceptions is False:
                    # check that we're as expected
                    assert obj.notify(title='test',
                                      body='body',
                                      notify_type=NotifyType.INFO) == response

                else:
                    for exception in test_smtplib_exceptions:
                        mock_socket.sendmail.side_effect = exception
                        try:
                            assert obj.notify(
                                title='test',
                                body='body',
                                notify_type=NotifyType.INFO) is False

                        except AssertionError:
                            # Don't mess with these entries
                            raise

                        except Exception:
                            # We can't handle this exception type
                            raise

            except AssertionError:
                # Don't mess with these entries
                print('%s AssertionError' % url)
                raise

            except Exception as e:
                # Check that we were expecting this exception to happen
                if not isinstance(e, response):
                    raise

        except AssertionError:
            # Don't mess with these entries
            print('%s AssertionError' % url)
            raise

        except Exception as e:
            # Handle our exception
            if (instance is None):
                raise

            if not isinstance(e, instance):
                raise
示例#12
0
    def __sendmail(self,
                   from_addr,
                   to_addrs,
                   msg,
                   mail_options=[],
                   rcpt_options=[]):
        """This command performs an entire mail transaction.

        The arguments are:
            - from_addr    : The address sending this mail.
            - to_addrs     : A list of addresses to send this mail to.  A bare
                             string will be treated as a list with 1 address.
            - msg          : The message to send.
            - mail_options : List of ESMTP options (such as 8bitmime) for the
                             mail command.
            - rcpt_options : List of ESMTP options (such as DSN commands) for
                             all the rcpt commands.

        If there has been no previous EHLO or HELO command this session, this
        method tries ESMTP EHLO first.  If the server does ESMTP, message size
        and each of the specified options will be passed to it.  If EHLO
        fails, HELO will be tried and ESMTP options suppressed.

        This method will return normally if the mail is accepted for at least
        one recipient.  It returns a dictionary, with one entry for each
        recipient that was refused.  Each entry contains a tuple of the SMTP
        error code and the accompanying error message sent by the server.

        This method may raise the following exceptions:

         SMTPHeloError          The server didn't reply properly to
                                the helo greeting.
         SMTPRecipientsRefused  The server rejected ALL recipients
                                (no mail was sent).
         SMTPSenderRefused      The server didn't accept the from_addr.
         SMTPDataError          The server replied with an unexpected
                                error code (other than a refusal of
                                a recipient).

        Note: the connection will be open even after an exception is raised.

        Example:

         >>> import smtplib
         >>> s=smtplib.SMTP("localhost")
         >>> tolist=["*****@*****.**","*****@*****.**","*****@*****.**","*****@*****.**"]
         >>> msg = '''From: [email protected]
         ... Subject: testin'...
         ...
         ... This is a test '''
         >>> s.sendmail("*****@*****.**",tolist,msg)
         { "*****@*****.**" : ( 550 ,"User unknown" ) }
         >>> s.quit()

        In the above example, the message was accepted for delivery to three
        of the four addresses, and one was rejected, with the error code
        550.  If all addresses are accepted, then the method will return an
        empty dictionary.

        """
        self.ehlo_or_helo_if_needed()
        esmtp_opts = []
        if self.does_esmtp:
            # Hmmm? what's this? -ddm
            # self.esmtp_features['7bit']=""
            if self.has_extn('size'):
                esmtp_opts.append("size=%d" % len(msg))
            for option in mail_options:
                esmtp_opts.append(option)

        (code, resp) = self.mail(from_addr, esmtp_opts)
        if code != 250:
            self.rset()
            raise smtplib.SMTPSenderRefused(code, resp, from_addr)
        senderrs = {}
        if isinstance(to_addrs, basestring):
            to_addrs = [to_addrs]
        for each in to_addrs:
            (code, resp) = self.rcpt(each, rcpt_options)
            if (code != 250) and (code != 251):
                senderrs[each] = (code, resp)
        if len(senderrs) == len(to_addrs):
            # the server refused all our recipients
            self.rset()
            raise smtplib.SMTPRecipientsRefused(senderrs)
        (code, resp) = self.data(msg)
        if code != 250:
            self.rset()
            raise smtplib.SMTPDataError(code, resp)
        #if we got here then somebody got our mail
        return senderrs
示例#13
0
def test_email_plugin(mock_smtp, mock_smtpssl):
    """
    API: NotifyEmail Plugin()

    """

    # iterate over our dictionary and test it out
    for (url, meta) in TEST_URLS:

        # Our expected instance
        instance = meta.get('instance', None)

        # Our expected exception
        exception = meta.get('exception', None)

        # Our expected server objects
        self = meta.get('self', None)

        # Our expected Query response (True, False, or exception type)
        response = meta.get('response', True)

        test_smtplib_exceptions = meta.get('test_smtplib_exceptions', False)

        # Our mock of our socket action
        mock_socket = mock.Mock()
        mock_socket.starttls.return_value = True
        mock_socket.login.return_value = True

        # Create a mock SMTP Object
        mock_smtp.return_value = mock_socket
        mock_smtpssl.return_value = mock_socket

        if test_smtplib_exceptions:
            # Handle exception testing; first we turn the boolean flag ito
            # a list of exceptions
            test_smtplib_exceptions = (
                smtplib.SMTPHeloError(0,
                                      'smtplib.SMTPHeloError() not handled'),
                smtplib.SMTPException(0,
                                      'smtplib.SMTPException() not handled'),
                RuntimeError(0, 'smtplib.HTTPError() not handled'),
                smtplib.SMTPRecipientsRefused(
                    'smtplib.SMTPRecipientsRefused() not handled'),
                smtplib.SMTPSenderRefused(
                    0, 'smtplib.SMTPSenderRefused() not handled',
                    '*****@*****.**'),
                smtplib.SMTPDataError(0,
                                      'smtplib.SMTPDataError() not handled'),
                smtplib.SMTPServerDisconnected(
                    'smtplib.SMTPServerDisconnected() not handled'),
            )

        try:
            obj = Apprise.instantiate(url, suppress_exceptions=False)

            assert (exception is None)

            if obj is None:
                # We're done
                continue

            if instance is None:
                # Expected None but didn't get it
                print('%s instantiated %s' % (url, str(obj)))
                assert (False)

            assert (isinstance(obj, instance))

            if self:
                # Iterate over our expected entries inside of our object
                for key, val in self.items():
                    # Test that our object has the desired key
                    assert (hasattr(key, obj))
                    assert (getattr(key, obj) == val)

            try:
                if test_smtplib_exceptions is False:
                    # check that we're as expected
                    assert obj.notify(title='test',
                                      body='body',
                                      notify_type=NotifyType.INFO) == response

                else:
                    for exception in test_smtplib_exceptions:
                        mock_socket.sendmail.side_effect = exception
                        try:
                            assert obj.notify(
                                title='test',
                                body='body',
                                notify_type=NotifyType.INFO) is False

                        except AssertionError:
                            # Don't mess with these entries
                            raise

                        except Exception as e:
                            # We can't handle this exception type
                            print('%s / %s' % (url, str(e)))
                            assert False

            except AssertionError:
                # Don't mess with these entries
                raise

            except Exception as e:
                # Check that we were expecting this exception to happen
                assert isinstance(e, response)

        except AssertionError:
            # Don't mess with these entries
            print('%s AssertionError' % url)
            raise

        except Exception as e:
            # Handle our exception
            print('%s / %s' % (url, str(e)))
            assert (exception is not None)
            assert (isinstance(e, exception))
示例#14
0
    def sendmail(self, from_addr, to_addrs, msg, mail_options=None, rcpt_options=None):

        if not to_addrs:
            return None

        rcpt_options = rcpt_options or []
        mail_options = mail_options or []
        esmtp_opts = []
        if self.does_esmtp:
            if self.has_extn('size'):
                esmtp_opts.append("size=%d" % len(msg))
            for option in mail_options:
                esmtp_opts.append(option)

        response = self.make_response()

        from_addr = sanitize_email(from_addr)

        response.from_addr = from_addr
        response.esmtp_opts = esmtp_opts[:]

        (code, resp) = self.mail(from_addr, esmtp_opts)
        response.set_status('mail', code, resp)

        if code != 250:
            self._rset()
            exc = smtplib.SMTPSenderRefused(code, resp, from_addr)
            response.set_exception(exc)
            return response

        if not isinstance(to_addrs, (list, tuple)):
            to_addrs = [to_addrs]

        to_addrs = [sanitize_email(e) for e in to_addrs]

        response.to_addrs = to_addrs
        response.rcpt_options = rcpt_options[:]
        response.refused_recipients = {}

        for a in to_addrs:
            (code, resp) = self.rcpt(a, rcpt_options)
            response.set_status('rcpt', code, resp, recipient=a)
            if (code != 250) and (code != 251):
                response.refused_recipients[a] = (code, resp)

        if len(response.refused_recipients) == len(to_addrs):
            # the server refused all our recipients
            self._rset()
            exc = smtplib.SMTPRecipientsRefused(response.refused_recipients)
            response.set_exception(exc)
            return response

        (code, resp) = self.data(msg)
        response.set_status('data', code, resp)
        if code != 250:
            self._rset()
            exc = smtplib.SMTPDataError(code, resp)
            response.set_exception(exc)
            return response

        response._finished = True
        return response