Repository: aio-libs/aiosmtpd
Pull request #18 (2016-11-20 15:33:07)

Added new parameter hostname for SMTP
Which can use for set custom hostname for smtpd and avoid blocking on call socket.getfqdn().


Patch:
diff --git a/aiosmtpd/smtp.py b/aiosmtpd/smtp.py
index 2d1e134..a16bf36 100644
--- a/aiosmtpd/smtp.py
+++ b/aiosmtpd/smtp.py
@@ -34,6 +34,7 @@ class SMTP(asyncio.StreamReaderProtocol):
                  data_size_limit=DATA_SIZE_DEFAULT,
                  enable_SMTPUTF8=False,
                  decode_data=False,
+                 hostname=None,
                  loop=None):
         self.loop = loop if loop else asyncio.get_event_loop()
         super().__init__(
@@ -64,7 +65,10 @@ class SMTP(asyncio.StreamReaderProtocol):
         self.seen_greeting = ''
         self.extended_smtp = False
         self.command_size_limits.clear()
-        self.fqdn = socket.getfqdn()   # XXX this blocks, fix it?
+        if hostname:
+            self.hostname = hostname
+        else:
+            self.hostname = socket.getfqdn()
 
     @property
     def max_command_size_limit(self):
@@ -116,7 +120,7 @@ class SMTP(asyncio.StreamReaderProtocol):
     @asyncio.coroutine
     def _handle_client(self):
         log.info('handling connection')
-        yield from self.push('220 %s %s' % (self.fqdn, __version__))
+        yield from self.push('220 %s %s' % (self.hostname, __version__))
         while not self.connection_closed:
             # XXX Put the line limit stuff into the StreamReader?
             line = yield from self._reader.readline()
@@ -161,7 +165,7 @@ class SMTP(asyncio.StreamReaderProtocol):
             return
         self._set_rset_state()
         self.seen_greeting = hostname
-        yield from self.push('250 %s' % self.fqdn)
+        yield from self.push('250 %s' % self.hostname)
 
     @asyncio.coroutine
     def smtp_EHLO(self, arg):
@@ -175,7 +179,7 @@ class SMTP(asyncio.StreamReaderProtocol):
         self._set_rset_state()
         self.seen_greeting = arg
         self.extended_smtp = True
-        yield from self.push('250-%s' % self.fqdn)
+        yield from self.push('250-%s' % self.hostname)
         if self.data_size_limit:
             yield from self.push('250-SIZE %s' % self.data_size_limit)
             self.command_size_limits['MAIL'] += 26


Test patch:
diff --git a/aiosmtpd/tests/test_smtp.py b/aiosmtpd/tests/test_smtp.py
index b7cb31b..cdb39f4 100644
--- a/aiosmtpd/tests/test_smtp.py
+++ b/aiosmtpd/tests/test_smtp.py
@@ -28,6 +28,11 @@ class SMTPUTF8Controller(Controller):
         return Server(self.handler, enable_SMTPUTF8=True)
 
 
+class CustomHostnameController(Controller):
+    def factory(self):
+        return Server(self.handler, hostname='custom.localhost')
+
+
 class ErroringHandler:
     def process_message(self, peer, mailfrom, rcpttos, data, **kws):
         return '499 Could not accept the message'
@@ -527,3 +532,17 @@ Testing
                 self.assertEqual(cm.exception.code, 499)
                 self.assertEqual(cm.exception.response,
                                  b'Could not accept the message')
+
+
+class TestCustomHostname(unittest.TestCase):
+    def setUp(self):
+        controller = CustomHostnameController(Sink)
+        controller.start()
+        self.addCleanup(controller.stop)
+        self.address = (controller.hostname, controller.port)
+
+    def test_helo(self):
+        with SMTP(*self.address) as client:
+            code, response = client.helo('example.com')
+            self.assertEqual(code, 250)
+            self.assertEqual(response, bytes('custom.localhost', 'utf-8'))