Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions Lib/smtpd.py
Original file line number Diff line number Diff line change
Expand Up @@ -738,16 +738,17 @@ def __init__(self, *args, **kwargs):
raise ValueError("PureProxy does not support SMTPUTF8.")
super(PureProxy, self).__init__(*args, **kwargs)

def process_message(self, peer, mailfrom, rcpttos, data):
lines = data.split('\n')
def process_message(self, peer, mailfrom, rcpttos, data, **kwargs):
lines = data.split(b'\n')
# Look for the last header
i = 0
for line in lines:
if not line:
break
i += 1
lines.insert(i, 'X-Peer: %s' % peer[0])
data = NEWLINE.join(lines)
peer_address = peer[0].encode('ascii')
lines.insert(i, b'X-Peer: %s' % peer_address)
data = b'\n'.join(lines)
refused = self._deliver(mailfrom, rcpttos, data)
# TBD: what to do with refused addresses?
print('we got some refusals:', refused, file=DEBUGSTREAM)
Expand Down Expand Up @@ -783,7 +784,7 @@ def __init__(self, *args, **kwargs):
raise ValueError("MailmanProxy does not support SMTPUTF8.")
super(PureProxy, self).__init__(*args, **kwargs)

def process_message(self, peer, mailfrom, rcpttos, data):
def process_message(self, peer, mailfrom, rcpttos, data, **kwargs):
from io import StringIO
from Mailman import Utils
from Mailman import Message
Expand Down Expand Up @@ -826,7 +827,7 @@ def process_message(self, peer, mailfrom, rcpttos, data):
print('we got refusals:', refused, file=DEBUGSTREAM)
# Now deliver directly to the list commands
mlists = {}
s = StringIO(data)
s = StringIO(data.decode())
msg = Message.Message(s)
# These headers are required for the proper execution of Mailman. All
# MTAs in existence seem to add these if the original message doesn't
Expand Down
80 changes: 80 additions & 0 deletions Lib/test/test_smtpd.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
import io
import smtpd
import asyncore
import smtplib
from unittest.mock import MagicMock, patch


class DummyServer(smtpd.SMTPServer):
Expand Down Expand Up @@ -160,6 +162,84 @@ def tearDown(self):
asyncore.socket = smtpd.socket = socket


class PureProxyServerTest(unittest.TestCase):

def setUp(self):
smtpd.socket = asyncore.socket = mock_socket

@patch('smtplib.SMTP')
def test_proxy_successful(self, mock_smtp):
fake_smtp = MagicMock()
fake_smtp.sendmail = MagicMock(return_value={})
mock_smtp.return_value = fake_smtp
server = smtpd.PureProxy((support.HOST, 0), ('b', 0))
conn, addr = server.accept()
channel = smtpd.SMTPChannel(server, conn, addr)

def write_line(line):
channel.socket.queue_recv(line)
channel.handle_read()

write_line(b'EHLO example')
write_line(b'MAIL From:eggs@example')
write_line(b'RCPT To:spam@example')
write_line(b'DATA')
write_line(b'From: test\n\nhello\n')
write_line(b'.')

mock_smtp.assert_called_once_with()
fake_smtp.connect.assert_called_once_with('b', 0)
fake_smtp.sendmail.assert_called_once_with(
'eggs@example',
['spam@example'],
b'From: test\nX-Peer: peer-address\n\nhello\n'
)
fake_smtp.quit.assert_called_once_with()

@patch('smtplib.SMTP')
def test_deliver_refused(self, mock_smtp):
fake_smtp = MagicMock()
exc = smtplib.SMTPRecipientsRefused({'error@example': (1, 'testing')})
fake_smtp.sendmail = MagicMock(side_effect=exc)
mock_smtp.return_value = fake_smtp

server = smtpd.PureProxy((support.HOST, 0), ('b', 0))
refused = server._deliver(
'eggs@example',
['spam@example'],
b'From: test\nX-Peer: peer-address\n\nhello\n'
)
self.assertEqual(refused, {'error@example': (1, 'testing')})
fake_smtp.connect.assert_called_once_with('b', 0)
fake_smtp.quit.assert_called_once_with()

@patch('smtplib.SMTP')
def test_deliver_error(self, mock_smtp):
fake_smtp = MagicMock()
exc = OSError()
exc.smtp_code = 42
fake_smtp.sendmail = MagicMock(side_effect=exc)
mock_smtp.return_value = fake_smtp

server = smtpd.PureProxy((support.HOST, 0), ('b', 0))
refused = server._deliver(
'eggs@example',
['spam@example'],
b'From: test\nX-Peer: peer-address\n\nhello\n'
)
self.assertEqual(refused, {'spam@example': (42, 'ignore')})
fake_smtp.connect.assert_called_once_with('b', 0)
fake_smtp.quit.assert_called_once_with()

def test_init_enable_SMTPUTF8(self):
self.assertRaises(ValueError, smtpd.PureProxy,
(support.HOST, 0), ('b', 0), enable_SMTPUTF8=True)

def tearDown(self):
asyncore.close_all()
asyncore.socket = smtpd.socket = socket


class TestFamilyDetection(unittest.TestCase):
def setUp(self):
smtpd.socket = asyncore.socket = mock_socket
Expand Down
1 change: 1 addition & 0 deletions Misc/ACKS
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,7 @@ Benjamin Collar
Jeffery Collins
Robert Collins
Paul Colomiets
Samuel Colvin
Christophe Combelles
Geremy Condra
Denver Coneybeare
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix regressions in ``smtpd.PureProxy`` and ``smtpd.MailmanProxy``.