diff --git a/aiosmtpd/docs/NEWS.rst b/aiosmtpd/docs/NEWS.rst
index dc6631a..7ade980 100644
--- a/aiosmtpd/docs/NEWS.rst
+++ b/aiosmtpd/docs/NEWS.rst
@@ -21,6 +21,10 @@
 * Widen the catch of ``ConnectionResetError`` and ``CancelledError`` to also
   catch such errors from handler methods.  (Closes #110)
 * Added a manpage for the ``aiosmtpd`` command line script.  (Closes #116)
+* Added much better support for the ``HELP``.  There's a new decorator called
+  ``@syntax()`` which you can use in derived classes to decorate ``smtp_*()``
+  methods.  These then show up in ``HELP`` responses.  This also fixes
+  ``HELP`` responses for the ``LMTP`` subclass.  (Closes #113)
 
 1.0 (2017-05-15)
 ================
diff --git a/aiosmtpd/docs/smtp.rst b/aiosmtpd/docs/smtp.rst
index f46a65e..de2aebc 100644
--- a/aiosmtpd/docs/smtp.rst
+++ b/aiosmtpd/docs/smtp.rst
@@ -28,8 +28,9 @@ All methods implementing ``SMTP`` commands are prefixed with ``smtp_``; they
 must also be coroutines.  Here's how you could implement this use case::
 
     >>> import asyncio
-    >>> from aiosmtpd.smtp import SMTP as Server
+    >>> from aiosmtpd.smtp import SMTP as Server, syntax
     >>> class MyServer(Server):
+    ...     @syntax('PING [ignored]')
     ...     async def smtp_PING(self, arg):
     ...         await self.push('259 Pong')
 
@@ -61,6 +62,17 @@ command, we have to use the lower level interface to talk to it.
     >>> message
     b'Pong'
 
+Because we prefixed the ``smtp_PING()`` method with the ``@syntax()``
+decorator, the command shows up in the ``HELP`` output.
+
+    >>> print(client.help().decode('utf-8'))
+    Supported commands: DATA EHLO HELO HELP MAIL NOOP PING QUIT RCPT RSET VRFY
+
+And we can get more detailed help on the new command.
+
+    >>> print(client.help('PING').decode('utf-8'))
+    Syntax: PING [ignored]
+
 
 Server hooks
 ============
diff --git a/aiosmtpd/lmtp.py b/aiosmtpd/lmtp.py
index 65b5fd3..53ed087 100644
--- a/aiosmtpd/lmtp.py
+++ b/aiosmtpd/lmtp.py
@@ -1,12 +1,14 @@
-from aiosmtpd.smtp import SMTP
+from aiosmtpd.smtp import SMTP, syntax
 from public import public
 
 
 @public
 class LMTP(SMTP):
+    @syntax('LHLO hostname')
     async def smtp_LHLO(self, arg):
         """The LMTP greeting, used instead of HELO/EHLO."""
         await super().smtp_HELO(arg)
+        self.show_smtp_greeting = False
 
     async def smtp_HELO(self, arg):
         """HELO is not a valid LMTP command."""
diff --git a/aiosmtpd/smtp.py b/aiosmtpd/smtp.py
index dfdbcb5..780d11a 100644
--- a/aiosmtpd/smtp.py
+++ b/aiosmtpd/smtp.py
@@ -51,6 +51,15 @@ def make_loop():
     return asyncio.get_event_loop()
 
 
+def syntax(text, extended=None, when=None):
+    def decorator(f):
+        f.__smtp_syntax__ = text
+        f.__smtp_syntax_extended__ = extended
+        f.__smtp_syntax_when__ = when
+        return f
+    return decorator
+
+
 @public
 class SMTP(asyncio.StreamReaderProtocol):
     command_size_limit = 512
@@ -281,6 +290,7 @@ class SMTP(asyncio.StreamReaderProtocol):
                     await self.push(status)
 
     # SMTP and ESMTP commands
+    @syntax('HELO hostname')
     async def smtp_HELO(self, hostname):
         if not hostname:
             await self.push('501 Syntax: HELO hostname')
@@ -293,6 +303,7 @@ class SMTP(asyncio.StreamReaderProtocol):
             status = '250 {}'.format(self.hostname)
         await self.push(status)
 
+    @syntax('EHLO hostname')
     async def smtp_EHLO(self, hostname):
         if not hostname:
             await self.push('501 Syntax: EHLO hostname')
@@ -320,10 +331,12 @@ class SMTP(asyncio.StreamReaderProtocol):
             status = '250 HELP'
         await self.push(status)
 
+    @syntax('NOOP [ignored]')
     async def smtp_NOOP(self, arg):
         status = await self._call_handler_hook('NOOP', arg)
         await self.push('250 OK' if status is MISSING else status)
 
+    @syntax('QUIT')
     async def smtp_QUIT(self, arg):
         if arg:
             await self.push('501 Syntax: QUIT')
@@ -333,6 +346,7 @@ class SMTP(asyncio.StreamReaderProtocol):
             self._handler_coroutine.cancel()
             self.transport.close()
 
+    @syntax('STARTTLS', when='tls_context')
     async def smtp_STARTTLS(self, arg):
         log.info('%r STARTTLS', self.session.peer)
         if arg:
@@ -390,43 +404,39 @@ class SMTP(asyncio.StreamReaderProtocol):
             result[param] = value if eq else True
         return result
 
+    def _syntax_available(self, method):
+        if getattr(method, '__smtp_syntax__', None) is None:
+            return False
+        if method.__smtp_syntax_when__:
+            return bool(getattr(self, method.__smtp_syntax_when__))
+        return True
+
+    @syntax('HELP [command]')
+    @asyncio.coroutine
     async def smtp_HELP(self, arg):
+        code = 250
         if arg:
-            extended = ' [SP <mail-parameters>]'
-            lc_arg = arg.upper()
-            if lc_arg == 'EHLO':
-                await self.push('250 Syntax: EHLO hostname')
-            elif lc_arg == 'HELO':
-                await self.push('250 Syntax: HELO hostname')
-            elif lc_arg == 'MAIL':
-                msg = '250 Syntax: MAIL FROM: <address>'
-                if self.session.extended_smtp:
-                    msg += extended
-                await self.push(msg)
-            elif lc_arg == 'RCPT':
-                msg = '250 Syntax: RCPT TO: <address>'
-                if self.session.extended_smtp:
-                    msg += extended
-                await self.push(msg)
-            elif lc_arg == 'DATA':
-                await self.push('250 Syntax: DATA')
-            elif lc_arg == 'RSET':
-                await self.push('250 Syntax: RSET')
-            elif lc_arg == 'NOOP':
-                await self.push('250 Syntax: NOOP')
-            elif lc_arg == 'QUIT':
-                await self.push('250 Syntax: QUIT')
-            elif lc_arg == 'VRFY':
-                await self.push('250 Syntax: VRFY <address>')
-            else:
-                await self.push(
-                    '501 Supported commands: EHLO HELO MAIL RCPT '
-                    'DATA RSET NOOP QUIT VRFY')
-        else:
-            await self.push(
-                '250 Supported commands: EHLO HELO MAIL RCPT DATA '
-                'RSET NOOP QUIT VRFY')
-
+            method = getattr(self, 'smtp_' + arg.upper(), None)
+            if method and self._syntax_available(method):
+                help_str = method.__smtp_syntax__
+                if (self.session.extended_smtp
+                        and method.__smtp_syntax_extended__):
+                    help_str += method.__smtp_syntax_extended__
+                await self.push('250 Syntax: ' + help_str)
+                return
+            code = 501
+        commands = []
+        for name in dir(self):
+            if not name.startswith('smtp_'):
+                continue
+            method = getattr(self, name)
+            if self._syntax_available(method):
+                commands.append(name.lstrip('smtp_'))
+        commands.sort()
+        await self.push(
+            '{} Supported commands: {}'.format(code, ' '.join(commands)))
+
+    @syntax('VRFY <address>')
     async def smtp_VRFY(self, arg):
         if arg:
             try:
@@ -444,6 +454,7 @@ class SMTP(asyncio.StreamReaderProtocol):
         else:
             await self.push('501 Syntax: VRFY <address>')
 
+    @syntax('MAIL FROM: <address>', extended=' [SP <mail-parameters>]')
     async def smtp_MAIL(self, arg):
         if not self.session.host_name:
             await self.push('503 Error: send HELO first')
@@ -510,6 +521,7 @@ class SMTP(asyncio.StreamReaderProtocol):
         log.info('%r sender: %s', self.session.peer, address)
         await self.push(status)
 
+    @syntax('RCPT TO: <address>', extended=' [SP <mail-parameters>]')
     async def smtp_RCPT(self, arg):
         if not self.session.host_name:
             await self.push('503 Error: send HELO first')
@@ -556,6 +568,7 @@ class SMTP(asyncio.StreamReaderProtocol):
         log.info('%r recip: %s', self.session.peer, address)
         await self.push(status)
 
+    @syntax('RSET')
     async def smtp_RSET(self, arg):
         if arg:
             await self.push('501 Syntax: RSET')
@@ -568,6 +581,7 @@ class SMTP(asyncio.StreamReaderProtocol):
         status = await self._call_handler_hook('RSET')
         await self.push('250 OK' if status is MISSING else status)
 
+    @syntax('DATA')
     async def smtp_DATA(self, arg):
         if not self.session.host_name:
             await self.push('503 Error: send HELO first')

LMTP server offers HELO, doesn't provide correct LHLO response
As initailly reported here: https://gitlab.com/mailman/mailman/issues/348

Telnet to the LMTP server, and type "HELP".

It responds with 
250 Supported commands: EHLO HELO MAIL RCPT DATA RSET NOOP QUIT VRFY

This isn't correct.  LMTP uses LHLO; the EHLO and HELO should not be offered.

LHLO foo

Responds with
250 foo.example.net

RFC2033 says the implementation MUST support PIPELINING and ENHANCEDSTATUSCODES, and SHOULD support 8BITMIME

Thus, LHLO should be responding with the ESMTP keywords for these extensions.

8BITMIME (RFC 1652)

ENHANCEDSTATUSCODES (RFC 2034)

PIPELINING (RFC 1854)

Since it also responds to HELP HELP should also be listed (RFC 1869)

Thus, the dialog should look like:
````
S: 220 foo.example.net GNU Mailman LMTP ...
C: LHLO foo
S: 250-foo.example.net
S: 250-HELP
S: 250-ENHANCEDSTATUSCODES
S: 250-8BITMIME
S: 250 PIPELINING
````

(The order doesn't matter.)

And, obviously, 'HELP' should respond with the correct list of supported commands - including LHLO.


diff --git a/aiosmtpd/tests/test_lmtp.py b/aiosmtpd/tests/test_lmtp.py
index 0af6594..d77816e 100644
--- a/aiosmtpd/tests/test_lmtp.py
+++ b/aiosmtpd/tests/test_lmtp.py
@@ -40,3 +40,13 @@ class TestLMTP(unittest.TestCase):
             code, response = client.ehlo('example.com')
             self.assertEqual(code, 500)
             self.assertEqual(response, b'Error: command "EHLO" not recognized')
+
+    def test_help(self):
+        # https://github.com/aio-libs/aiosmtpd/issues/113
+        with SMTP(*self.address) as client:
+            # Don't get tricked by smtplib processing of the response.
+            code, response = client.docmd('HELP')
+            self.assertEqual(code, 250)
+            self.assertEqual(response,
+                             b'Supported commands: DATA HELP LHLO MAIL '
+                             b'NOOP QUIT RCPT RSET VRFY')
diff --git a/aiosmtpd/tests/test_smtp.py b/aiosmtpd/tests/test_smtp.py
index ab52cf6..8d2a07d 100644
--- a/aiosmtpd/tests/test_smtp.py
+++ b/aiosmtpd/tests/test_smtp.py
@@ -287,8 +287,8 @@ class TestSMTP(unittest.TestCase):
             code, response = client.docmd('HELP')
             self.assertEqual(code, 250)
             self.assertEqual(response,
-                             b'Supported commands: EHLO HELO MAIL RCPT '
-                             b'DATA RSET NOOP QUIT VRFY')
+                             b'Supported commands: DATA EHLO HELO HELP MAIL '
+                             b'NOOP QUIT RCPT RSET VRFY')
 
     def test_help_helo(self):
         with SMTP(*self.address) as client:
@@ -354,7 +354,7 @@ class TestSMTP(unittest.TestCase):
         with SMTP(*self.address) as client:
             code, response = client.docmd('HELP', 'NOOP')
             self.assertEqual(code, 250)
-            self.assertEqual(response, b'Syntax: NOOP')
+            self.assertEqual(response, b'Syntax: NOOP [ignored]')
 
     def test_help_quit(self):
         with SMTP(*self.address) as client:
@@ -374,8 +374,8 @@ class TestSMTP(unittest.TestCase):
             code, response = client.docmd('HELP me!')
             self.assertEqual(code, 501)
             self.assertEqual(response,
-                             b'Supported commands: EHLO HELO MAIL RCPT '
-                             b'DATA RSET NOOP QUIT VRFY')
+                             b'Supported commands: DATA EHLO HELO HELP MAIL '
+                             b'NOOP QUIT RCPT RSET VRFY')
 
     def test_expn(self):
         with SMTP(*self.address) as client:
diff --git a/aiosmtpd/tests/test_starttls.py b/aiosmtpd/tests/test_starttls.py
index e8608c4..f7c1fde 100644
--- a/aiosmtpd/tests/test_starttls.py
+++ b/aiosmtpd/tests/test_starttls.py
@@ -103,6 +103,18 @@ class TestStartTLS(unittest.TestCase):
             code, response = client.docmd('STARTTLS', 'TRUE')
             self.assertEqual(code, 501)
 
+    def test_help_after_starttls(self):
+        controller = TLSController(Sink())
+        controller.start()
+        self.addCleanup(controller.stop)
+        with SMTP(controller.hostname, controller.port) as client:
+            # Don't get tricked by smtplib processing of the response.
+            code, response = client.docmd('HELP')
+            self.assertEqual(code, 250)
+            self.assertEqual(response,
+                             b'Supported commands: DATA EHLO HELO HELP MAIL '
+                             b'NOOP QUIT RCPT RSET STARTTLS VRFY')
+
 
 class TestTLSForgetsSessionData(unittest.TestCase):
     def setUp(self):

pip install -e .[dev]
parse_log_pytest
pytest
pytest
3.9
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
-e git+https://github.com/aio-libs/aiosmtpd.git@b87538bc1fc0137b5d188db938c9b386c71683a3#egg=aiosmtpd
atpublic==5.1
exceptiongroup @ file:///croot/exceptiongroup_1706031385326/work
iniconfig @ file:///home/linux1/recipes/ci/iniconfig_1610983019677/work
packaging @ file:///croot/packaging_1734472117206/work
pluggy @ file:///croot/pluggy_1733169602837/work
pytest @ file:///croot/pytest_1738938843180/work
tomli @ file:///opt/conda/conda-bld/tomli_1657175507142/work

name: aiosmtpd
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - exceptiongroup=1.2.0=py39h06a4308_0
  - iniconfig=1.1.1=pyhd3eb1b0_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.4.4=h6a678d5_1
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=3.0.16=h5eee18b_0
  - packaging=24.2=py39h06a4308_0
  - pip=25.0=py39h06a4308_0
  - pluggy=1.5.0=py39h06a4308_0
  - pytest=8.3.4=py39h06a4308_0
  - python=3.9.21=he870216_1
  - readline=8.2=h5eee18b_0
  - setuptools=75.8.0=py39h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - tomli=2.0.1=py39h06a4308_0
  - tzdata=2025a=h04d1e81_0
  - wheel=0.45.1=py39h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - atpublic==5.1
prefix: /opt/conda/envs/aiosmtpd

aiosmtpd/tests/test_lmtp.py::TestLMTP::test_help aiosmtpd/tests/test_smtp.py::TestSMTP::test_help aiosmtpd/tests/test_smtp.py::TestSMTP::test_help_bad_arg aiosmtpd/tests/test_smtp.py::TestSMTP::test_help_noop aiosmtpd/tests/test_starttls.py::TestStartTLS::test_help_after_starttls
aiosmtpd/tests/test_lmtp.py::TestLMTP::test_ehlo aiosmtpd/tests/test_lmtp.py::TestLMTP::test_helo aiosmtpd/tests/test_lmtp.py::TestLMTP::test_lhlo aiosmtpd/tests/test_smtp.py::TestProtocol::test_empty_email aiosmtpd/tests/test_smtp.py::TestProtocol::test_honors_mail_delimeters aiosmtpd/tests/test_smtp.py::TestSMTP::test_data_invalid_params aiosmtpd/tests/test_smtp.py::TestSMTP::test_data_no_helo aiosmtpd/tests/test_smtp.py::TestSMTP::test_data_no_rcpt aiosmtpd/tests/test_smtp.py::TestSMTP::test_ehlo aiosmtpd/tests/test_smtp.py::TestSMTP::test_ehlo_duplicate aiosmtpd/tests/test_smtp.py::TestSMTP::test_ehlo_no_hostname aiosmtpd/tests/test_smtp.py::TestSMTP::test_ehlo_then_helo aiosmtpd/tests/test_smtp.py::TestSMTP::test_empty_command aiosmtpd/tests/test_smtp.py::TestSMTP::test_expn aiosmtpd/tests/test_smtp.py::TestSMTP::test_helo aiosmtpd/tests/test_smtp.py::TestSMTP::test_helo_duplicate aiosmtpd/tests/test_smtp.py::TestSMTP::test_helo_no_hostname aiosmtpd/tests/test_smtp.py::TestSMTP::test_helo_then_ehlo aiosmtpd/tests/test_smtp.py::TestSMTP::test_help_data aiosmtpd/tests/test_smtp.py::TestSMTP::test_help_ehlo aiosmtpd/tests/test_smtp.py::TestSMTP::test_help_helo aiosmtpd/tests/test_smtp.py::TestSMTP::test_help_mail aiosmtpd/tests/test_smtp.py::TestSMTP::test_help_mail_esmtp aiosmtpd/tests/test_smtp.py::TestSMTP::test_help_quit aiosmtpd/tests/test_smtp.py::TestSMTP::test_help_rcpt aiosmtpd/tests/test_smtp.py::TestSMTP::test_help_rcpt_esmtp aiosmtpd/tests/test_smtp.py::TestSMTP::test_help_rset aiosmtpd/tests/test_smtp.py::TestSMTP::test_help_vrfy aiosmtpd/tests/test_smtp.py::TestSMTP::test_mail_fail_parse_email aiosmtpd/tests/test_smtp.py::TestSMTP::test_mail_from_malformed aiosmtpd/tests/test_smtp.py::TestSMTP::test_mail_from_twice aiosmtpd/tests/test_smtp.py::TestSMTP::test_mail_malformed_params_esmtp aiosmtpd/tests/test_smtp.py::TestSMTP::test_mail_missing_params_esmtp aiosmtpd/tests/test_smtp.py::TestSMTP::test_mail_no_arg aiosmtpd/tests/test_smtp.py::TestSMTP::test_mail_no_from aiosmtpd/tests/test_smtp.py::TestSMTP::test_mail_no_helo aiosmtpd/tests/test_smtp.py::TestSMTP::test_mail_params_bad_syntax_esmtp aiosmtpd/tests/test_smtp.py::TestSMTP::test_mail_params_esmtp aiosmtpd/tests/test_smtp.py::TestSMTP::test_mail_params_no_esmtp aiosmtpd/tests/test_smtp.py::TestSMTP::test_mail_unrecognized_params_esmtp aiosmtpd/tests/test_smtp.py::TestSMTP::test_noop aiosmtpd/tests/test_smtp.py::TestSMTP::test_noop_with_arg aiosmtpd/tests/test_smtp.py::TestSMTP::test_quit aiosmtpd/tests/test_smtp.py::TestSMTP::test_quit_with_arg aiosmtpd/tests/test_smtp.py::TestSMTP::test_rcpt_fail_parse_email aiosmtpd/tests/test_smtp.py::TestSMTP::test_rcpt_no_address aiosmtpd/tests/test_smtp.py::TestSMTP::test_rcpt_no_arg aiosmtpd/tests/test_smtp.py::TestSMTP::test_rcpt_no_arg_esmtp aiosmtpd/tests/test_smtp.py::TestSMTP::test_rcpt_no_helo aiosmtpd/tests/test_smtp.py::TestSMTP::test_rcpt_no_mail aiosmtpd/tests/test_smtp.py::TestSMTP::test_rcpt_no_to aiosmtpd/tests/test_smtp.py::TestSMTP::test_rcpt_with_bad_params aiosmtpd/tests/test_smtp.py::TestSMTP::test_rcpt_with_params_no_esmtp aiosmtpd/tests/test_smtp.py::TestSMTP::test_rcpt_with_unknown_params aiosmtpd/tests/test_smtp.py::TestSMTP::test_rset aiosmtpd/tests/test_smtp.py::TestSMTP::test_rset_with_arg aiosmtpd/tests/test_smtp.py::TestSMTP::test_too_long_command aiosmtpd/tests/test_smtp.py::TestSMTP::test_unknown_command aiosmtpd/tests/test_smtp.py::TestSMTP::test_vrfy aiosmtpd/tests/test_smtp.py::TestSMTP::test_vrfy_no_arg aiosmtpd/tests/test_smtp.py::TestSMTP::test_vrfy_not_an_address aiosmtpd/tests/test_smtp.py::TestResetCommands::test_ehlo aiosmtpd/tests/test_smtp.py::TestResetCommands::test_helo aiosmtpd/tests/test_smtp.py::TestResetCommands::test_rset aiosmtpd/tests/test_smtp.py::TestSMTPWithController::test_bad_encodings aiosmtpd/tests/test_smtp.py::TestSMTPWithController::test_dots_escaped aiosmtpd/tests/test_smtp.py::TestSMTPWithController::test_esmtp_no_size_limit aiosmtpd/tests/test_smtp.py::TestSMTPWithController::test_exception_handler_exception aiosmtpd/tests/test_smtp.py::TestSMTPWithController::test_exception_handler_undescribable aiosmtpd/tests/test_smtp.py::TestSMTPWithController::test_mail_invalid_body aiosmtpd/tests/test_smtp.py::TestSMTPWithController::test_mail_with_compatible_smtputf8 aiosmtpd/tests/test_smtp.py::TestSMTPWithController::test_mail_with_incompatible_smtputf8 aiosmtpd/tests/test_smtp.py::TestSMTPWithController::test_mail_with_size_too_large aiosmtpd/tests/test_smtp.py::TestSMTPWithController::test_mail_with_unrequited_smtputf8 aiosmtpd/tests/test_smtp.py::TestSMTPWithController::test_process_message_error aiosmtpd/tests/test_smtp.py::TestSMTPWithController::test_too_long_message_body aiosmtpd/tests/test_smtp.py::TestSMTPWithController::test_unexpected_errors aiosmtpd/tests/test_smtp.py::TestSMTPWithController::test_unexpected_errors_custom_response aiosmtpd/tests/test_smtp.py::TestSMTPWithController::test_unexpected_errors_unhandled aiosmtpd/tests/test_smtp.py::TestCustomizations::test_custom_greeting aiosmtpd/tests/test_smtp.py::TestCustomizations::test_custom_hostname aiosmtpd/tests/test_smtp.py::TestCustomizations::test_default_greeting aiosmtpd/tests/test_smtp.py::TestCustomizations::test_mail_invalid_body_param aiosmtpd/tests/test_smtp.py::TestClientCrash::test_close_in_command aiosmtpd/tests/test_smtp.py::TestClientCrash::test_close_in_data aiosmtpd/tests/test_smtp.py::TestClientCrash::test_connection_reset_during_DATA aiosmtpd/tests/test_smtp.py::TestClientCrash::test_connection_reset_during_command aiosmtpd/tests/test_smtp.py::TestStrictASCII::test_bad_encoded_param aiosmtpd/tests/test_smtp.py::TestStrictASCII::test_data aiosmtpd/tests/test_smtp.py::TestStrictASCII::test_ehlo aiosmtpd/tests/test_smtp.py::TestStrictASCII::test_mail_param aiosmtpd/tests/test_smtp.py::TestSleepingHandler::test_close_after_helo aiosmtpd/tests/test_starttls.py::TestStartTLS::test_disabled_tls aiosmtpd/tests/test_starttls.py::TestStartTLS::test_failed_handshake aiosmtpd/tests/test_starttls.py::TestStartTLS::test_starttls aiosmtpd/tests/test_starttls.py::TestStartTLS::test_tls_bad_syntax aiosmtpd/tests/test_starttls.py::TestTLSForgetsSessionData::test_forget_ehlo aiosmtpd/tests/test_starttls.py::TestTLSForgetsSessionData::test_forget_mail aiosmtpd/tests/test_starttls.py::TestTLSForgetsSessionData::test_forget_rcpt aiosmtpd/tests/test_starttls.py::TestRequireTLS::test_data_fails aiosmtpd/tests/test_starttls.py::TestRequireTLS::test_ehlo aiosmtpd/tests/test_starttls.py::TestRequireTLS::test_hello_fails aiosmtpd/tests/test_starttls.py::TestRequireTLS::test_help_fails aiosmtpd/tests/test_starttls.py::TestRequireTLS::test_mail_fails aiosmtpd/tests/test_starttls.py::TestRequireTLS::test_rcpt_fails aiosmtpd/tests/test_starttls.py::TestRequireTLS::test_vrfy_fails
aiosmtpd/smtp.py aiosmtpd/docs/NEWS.rst aiosmtpd/lmtp.py aiosmtpd/docs/smtp.rst
aiosmtpd/smtp.py aiosmtpd/docs/NEWS.rst aiosmtpd/lmtp.py aiosmtpd/docs/smtp.rst