Exemplo n.º 1
0
def sendmail(smtphost, port, from_addr, to_addrs, msg):
    msg = StringIO(str(msg))
    d = defer.Deferred()
    factory = smtp.SMTPSenderFactory(from_addr, to_addrs, msg, d)
    factory.noisy = False
    reactor.connectTCP(smtphost, port, factory)
    return d
Exemplo n.º 2
0
 def testSMTPClient(self):
     onDone = defer.Deferred()
     clientFactory = smtp.SMTPSenderFactory('source@address',
                                            'recipient@address',
                                            StringIO("Message body"),
                                            onDone,
                                            retries=0,
                                            timeout=0.5)
     return self._timeoutTest(onDone, clientFactory)
Exemplo n.º 3
0
 def test_SMTPClient(self):
     """
     Test timeout for L{smtp.SMTPSenderFactory}: the response L{Deferred}
     should be errback with a L{smtp.SMTPTimeoutError}.
     """
     onDone = defer.Deferred()
     clientFactory = smtp.SMTPSenderFactory(
         'source@address', 'recipient@address',
         StringIO("Message body"), onDone,
         retries=0, timeout=0.5)
     return self._timeoutTest(onDone, clientFactory)
Exemplo n.º 4
0
    def test_retryAfterDisconnect(self):
        """
        If the protocol created by L{SMTPSenderFactory} loses its connection
        before receiving confirmation of message delivery, it reconnects and
        tries to deliver the message again.
        """
        recipient = 'alice'
        message = "some message text"
        domain = DummyDomain([recipient])

        class CleanSMTP(smtp.SMTP):
            """
            An SMTP subclass which ensures that its transport will be
            disconnected before the test ends.
            """
            def makeConnection(innerSelf, transport):
                self.addCleanup(transport.loseConnection)
                smtp.SMTP.makeConnection(innerSelf, transport)

        # Create a server which will fail the first message deliver attempt to
        # it with a 500 and a disconnect, but which will accept a message
        # delivered over the 2nd connection to it.
        serverFactory = MultipleDeliveryFactorySMTPServerFactory([
                BrokenMessage,
                lambda user: DummyMessage(domain, user)])
        serverFactory.protocol = CleanSMTP
        serverPort = reactor.listenTCP(0, serverFactory, interface='127.0.0.1')
        serverHost = serverPort.getHost()
        self.addCleanup(serverPort.stopListening)

        # Set up a client to try to deliver a message to the above created
        # server.
        sentDeferred = defer.Deferred()
        clientFactory = smtp.SMTPSenderFactory(
            "*****@*****.**", recipient + "@example.com",
            StringIO(message), sentDeferred)
        clientFactory.domain = "example.org"
        clientConnector = reactor.connectTCP(
            serverHost.host, serverHost.port, clientFactory)
        self.addCleanup(clientConnector.disconnect)

        def cbSent(ignored):
            """
            Verify that the message was successfully delivered and flush the
            error which caused the first attempt to fail.
            """
            self.assertEquals(
                domain.messages,
                {recipient: ["\n%s\n" % (message,)]})
            # Flush the RuntimeError that BrokenMessage caused to be logged.
            self.assertEqual(len(self.flushLoggedErrors(RuntimeError)), 1)
        sentDeferred.addCallback(cbSent)
        return sentDeferred
    def test_onlyLogFailedAddresses(self):
        """
        L{smtp.SenderMixin.sentMail} adds only the addresses with failing
        SMTP response codes to the log passed to the factory's errback.
        """
        onDone = self.assertFailure(defer.Deferred(), smtp.SMTPDeliveryError)
        onDone.addCallback(lambda e: self.assertEquals(
                e.log, "[email protected]: 199 Error in sending.\n"))

        clientFactory = smtp.SMTPSenderFactory(
            'source@address', 'recipient@address',
            StringIO("Message body"), onDone,
            retries=0, timeout=0.5)

        client = clientFactory.buildProtocol(
            address.IPv4Address('TCP', 'example.net', 25))

        addresses = [("*****@*****.**", 200, "No errors here!"),
                     ("*****@*****.**", 199, "Error in sending.")]
        client.sentMail(199, "Test response", 1, addresses, client.log)

        return onDone
Exemplo n.º 6
0
    def send(self, response, retries=0, timeout=30, reaktor=reactor):
        """Send our **response** in reply to :data:`incoming`.

        :type client: :api:`twisted.mail.smtp.Address`
        :param client: The email address of the client.
        :param response: A :class:`EmailResponse`.
        :param int retries: Try resending this many times. (default: ``0``)
        :param int timeout: Timeout after this many seconds. (default: ``30``)
        :rtype: :api:`Deferred <twisted.internet.defer.Deferred>`
        :returns: Our :data:`deferred`.
        """
        logging.info("Sending reply to %s ..." % str(response.to))

        factory = smtp.SMTPSenderFactory(self.incoming.context.smtpFromAddr,
                                         str(response.to),
                                         response,
                                         self.deferred,
                                         retries=retries,
                                         timeout=timeout)
        factory.domain = smtp.DNSNAME
        reaktor.connectTCP(self.incoming.context.smtpServerIP,
                           self.incoming.context.smtpServerPort, factory)
        return self.deferred
Exemplo n.º 7
0
    def test_resetTimeoutWhileSending(self):
        """
        The timeout is not allowed to expire after the server has accepted a
        DATA command and the client is actively sending data to it.
        """
        class SlowFile:
            """
            A file-like which returns one byte from each read call until the
            specified number of bytes have been returned.
            """
            def __init__(self, size):
                self._size = size

            def read(self, max=None):
                if self._size:
                    self._size -= 1
                    return 'x'
                return ''

        failed = []
        onDone = defer.Deferred()
        onDone.addErrback(failed.append)
        clientFactory = smtp.SMTPSenderFactory(
            'source@address', 'recipient@address',
            SlowFile(1), onDone, retries=0, timeout=3)
        clientFactory.domain = "example.org"
        clock = task.Clock()
        client = clientFactory.buildProtocol(
            address.IPv4Address('TCP', 'example.net', 25))
        client.callLater = clock.callLater
        transport = StringTransport()
        client.makeConnection(transport)

        client.dataReceived(
            "220 Ok\r\n" # Greet the client
            "250 Ok\r\n" # Respond to HELO
            "250 Ok\r\n" # Respond to MAIL FROM
            "250 Ok\r\n" # Respond to RCPT TO
            "354 Ok\r\n" # Respond to DATA
            )

        # Now the client is producing data to the server.  Any time
        # resumeProducing is called on the producer, the timeout should be
        # extended.  First, a sanity check.  This test is only written to
        # handle pull producers.
        self.assertNotIdentical(transport.producer, None)
        self.assertFalse(transport.streaming)

        # Now, allow 2 seconds (1 less than the timeout of 3 seconds) to
        # elapse.
        clock.advance(2)

        # The timeout has not expired, so the failure should not have happened.
        self.assertEqual(failed, [])

        # Let some bytes be produced, extending the timeout.  Then advance the
        # clock some more and verify that the timeout still hasn't happened.
        transport.producer.resumeProducing()
        clock.advance(2)
        self.assertEqual(failed, [])

        # The file has been completely produced - the next resume producing
        # finishes the upload, successfully.
        transport.producer.resumeProducing()
        client.dataReceived("250 Ok\r\n")
        self.assertEqual(failed, [])

        # Verify that the client actually did send the things expected.
        self.assertEqual(
            transport.value(),
            "HELO example.org\r\n"
            "MAIL FROM:<source@address>\r\n"
            "RCPT TO:<recipient@address>\r\n"
            "DATA\r\n"
            "x\r\n"
            ".\r\n"
            # This RSET is just an implementation detail.  It's nice, but this
            # test doesn't really care about it.
            "RSET\r\n")