示例#1
0
    def raise_error(self, status, stdout, stderr):
        """This method may be over-ridden by sub-classes if you need to control
        how the relay error is generated. By default, the error raised is a
        :class:`~slimta.relay.TransientRelayError` unless the process output
        begins with a ``5.X.X`` enhanced status code. This behavior attempts to
        mimic the postfix pipe_ daemon.

        This method is only called if the subprocess returns a non-zero exit
        status.

        :param status: The non-zero exit status of the subprocess.
        :param stdout: The subprocess's standard output, as received by
                       :py:meth:`~subprocess.Popen.communicate`.
        :type stdout: string
        :param stderr: The subprocess's standard error output, as received by
                       :py:meth:`~subprocess.Popen.communicate`.
        :type stderr: string
        :raises: :class:`~slimta.relay.TransientRelayError`,
                 :class:`~slimta.relay.PermanentRelayError`

        """
        error_msg = stdout.rstrip() or stderr.rstrip() or 'Delivery failed'
        if self._permanent_error_pattern.match(error_msg):
            reply = Reply('550', error_msg)
            raise PermanentRelayError(error_msg, reply)
        else:
            reply = Reply('450', error_msg)
            raise TransientRelayError(error_msg, reply)
示例#2
0
    def test_enqueue_wait_partial_relay(self):
        env = Envelope(
            '*****@*****.**',
            ['*****@*****.**', '*****@*****.**', '*****@*****.**'])
        self.store.write(env, IsA(float)).AndReturn('1234')
        self.relay._attempt(env, 0).AndReturn({
            '*****@*****.**':
            None,
            '*****@*****.**':
            TransientRelayError('transient', Reply('450', 'transient')),
            '*****@*****.**':
            PermanentRelayError('permanent', Reply('550', 'permanent'))
        })
        self.store.increment_attempts('1234')
        self.store.set_timestamp('1234', IsA(float))
        self.store.set_recipients_delivered('1234', set([0, 2]))
        self.mox.ReplayAll()

        def backoff(envelope, attempts):
            return 0

        def no_bounce(envelope, reply):
            return None

        queue = Queue(self.store,
                      self.relay,
                      backoff=backoff,
                      bounce_factory=no_bounce,
                      relay_pool=5)
        queue.enqueue(env)
        queue.relay_pool.join()
示例#3
0
 def raise_error(self, status, stdout, stderr):
     error_msg = stdout.rstrip() or stderr.rstrip() or 'LDA delivery failed'
     if status == self.EX_TEMPFAIL:
         reply = Reply('450', error_msg)
         raise TransientRelayError(error_msg, reply)
     else:
         reply = Reply('550', error_msg)
         raise PermanentRelayError(error_msg, reply)
 def test_enqueue_wait_partial_relay_expired(self):
     env = Envelope('*****@*****.**', ['*****@*****.**',
                                           '*****@*****.**',
                                           '*****@*****.**'])
     bounce_mock = self.mox.CreateMockAnything()
     bounce_mock(IsA(Envelope), IsA(Reply)).AndReturn(None)
     bounce_mock(IsA(Envelope), IsA(Reply)).AndReturn(None)
     self.store.write(env, IsA(float)).AndReturn('1234')
     self.relay._attempt(env, 0).AndReturn([TransientRelayError('transient', Reply('450', 'transient 1')),
                                            TransientRelayError('transient', Reply('450', 'transient 1')),
                                            TransientRelayError('transient', Reply('450', 'transient 2'))])
     self.store.increment_attempts('1234')
     self.store.remove('1234')
     self.mox.ReplayAll()
     queue = Queue(self.store, self.relay, bounce_factory=bounce_mock, relay_pool=5)
     queue.enqueue(env)
     queue.relay_pool.join()
示例#5
0
 def _try_pipe(self, envelope):
     try:
         status, stdout, stderr = self._exec_process(envelope)
     except Timeout:
         msg = 'Delivery timed out'
         reply = Reply('450', msg)
         raise TransientRelayError(msg, reply)
     if status != 0:
         self.raise_error(status, stdout, stderr)
 def test_enqueue_wait_transientfail_noretry(self):
     self.store.write(self.env, IsA(float)).AndReturn('1234')
     self.relay._attempt(self.env, 0).AndRaise(TransientRelayError('transient', Reply('450', 'transient')))
     self.store.increment_attempts('1234')
     self.store.remove('1234')
     self.mox.ReplayAll()
     def no_bounce(envelope, reply):
         return None
     queue = Queue(self.store, self.relay, bounce_factory=no_bounce, relay_pool=5)
     queue.enqueue(self.env)
     queue.relay_pool.join()
 def test_enqueue_wait_transientfail(self):
     self.store.write(self.env, IsA(float)).AndReturn('1234')
     self.relay._attempt(self.env, 0).AndRaise(TransientRelayError('transient', Reply('450', 'transient')))
     self.store.increment_attempts('1234')
     self.store.set_timestamp('1234', IsA(float))
     self.mox.ReplayAll()
     def backoff(envelope, attempts):
         return 0
     queue = Queue(self.store, self.relay, backoff=backoff, relay_pool=5)
     queue.enqueue(self.env)
     queue.relay_pool.join()
示例#8
0
 def raise_error(self, status, stdout, stderr):
     error_msg = 'Delivery failed'
     if stdout.startswith('maildrop: '):
         error_msg = stdout[10:].rstrip()
     elif stderr.startswith('maildrop: '):
         error_msg = stderr[10:].rstrip()
     if status == self.EX_TEMPFAIL:
         reply = Reply('450', error_msg)
         raise TransientRelayError(error_msg, reply)
     else:
         reply = Reply('550', error_msg)
         raise PermanentRelayError(error_msg, reply)
示例#9
0
 def _try_pipe_one_rcpt(self, envelope):
     header_data, message_data = envelope.flatten()
     stdin = b''.join((header_data, message_data))
     rcpt = envelope.recipients[0]
     try:
         with Timeout(self.timeout):
             args = self._process_args(envelope, rcpt)
             return self._exec_process(args, stdin)
     except Timeout:
         msg = 'Delivery timed out'
         reply = Reply('450', '4.4.2 ' + msg)
         raise TransientRelayError(msg, reply)
示例#10
0
 def _try_pipe_all_rcpts(self, envelope):
     header_data, message_data = envelope.flatten()
     stdin = b''.join((header_data, message_data))
     results = {}
     try:
         with Timeout(self.timeout):
             for rcpt in envelope.recipients:
                 args = self._process_args(envelope, rcpt)
                 results[rcpt] = self._exec_process(args, stdin)
     except Timeout:
         for rcpt in envelope.recipients:
             if rcpt not in results:
                 msg = 'Delivery timed out'
                 reply = Reply('450', '4.4.2 ' + msg)
                 results[rcpt] = TransientRelayError(msg, reply)
     return results
 def test_attempt_delivery_transientrelayerror(self):
     task = self.mox.CreateMockAnything()
     subtask = self.mox.CreateMockAnything()
     result = self.mox.CreateMockAnything()
     result.id = '12345'
     self.relay.attempt(self.env, 0).AndRaise(TransientRelayError('transient', Reply('450', 'transient error')))
     self.celery.task(IgnoreArg()).AndReturn(task)
     task.s(self.env, 1).AndReturn(subtask)
     subtask.set(countdown=60)
     subtask.apply_async().AndReturn(result)
     self.mox.ReplayAll()
     def backoff(envelope, attempts):
         self.assertEqual(self.env, envelope)
         self.assertEqual(1, attempts)
         return 60
     queue = CeleryQueue(self.celery, self.relay, backoff=backoff)
     queue.attempt_delivery(self.env, 0)
 def test_attempt_delivery_transientrelayerror_no_retry(self):
     task = self.mox.CreateMockAnything()
     subtask = self.mox.CreateMockAnything()
     result = self.mox.CreateMockAnything()
     result.id = '12345'
     self.relay.attempt(self.env, 0).AndRaise(TransientRelayError('transient', Reply('450', 'transient error')))
     self.celery.task(IgnoreArg()).AndReturn(task)
     task.s(self.bounce, 0).AndReturn(subtask)
     subtask.apply_async().AndReturn(result)
     self.mox.ReplayAll()
     def return_bounce(envelope, reply):
         self.assertEqual(self.env, envelope)
         return self.bounce
     def no_retry(envelope, attempts):
         self.assertEqual(self.env, envelope)
         self.assertEqual(1, attempts)
         return None
     queue = CeleryQueue(self.celery, self.relay, backoff=no_retry, bounce_factory=return_bounce)
     queue.attempt_delivery(self.env, 0)
 def test_default_replies(self):
     perm = PermanentRelayError('test msg')
     transient = TransientRelayError('test msg')
     self.assertEqual('550 5.0.0 test msg', str(perm.reply))
     self.assertEqual('450 4.0.0 test msg', str(transient.reply))