コード例 #1
0
 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()
コード例 #2
0
 def test_str(self):
     if PY3:
         r = Reply('250', '2.1.0 Ok \U0001f44d')
         self.assertEqual('250 2.1.0 Ok \U0001f44d', str(r))
     else:
         r = Reply('250', u'2.1.0 Ok \U0001f44d')
         self.assertEqual('250 2.1.0 Ok \xf0\x9f\x91\x8d', str(r))
コード例 #3
0
ファイル: sending_domain.py プロジェクト: toxinu/munch-core
    def apply(self, envelope):
        sender_email = parseaddr(envelope.headers.get('From'))[1]

        try:
            validate_email(sender_email)
        except ValidationError:
            sender_email = None

        if not sender_email:
            error = QueueError()
            error.reply = Reply(
                code='554',
                message=(
                    '5.7.1 <{}>: Relay access denied: '
                    'Sending domain invalid').format(envelope.recipients[0]))
            raise error

        organization_domain = SendingDomain.objects.filter(
            organization=envelope.organization)
        domain = organization_domain.get_from_email_addr(
            sender_email, must_raise=False)

        if not domain:
            error = QueueError()
            error.reply = Reply(
                code='554',
                message=(
                    '5.7.1 <{}>: Relay access denied: Sending '
                    'domain for <{}> is not properly configured').format(
                        envelope.recipients[0], sender_email))
            raise error

        envelope.sending_domain = domain
コード例 #4
0
ファイル: pipe.py プロジェクト: rymmx-gls/python-slimta
    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 isinstance(error_msg, bytes):
            error_msg = error_msg.decode('utf-8')
        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)
コード例 #5
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()
コード例 #6
0
 def test_copy(self):
     r1 = Reply('250', '2.1.0 Ok')
     r2 = Reply(command='RCPT')
     r2.copy(r1)
     assert_equal('250', r2.code)
     assert_equal('2.1.0', r2.enhanced_status_code)
     assert_equal('2.1.0 Ok', r2.message)
     assert_equal('RCPT', r2.command)
コード例 #7
0
ファイル: pipe.py プロジェクト: rymmx-gls/python-slimta
 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)
コード例 #8
0
 def test_eq(self):
     r1 = Reply('250', '2.1.0 Ok')
     r2 = Reply('250', '2.1.0 Ok')
     r3 = Reply('251', '2.1.0 Ok')
     r4 = Reply('250', '2.1.1 Ok')
     self.assertEqual(r1, r2)
     self.assertNotEqual(r1, r3)
     self.assertNotEqual(r1, r4)
     self.assertNotEqual(r3, r4)
コード例 #9
0
 def _enqueue_envelope(self, env):
     results = self.handoff(env)
     if isinstance(results[0][1], QueueError):
         reply = Reply('550', '5.6.0 Error queuing message')
         raise _build_http_response(reply)
     elif isinstance(results[0][1], RelayError):
         relay_reply = results[0][1].reply
         raise _build_http_response(relay_reply)
     reply = Reply('250', '2.6.0 Message accepted for delivery')
     raise _build_http_response(reply)
コード例 #10
0
 def test_simple_handshake(self):
     mock = self.mox.CreateMockAnything()
     mock.__call__(IsA(SmtpSession)).AndReturn(mock)
     mock.handle_banner(IsA(Reply), ('127.0.0.1', 0))
     mock.handle_helo(IsA(Reply), 'there')
     self.mox.ReplayAll()
     h = SmtpSession(('127.0.0.1', 0), mock, None)
     h.BANNER_(Reply('220'))
     h.HELO(Reply('250'), 'there')
     self.assertEqual('there', h.ehlo_as)
     self.assertFalse(h.extended_smtp)
コード例 #11
0
ファイル: pipe.py プロジェクト: rymmx-gls/python-slimta
 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)
コード例 #12
0
 def test_mail_rcpt_data_rset(self):
     mock = self.mox.CreateMockAnything()
     mock.__call__(IsA(SmtpSession)).AndReturn(mock)
     mock.handle_mail(IsA(Reply), '*****@*****.**', {})
     mock.handle_rcpt(IsA(Reply), '*****@*****.**', {})
     mock.handle_data(IsA(Reply))
     self.mox.ReplayAll()
     h = SmtpSession(None, mock, None)
     h.MAIL(Reply('250'), '*****@*****.**', {})
     h.RCPT(Reply('250'), '*****@*****.**', {})
     self.assertEqual('*****@*****.**', h.envelope.sender)
     self.assertEqual(['*****@*****.**'], h.envelope.recipients)
     h.DATA(Reply('550'))
     h.RSET(Reply('250'))
     self.assertFalse(h.envelope)
コード例 #13
0
 def test_deliver_conversion(self):
     result = AsyncResult()
     env = Envelope('*****@*****.**', ['*****@*****.**'])
     env.parse(b'From: [email protected]\r\n\r\ntest test \x81\r\n')
     self.sock.sendall(b'EHLO there\r\n')
     self.sock.recv(IsA(int)).AndReturn(b'250-Hello\r\n250 PIPELINING\r\n')
     self.sock.sendall(
         b'MAIL FROM:<*****@*****.**>\r\nRCPT TO:<*****@*****.**>\r\nDATA\r\n'
     )
     self.sock.recv(
         IsA(int)).AndReturn(b'250 Ok\r\n250 Ok\r\n354 Go ahead\r\n')
     if pycompat.PY3:
         self.sock.sendall(
             b'From: [email protected]\r\nContent-Transfer-Encoding: base64\r\n\r\ndGVzdCB0ZXN0IIEK\r\n.\r\n'
         )
     else:
         self.sock.sendall(
             b'From: [email protected]\r\nContent-Transfer-Encoding: base64\r\n\r\ndGVzdCB0ZXN0IIENCg==\r\n.\r\n'
         )
     self.sock.recv(IsA(int)).AndReturn(b'250 Ok\r\n')
     self.mox.ReplayAll()
     client = SmtpRelayClient(('addr', 0),
                              self.queue,
                              socket_creator=self._socket_creator,
                              ehlo_as='there',
                              binary_encoder=encode_base64)
     client._connect()
     client._ehlo()
     client._deliver(result, env)
     self.assertEqual({'*****@*****.**': Reply('250', 'Ok')},
                      result.get_nowait())
コード例 #14
0
    def test_on_validate_rcpt(self):
        espf = EnforceSpf()
        espf.set_enforcement('fail', match_code='550')

        class TestSession(object):
            address = ('1.2.3.4', 56789)
            envelope = Envelope('*****@*****.**')
            ehlo_as = 'testehlo'

        class TestValidators(object):
            def __init__(self):
                self.session = TestSession()

            @espf.check
            def validate_rcpt(self, reply, recipient):
                pass

        spf.check2(i='1.2.3.4', s='*****@*****.**',
                   h='testehlo').AndReturn(('fail', 'the reason'))
        self.mox.ReplayAll()
        validators = TestValidators()
        reply = Reply('250', '2.0.0 Ok')
        validators.validate_rcpt(reply, 'asdf')
        self.assertEqual('550', reply.code)
        self.assertEqual('5.7.1 Access denied', reply.message)
コード例 #15
0
 def test_deliver(self):
     result = AsyncResult()
     env = Envelope('*****@*****.**', ['*****@*****.**'])
     env.parse(b'From: [email protected]\r\n\r\ntest test \x81\r\n')
     self.sock.sendall(b'EHLO there\r\n')
     self.sock.recv(IsA(int)).AndReturn(b'250-Hello\r\n250 8BITMIME\r\n')
     self.sock.sendall(b'MAIL FROM:<*****@*****.**>\r\n')
     self.sock.recv(IsA(int)).AndReturn(b'250 Ok\r\n')
     self.sock.sendall(b'RCPT TO:<*****@*****.**>\r\n')
     self.sock.recv(IsA(int)).AndReturn(b'250 Ok\r\n')
     self.sock.sendall(b'DATA\r\n')
     self.sock.recv(IsA(int)).AndReturn(b'354 Go ahead\r\n')
     self.sock.sendall(
         b'From: [email protected]\r\n\r\ntest test \x81\r\n.\r\n')
     self.sock.recv(IsA(int)).AndReturn(b'250 Ok\r\n')
     self.mox.ReplayAll()
     client = SmtpRelayClient(('addr', 0),
                              self.queue,
                              socket_creator=self._socket_creator,
                              ehlo_as='there')
     client._connect()
     client._ehlo()
     client._deliver(result, env)
     self.assertEqual({'*****@*****.**': Reply('250', 'Ok')},
                      result.get_nowait())
コード例 #16
0
 def _connect(self):
     try:
         with Timeout(self.connect_timeout):
             self.socket = self._socket_creator(self.address)
     except socket_error as (err, msg):
         reply = Reply('451', '4.3.0 Connection failed')
         raise SmtpRelayError.factory(reply)
コード例 #17
0
 def _run(self):
     result, envelope = self.poll()
     if not result:
         return
     try:
         self._connect()
         self._handshake()
         while result:
             if self._check_server_timeout():
                 self.queue.appendleft((result, envelope))
                 break
             if self._send_envelope(result, envelope):
                 result.set(True)
             if self.idle_timeout is None:
                 break
             result, envelope = self.poll()
     except SmtpRelayError as e:
         result.set_exception(e)
     except SmtpError as e:
         if not result.ready():
             reply = Reply('421', '4.3.0 {0!s}'.format(e))
             relay_error = SmtpRelayError.factory(reply)
             result.set_exception(relay_error)
     except Timeout:
         if not result.ready():
             relay_error = SmtpRelayError.factory(timed_out)
             result.set_exception(relay_error)
     except Exception as e:
         if not result.ready():
             result.set_exception(e)
         raise
     finally:
         self._disconnect()
コード例 #18
0
 def test_not_populated(self):
     r = Reply(command='SOMECOMMAND')
     assert_equal(None, r.code)
     assert_equal(None, r.message)
     assert_equal(None, r.enhanced_status_code)
     assert_false(r)
     assert_equal('SOMECOMMAND', r.command)
コード例 #19
0
 def test_message_set_clear_esc(self):
     r = Reply('250', '2.3.4 Ok')
     assert_equal('2.3.4 Ok', r.message)
     assert_equal('2.3.4', r.enhanced_status_code)
     r.message = None
     assert_equal(None, r.message)
     assert_equal('2.0.0', r.enhanced_status_code)
コード例 #20
0
    def test_check_dnsrbl(self):
        class TestSession(object):
            address = ('1.2.3.4', 56789)

        class TestValidators(object):
            def __init__(self):
                self.session = TestSession()

            @check_dnsbl('test.example.com')
            def validate_mail(self, reply, sender):
                assert False

        DNSResolver.query('4.3.2.1.test.example.com',
                          'A').AndRaise(DNSError(ARES_ENOTFOUND))
        DNSResolver.query('4.3.2.1.test.example.com',
                          'A').AndReturn(FakeAsyncResult())
        self.mox.ReplayAll()
        validators = TestValidators()
        reply = Reply('250', '2.0.0 Ok')
        self.assertRaises(AssertionError, validators.validate_mail, reply,
                          'asdf')
        self.assertEqual('250', reply.code)
        self.assertEqual('2.0.0 Ok', reply.message)
        validators.validate_mail(reply, 'asdf')
        self.assertEqual('550', reply.code)
        self.assertEqual('5.7.1 Access denied', reply.message)
コード例 #21
0
 def test_esc_set_false(self):
     r = Reply('250', 'Ok')
     assert_equal('2.0.0 Ok', r.message)
     r.enhanced_status_code = None
     assert_equal('2.0.0 Ok', r.message)
     r.enhanced_status_code = False
     assert_equal('Ok', r.message)
コード例 #22
0
 def _handle_encoding(self, envelope):
     if '8BITMIME' not in self.client.extensions:
         try:
             envelope.encode_7bit(self.binary_encoder)
         except UnicodeError:
             reply = Reply('554', '5.6.3 Conversion not allowed')
             raise SmtpRelayError.factory(reply)
コード例 #23
0
 def test_is_error(self):
     replies = [Reply(str(i) + '50', 'Test') for i in range(1, 6)]
     assert_false(replies[0].is_error())
     assert_false(replies[1].is_error())
     assert_false(replies[2].is_error())
     assert_true(replies[3].is_error())
     assert_true(replies[4].is_error())
コード例 #24
0
 def test_have_data_errors(self):
     h = SmtpSession(None, None, None)
     reply = Reply('250')
     h.HAVE_DATA(reply, None, MessageTooBig())
     self.assertEqual('552', reply.code)
     with self.assertRaises(ValueError):
         h.HAVE_DATA(reply, None, ValueError())
コード例 #25
0
    def test_no_policy_match(self):
        espf = EnforceSpf()
        espf.set_enforcement('fail', match_code='550')

        class TestSession(object):
            address = ('1.2.3.4', 56789)
            envelope = None
            ehlo_as = 'testehlo'

        class TestValidators(object):
            def __init__(self):
                self.session = TestSession()

            @espf.check
            def validate_mail(self, reply, sender):
                pass

        spf.check2(i='1.2.3.4', s='*****@*****.**',
                   h='testehlo').AndReturn(('none', 'the reason'))
        self.mox.ReplayAll()
        validators = TestValidators()
        reply = Reply('250', '2.0.0 Ok')
        validators.validate_mail(reply, '*****@*****.**')
        self.assertEqual('250', reply.code)
        self.assertEqual('2.0.0 Ok', reply.message)
コード例 #26
0
 def test_run(self):
     result = AsyncResult()
     env = Envelope('*****@*****.**', ['*****@*****.**'])
     env.parse(b'From: [email protected]\r\n\r\ntest test\r\n')
     queue = BlockingDeque()
     queue.append((result, env))
     self.sock.recv(IsA(int)).AndReturn(b'220 Welcome\r\n')
     self.sock.sendall(b'EHLO there\r\n')
     self.sock.recv(IsA(int)).AndReturn(b'250-Hello\r\n250 PIPELINING\r\n')
     self.sock.sendall(
         b'MAIL FROM:<*****@*****.**>\r\nRCPT TO:<*****@*****.**>\r\nDATA\r\n'
     )
     self.sock.recv(
         IsA(int)).AndReturn(b'250 Ok\r\n250 Ok\r\n354 Go ahead\r\n')
     self.sock.sendall(
         b'From: [email protected]\r\n\r\ntest test\r\n.\r\n')
     self.sock.recv(IsA(int)).AndReturn(b'250 Ok\r\n')
     self.sock.sendall(b'QUIT\r\n')
     self.sock.recv(IsA(int)).AndReturn(b'221 Goodbye\r\n')
     self.sock.close()
     self.mox.ReplayAll()
     client = SmtpRelayClient(('addr', 0),
                              queue,
                              socket_creator=self._socket_creator,
                              ehlo_as='there')
     client._run()
     self.assertEqual({'*****@*****.**': Reply('250', 'Ok')},
                      result.get_nowait())
コード例 #27
0
    def HAVE_DATA(self, reply, data, err):
        if isinstance(err, MessageTooBig):
            reply.code = '552'
            reply.message = '5.3.4 Message exceeded size limit'
            return
        elif err:
            raise err

        self._call_validator('have_data', reply, data)
        if reply.code != '250':
            return

        if self._ptr_lookup is not None:
            self.reverse_address = self._ptr_lookup.finish()
        self.envelope.client['ip'] = self.address[0]
        self.envelope.client['host'] = self.reverse_address
        self.envelope.client['name'] = self.ehlo_as
        self.envelope.client['protocol'] = self.protocol
        self.envelope.client['auth'] = self.auth

        self.envelope.parse(data)

        results = self.handoff(self.envelope)
        if isinstance(results[0][1], QueueError):
            default_reply = Reply('451', '4.3.0 Error queuing message')
            queue_reply = getattr(results[0][1], 'reply', default_reply)
            reply.copy(queue_reply)
        elif isinstance(results[0][1], RelayError):
            relay_reply = results[0][1].reply
            reply.copy(relay_reply)
        else:
            reply.message = '2.6.0 Message accepted for delivery'
        self._call_validator('queued', reply, results)

        self.envelope = None
コード例 #28
0
 def test_not_populated(self):
     r = Reply(command=b'SOMECOMMAND')
     self.assertEqual(None, r.code)
     self.assertEqual(None, r.message)
     self.assertEqual(None, r.enhanced_status_code)
     self.assertFalse(r)
     self.assertEqual(b'SOMECOMMAND', r.command)
コード例 #29
0
 def __init__(self, msg, reply=None):
     super(RelayError, self).__init__(msg)
     if reply:
         self.reply = reply
     else:
         reply_msg = self._default_esc + ' ' + msg
         self.reply = Reply(self._default_code, reply_msg)
コード例 #30
0
 def test_deliver_multircpt(self):
     result = self.mox.CreateMockAnything()
     env = Envelope(
         '*****@*****.**',
         ['*****@*****.**', '*****@*****.**', '*****@*****.**'])
     env.parse(b'From: [email protected]\r\n\r\ntest test\r\n')
     self.sock.sendall(b'LHLO there\r\n')
     self.sock.recv(IsA(int)).AndReturn(b'250-Hello\r\n250 PIPELINING\r\n')
     self.sock.sendall(
         b'MAIL FROM:<*****@*****.**>\r\nRCPT TO:<*****@*****.**>\r\nRCPT TO:<*****@*****.**>\r\nRCPT TO:<*****@*****.**>\r\nDATA\r\n'
     )
     self.sock.recv(IsA(int)).AndReturn(
         b'250 Ok\r\n250 Ok\r\n550 Nope\r\n250 Ok\r\n354 Go ahead\r\n')
     self.sock.sendall(
         b'From: [email protected]\r\n\r\ntest test\r\n.\r\n')
     self.sock.recv(IsA(int)).AndReturn(b'250 Ok\r\n450 Yikes\r\n')
     result.set({
         '*****@*****.**': Reply('250', 'Ok'),
         '*****@*****.**': IsA(PermanentRelayError),
         '*****@*****.**': IsA(TransientRelayError)
     })
     self.sock.sendall(b'RSET\r\n')
     self.sock.recv(IsA(int)).AndReturn(b'250 Ok\r\n')
     self.mox.ReplayAll()
     client = LmtpRelayClient('addr',
                              self.queue,
                              socket_creator=self._socket_creator,
                              ehlo_as='there')
     client._connect()
     client._ehlo()
     client._deliver(result, env)