diff --git a/MANIFEST.in b/MANIFEST.in
index 1b19070..6c44541 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -1,4 +1,4 @@
 include *.py MANIFEST.in
 global-include *.txt *.rst *.ini *.yml *.cfg *.crt *.key
-exclude .gitignore
+global-exclude .gitignore
 prune build
diff --git a/aiosmtpd/smtp.py b/aiosmtpd/smtp.py
index b790785..dfdbcb5 100644
--- a/aiosmtpd/smtp.py
+++ b/aiosmtpd/smtp.py
@@ -201,12 +201,6 @@ class SMTP(asyncio.StreamReaderProtocol):
             try:
                 line = await self._reader.readline()
                 log.debug('_handle_client readline: %s', line)
-            except (ConnectionResetError, asyncio.CancelledError) as error:
-                # The connection got reset during the DATA command.
-                log.info('Connection lost during _handle_client()')
-                self.connection_lost(error)
-                return
-            try:
                 # XXX this rstrip may not completely preserve old behavior.
                 line = line.rstrip(b'\r\n')
                 log.info('%r Data: %s', self.session.peer, line)
@@ -266,6 +260,13 @@ class SMTP(asyncio.StreamReaderProtocol):
                         '500 Error: command "%s" not recognized' % command)
                     continue
                 await method(arg)
+            except (ConnectionResetError, asyncio.CancelledError) as error:
+                # The connection got reset during the DATA command.
+                # XXX If handler method raises ConnectionResetError, we should
+                # verify that it was actually self._reader that was reset.
+                log.info('Connection lost during _handle_client()')
+                self.connection_lost(error)
+                return
             except Exception as error:
                 try:
                     status = await self.handle_exception(error)

CancelledError and misbehaving clients handling
I tried to write a RCPT handler that accepts connection from various embedded devices and forwards the email address to an external system. However, as the devices are not proper SMTP clients and their quality varies I need the solution to be pretty robust. While developing it I discovered a problem with the way aoismtpd deals with clients who send data and ignore the response. To reproduce:

sleep.py (simple handler class simulating my handler):

```
import asyncio
from aiosmtpd.handlers import Debugging

class RcptWebhook(Debugging):
    async def handle_RCPT(self, server, session, envelope, address, rcpt_options):
        await asyncio.sleep(10)

        envelope.rcpt_tos.append(address)
        return '250 OK'
```

Run aiosmtpd

    python3 -m aiosmtpd -n -c sleep.RcptWebhook

smtp.txt (sample SMTP session)

```
HELO there
MAIL FROM: somebody@example.com
RCPT TO: anybody@example.com
DATA
test
.
```
(note the is no QUIT in the data)

Send it witch netcat

    nc localhost 8025 < smtp.txt

It sends the content of the file and EOF which causes unhandled CanceledError in aiosmtpd while it is waiting for my sleep handler to finish:
```

INFO:mail.log:Server listening on localhost:8025
INFO:mail.log:Starting asyncio loop
INFO:mail.log:Peer: ('127.0.0.1', 39306)
INFO:mail.log:('127.0.0.1', 39306) handling connection
INFO:mail.log:('127.0.0.1', 39306) Data: b'HELO there'
INFO:mail.log:('127.0.0.1', 39306) Data: b'MAIL FROM: somebody@example.com'
INFO:mail.log:('127.0.0.1', 39306) sender: somebody@example.com
INFO:mail.log:('127.0.0.1', 39306) Data: b'RCPT TO: anybody@example.com'
INFO:mail.log:('127.0.0.1', 39306) EOF received
ERROR:mail.log:SMTP session exception
Traceback (most recent call last):
  File "/usr/local/lib/python3.5/dist-packages/aiosmtpd/smtp.py", line 276, in _handle_client
    yield from method(arg)
  File "/usr/local/lib/python3.5/dist-packages/aiosmtpd/smtp.py", line 582, in smtp_RCPT
    'RCPT', address, rcpt_options)
  File "/usr/local/lib/python3.5/dist-packages/aiosmtpd/smtp.py", line 116, in _call_handler_hook
    status = yield from hook(self, self.session, self.envelope, *args)
  File "/home/vaclav/src/smtp-events-receiver/sleep.py", line 6, in handle_RCPT
    await asyncio.sleep(10)
  File "/usr/lib/python3.5/asyncio/tasks.py", line 516, in sleep
    return (yield from future)
  File "/usr/lib/python3.5/asyncio/futures.py", line 361, in __iter__
    yield self  # This tells Task to wait for completion.
  File "/usr/lib/python3.5/asyncio/tasks.py", line 296, in _wakeup
    future.result()
  File "/usr/lib/python3.5/asyncio/futures.py", line 266, in result
    raise CancelledError
concurrent.futures._base.CancelledError
INFO:mail.log:('127.0.0.1', 39306) Data: b'DATA'
INFO:mail.log:('127.0.0.1', 39306) Data: b'test'
INFO:mail.log:('127.0.0.1', 39306) Data: b'.'
INFO:mail.log:('127.0.0.1', 39306) Data: b''
INFO:mail.log:('127.0.0.1', 39306) Data: b''
INFO:mail.log:('127.0.0.1', 39306) Data: b''
INFO:mail.log:('127.0.0.1', 39306) Data: b''
...
```
aiosmtpd is now 100% busy on CPU and keeps printing "500 Error: bad syntax" to the netcat. It ignores KeyboardInterrupt and to quit it I need to terminate netcat with ^C which stops aiosmtp with "Connection lost".

I think aiosmtpd should handle this more gracefully as you don't want your server to get stuck on CPU due to misbehaving client. I see in RFC 5321 that the server must not close the connection until QUIT from the client so I'm not sure what is the proper way of handling EOF though.
diff --git a/aiosmtpd/tests/test_smtp.py b/aiosmtpd/tests/test_smtp.py
index 8a7ba7d..ab52cf6 100644
--- a/aiosmtpd/tests/test_smtp.py
+++ b/aiosmtpd/tests/test_smtp.py
@@ -124,6 +124,13 @@ class ErrorController(Controller):
         return ErrorSMTP(self.handler)
 
 
+class SleepingHeloHandler:
+    async def handle_HELO(self, server, session, envelope, hostname):
+        await asyncio.sleep(0.01)
+        session.host_name = hostname
+        return '250 {}'.format(server.hostname)
+
+
 class TestProtocol(unittest.TestCase):
     def setUp(self):
         self.transport = Mock()
@@ -1135,3 +1142,17 @@ Testing\xFF
 """)
             self.assertEqual(cm.exception.smtp_code, 500)
             self.assertIn(b'Error: strict ASCII mode', cm.exception.smtp_error)
+
+
+class TestSleepingHandler(unittest.TestCase):
+    def setUp(self):
+        controller = NoDecodeController(SleepingHeloHandler())
+        controller.start()
+        self.addCleanup(controller.stop)
+        self.address = (controller.hostname, controller.port)
+
+    def test_close_after_helo(self):
+        with SMTP(*self.address) as client:
+            client.send('HELO example.com\r\n')
+            client.sock.shutdown(socket.SHUT_WR)
+            self.assertRaises(SMTPServerDisconnected, client.getreply)

pip install -e .
parse_log_pytest
pytest
pytest
3.6
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
-e git+https://github.com/aio-libs/aiosmtpd.git@a046b08ac5a697718268c30394bcd45586074be0#egg=aiosmtpd
atpublic==2.3
attrs @ file:///opt/conda/conda-bld/attrs_1642510447205/work
certifi==2021.5.30
importlib-metadata @ file:///tmp/build/80754af9/importlib-metadata_1631916693255/work
iniconfig @ file:///home/linux1/recipes/ci/iniconfig_1610983019677/work
more-itertools @ file:///tmp/build/80754af9/more-itertools_1637733554872/work
packaging @ file:///tmp/build/80754af9/packaging_1637314298585/work
pluggy @ file:///tmp/build/80754af9/pluggy_1615976315926/work
py @ file:///opt/conda/conda-bld/py_1644396412707/work
pyparsing @ file:///tmp/build/80754af9/pyparsing_1635766073266/work
pytest==6.2.4
toml @ file:///tmp/build/80754af9/toml_1616166611790/work
typing_extensions @ file:///opt/conda/conda-bld/typing_extensions_1647553014482/work
zipp @ file:///tmp/build/80754af9/zipp_1633618647012/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
  - attrs=21.4.0=pyhd3eb1b0_0
  - ca-certificates=2025.2.25=h06a4308_0
  - certifi=2021.5.30=py36h06a4308_0
  - importlib-metadata=4.8.1=py36h06a4308_0
  - importlib_metadata=4.8.1=hd3eb1b0_0
  - iniconfig=1.1.1=pyhd3eb1b0_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.3=he6710b0_2
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - more-itertools=8.12.0=pyhd3eb1b0_0
  - ncurses=6.4=h6a678d5_0
  - openssl=1.1.1w=h7f8727e_0
  - packaging=21.3=pyhd3eb1b0_0
  - pip=21.2.2=py36h06a4308_0
  - pluggy=0.13.1=py36h06a4308_0
  - py=1.11.0=pyhd3eb1b0_0
  - pyparsing=3.0.4=pyhd3eb1b0_0
  - pytest=6.2.4=py36h06a4308_2
  - python=3.6.13=h12debd9_1
  - readline=8.2=h5eee18b_0
  - setuptools=58.0.4=py36h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - toml=0.10.2=pyhd3eb1b0_0
  - typing_extensions=4.1.1=pyh06a4308_0
  - wheel=0.37.1=pyhd3eb1b0_0
  - xz=5.6.4=h5eee18b_1
  - zipp=3.6.0=pyhd3eb1b0_0
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - atpublic==2.3
prefix: /opt/conda/envs/aiosmtpd

aiosmtpd/tests/test_smtp.py::TestSleepingHandler::test_close_after_helo
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 aiosmtpd/tests/test_smtp.py::TestSMTP::test_help_bad_arg 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_noop 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/smtp.py MANIFEST.in
aiosmtpd/smtp.py MANIFEST.in