You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
After upgrading from version 1.2.2 to 1.2.4 we receive the following error when trying to start the controller:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/lib/python3.6/site-packages/aiosmtpd/controller.py", line 165, in start
raise RuntimeError("Unknown Error, failed to init SMTP server")
RuntimeError: Unknown Error, failed to init SMTP server
This error can even be triggered by running the sample code from the documentation:
After executing "controller.start()" the RuntimeError from above appears.
Python version is 3.6.8
OS is Red Hat 7.9
aiosmtpd was installed with pip3. After downgrading via "sudo pip3 install aiosmtpd=1.2.2" everything works again and aiosmtpd receives and processes emails without problems.
Ok I believe we get one step further. The following tests where performed with aiosmtpd==1.3.0:
Output of the code you requested to be run:
$ python3
Python 3.6.8 (default, Aug 13 2020, 07:46:32)
[GCC 4.8.5 20150623 (Red Hat 4.8.5-39)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from aiosmtpd.controller import Controller
>>> from aiosmtpd.handlers import Sink
>>> cont = Controller(Sink())
>>> s1 = cont.factory()
>>> print(repr(s1))
<aiosmtpd.smtp.SMTP object at 0x7fda740d0f28>
>>> print(s1.hostname)
myhostname...
Then I modified /usr/local/lib/python3.6/site-packages/aiosmtpd/controller.py and put some debug statements at the beginning of factory() and _factory_invoker().
>>> class ExampleHandler:
... async def handle_RCPT(self, server, session, envelope, address, rcpt_options):
... return "250 OK"
...
>>> from aiosmtpd.controller import Controller
>>> cont = Controller(ExampleHandler())
>>> cont.factory()
DEBUG: In factory()
<aiosmtpd.smtp.SMTP object at 0x7f7f56cf09b0>
>>> cont._factory_invoker()
DEBUG: In _factory_invoker()
DEBUG: In factory()
<aiosmtpd.smtp.SMTP object at 0x7f7f562d1e10>
As expected executing factory() returns its debug output, whereas executing _factory_invoker() calls both _factory_invoker() as well as factory().
However as you can see below when executing start(), neither the debug output at the beginning of factory() nor of _factory_invoker() appears. I can't tell if this is because _factory_invoker() never gets called, or if it runs asynchronously and its output doesn't reach STDOUT. But I know that if I run the same code on another server, I see the debug lines.
>>> class ExampleHandler:
... async def handle_RCPT(self, server, session, envelope, address, rcpt_options):
... return "250 OK"
...
>>> from aiosmtpd.controller import Controller
>>> cont = Controller(ExampleHandler())
>>> cont.start()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/lib/python3.6/site-packages/aiosmtpd/controller.py", line 181, in start
raise RuntimeError("Unknown Error, failed to init SMTP server")
RuntimeError: Unknown Error, failed to init SMTP server
>>> # No DEBUG output seen
If I explicitely call _factory_invoker() first, then start() doesn't produce a RuntimeError:
At first glance, it seems that on the failing machine, Python's threading library works differently.
Yet your last experiment, in which you "pre-initialize" the SMTP object (because that's what _factory_invoker() actually do), threading works!
For some reasons, the spawned thread seems to be unable to write back to the main thread, and that's why cont.smtpd in the main thread remained None ...
Hmm... I don't have a quick answer for this. Please allow me some time to study this interesting situation.
PS: This "unable to modify main thread's behavior" totally reminds me of how multiprocessing behaves. Not trying to hint about anything, just something that popped into my mind and mildly interesting enough to share....
Unfortunately I don't know enough about Pythons threading to debug this alone.
I added time.sleep(3) to run() before the self.smtpd == None check, but the RuntimeError still appeared. So it doesn't seem to be a timing issue.
Unfortunately I don't know enough about Pythons threading to debug this alone.
I added time.sleep(3) to run() before the self.smtpd == None check, but the RuntimeError still appeared. So it doesn't seem to be a timing issue.
I suddenly have an inspiration:
Within the Controller.run() method, right after this block:
ifself._thread_exceptionisnotNone: # pragma: on-wsl# See comment about WSL1.0 in the _run() methodassertself._threadisnotNone# Stupid LGTM.com; see github/codeql#4918raiseself._thread_exception
can you insert the lines:
ifnotready_event.is_set():
raiseRuntimeError("Server not ready within alotted time.")
(The if statement of the inserted line must be on the same indentation level as the if statement on if self._thread_exception)
It won't fix the problem, but at least we'll get another control point to observe the behavior. If a RuntimeError gets raised there, we can narrow down the problem.
Okay, so at least we know it was not caused by timeout.
Let's add another check point.
In the middle of these lines:
try:
self._testconn()
exceptException:
# We totally don't care of exceptions experienced by _testconn,# which _will_ happen if factory() experienced problems.passifself._thread_exceptionisnotNone:
raiseself._thread_exception
Please add time.sleep(0.2) right before the test for self._thread_exception, so it looks like this:
try:
self._testconn()
exceptException:
# We totally don't care of exceptions experienced by _testconn,# which _will_ happen if factory() experienced problems.passtime.sleep(0.5)
ifself._thread_exceptionisnotNone:
raiseself._thread_exception
We try giving additional time for create_server to finish initialization.
Apparently someone else is running into the same issue, so at least it's not some messed up setting only on my servers.
I added the following to Controller.start(), which is very similar to what I tried in #244 (comment)
try:
self._testconn()
except Exception:
# We totally don't care of exceptions experienced by _testconn,
# which _will_ happen if factory() experienced problems.
pass
time.sleep(0.5)
print("checkpoint2")
However the output is unchanged:
>>> class ExampleHandler:
... async def handle_RCPT(self, server, session, envelope, address, rcpt_options):
... return "250 OK"
...
>>> from aiosmtpd.controller import Controller
>>> cont = Controller(ExampleHandler())
>>> cont.start()
checkpoint2
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/lib/python3.6/site-packages/aiosmtpd/controller.py", line 180, in start
raise RuntimeError("Unknown Error, failed to init SMTP server")
RuntimeError: Unknown Error, failed to init SMTP server
Hello @pepoluan thank you very much! Looks very good, except that on my system the error 97 is thrown:
>>> from aiosmtpd.controller import Controller
>>> cont = Controller(ExampleHandler())
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/lib/python3.6/site-packages/aiosmtpd/controller.py", line 107, in __init__
self.hostname = get_localhost() if hostname is None else hostname
File "/usr/local/lib/python3.6/site-packages/aiosmtpd/controller.py", line 41, in get_localhost
with makesock(AF_INET6, SOCK_STREAM) as sock:
File "/usr/lib64/python3.6/socket.py", line 144, in __init__
_socket.socket.__init__(self, family, type, proto, fileno)
OSError: [Errno 97] Address family not supported by protocol
Errno 97 translates to errno.EAFNOSUPPORT, however get_localhost() is catching errno.EADDRNOTAVAIL. If I replace errno.EADDRNOTAVAIL with errno.EAFNOSUPPORT, version 1.3.1 works!
Hello @pepoluan thank you very much! Looks very good, except that on my system the error 97 is thrown:
>>> from aiosmtpd.controller import Controller
>>> cont = Controller(ExampleHandler())
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/lib/python3.6/site-packages/aiosmtpd/controller.py", line 107, in __init__
self.hostname = get_localhost() if hostname is None else hostname
File "/usr/local/lib/python3.6/site-packages/aiosmtpd/controller.py", line 41, in get_localhost
with makesock(AF_INET6, SOCK_STREAM) as sock:
File "/usr/lib64/python3.6/socket.py", line 144, in __init__
_socket.socket.__init__(self, family, type, proto, fileno)
OSError: [Errno 97] Address family not supported by protocol
Errno 97 translates to errno.EAFNOSUPPORT, however get_localhost() is catching errno.EADDRNOTAVAIL. If I replace errno.EADDRNOTAVAIL with errno.EAFNOSUPPORT, version 1.3.1 works!
Thanks!
Hmm... seems like different errors for different systems? I'll just change the == to in some_set, and push another bugfix tomorrow.
I never received errno 99 (EADDRNOTAVAIL). Only errno 97. Maybe in the environment of @LeoVerto errno 99 was seen?
In my test system I got EADDRNOTAVAIL, that's why the equality test was against EADDRNOTAVAIL.
I've changed it so it's if e.errno in {EADDRNOTAVAIL, EAFNOSUPPORT}, so we'll be good any which way.
Edit: After some thinking, I think the difference is because on my test systems I disabled IPv6 using sysctl, so the IPv6 modules are still loaded in the kernel, hence EADDRNOTAVAIL ("you want IPv6 address? Sure I can give you that but I'm currently on vacation.") Your kernel probably didn't load the IPv6 module at all, thus EAFNOSUPPORT ("You want what? Nobody here provides what you want.")
Hello,
I have similar problem. My project msztolcman/sendria is using aiosmtpd to handle incoming smtp connections. It works fine with aiosmtps 1.2.2, but after upgrade to 1.4.1 I have:
% sendria --db db.sqlite -d -a
2021-03-05T12:36:02.487786Z no PID file specified; runnning in foreground
2021-03-05T12:36:02.487885Z starting Sendria db=/Users/mysz/Projects/sendria/db.sqlite debug=enabled foreground=true pidfile=None
2021-03-05T12:36:02.491769Z DB initialized
2021-03-05T12:36:02.492011Z webhooks disabled
Traceback (most recent call last):
File "/Users/mysz/Projects/sendria/.venv/bin/sendria", line 33, in<module>
sys.exit(load_entry_point('sendria', 'console_scripts', 'sendria')())
File "/Users/mysz/Projects/sendria/sendria/cli.py", line 296, in main
run_sendria_servers(loop, args)
File "/Users/mysz/Projects/sendria/sendria/cli.py", line 176, in run_sendria_servers
smtp.run(args.smtp_ip, args.smtp_port, args.smtp_auth, args.smtp_ident, args.debug)
File "/Users/mysz/Projects/sendria/sendria/smtp.py", line 69, in run
controller.start()
File "/Users/mysz/Projects/sendria/.venv/lib/python3.9/site-packages/aiosmtpd/controller.py", line 225, in start
raise TimeoutError("SMTP server not responding within allotted time")
TimeoutError: SMTP server not responding within allotted time
Hello,
I have similar problem. My project msztolcman/sendria is using aiosmtpd to handle incoming smtp connections. It works fine with aiosmtps 1.2.2, but after upgrade to 1.4.1 I have:
Hi, can you create a new issue instead of replying here?
That way we can actually track which issues have been fixed, and by which PR. Would go a long way towards ease of troubleshooting as we can bisect.
Because this seems to be caused by a different bug from the 1.3.x issues.
Activity
pepoluan commentedon Feb 8, 2021
I've just released 1.3.0, can you try with that?
pepoluan commentedon Feb 8, 2021
TBH I tried checking out 1.2.4 on Ubuntu 18.04, ran the code snippet you gave [simplification from the docs], and I couldn't replicate the error.
Asciinema Recording: https://asciinema.org/a/Fih5rZOm5QGlIboe4JWysSdSX
pepoluan commentedon Feb 9, 2021
Update: I've just spun up a CentOS 7 instance, installed python3, created a new virtualenv, and also cannot replicate the error.
Asciinema Recording: https://asciinema.org/a/6k5vSAI4lX5oyOn2OiwRYZNdM
gnugnug commentedon Feb 9, 2021
Thank you for the quick reply! I tried 1.3.0 but the problem remains:
I tried it on another Red Hat 7.9 server and there the same code works. Is there any way how I can find out what exactly is failing?
pepoluan commentedon Feb 9, 2021
Oookay, that's ... strange.
The lines that raised that exception are these lines.
It's very hard to reach that line, as can be seen in the amount of acrobatics I have to do in the relevant test.
Because even if the
factory()method returnedNone, the_factory_invoker()method should catch that and raise an Exception.But I wonder ...
Can you try this:
gnugnug commentedon Feb 9, 2021
Ok I believe we get one step further. The following tests where performed with aiosmtpd==1.3.0:
Output of the code you requested to be run:
Then I modified /usr/local/lib/python3.6/site-packages/aiosmtpd/controller.py and put some debug statements at the beginning of factory() and _factory_invoker().
As expected executing factory() returns its debug output, whereas executing _factory_invoker() calls both _factory_invoker() as well as factory().
However as you can see below when executing start(), neither the debug output at the beginning of factory() nor of _factory_invoker() appears. I can't tell if this is because _factory_invoker() never gets called, or if it runs asynchronously and its output doesn't reach STDOUT. But I know that if I run the same code on another server, I see the debug lines.
If I explicitely call _factory_invoker() first, then start() doesn't produce a RuntimeError:
pepoluan commentedon Feb 9, 2021
Interesting!
At first glance, it seems that on the failing machine, Python's
threadinglibrary works differently.Yet your last experiment, in which you "pre-initialize" the
SMTPobject (because that's what_factory_invoker()actually do), threading works!For some reasons, the spawned thread seems to be unable to write back to the main thread, and that's why
cont.smtpdin the main thread remainedNone...Hmm... I don't have a quick answer for this. Please allow me some time to study this interesting situation.
PS: This "unable to modify main thread's behavior" totally reminds me of how
multiprocessingbehaves. Not trying to hint about anything, just something that popped into my mind and mildly interesting enough to share....gnugnug commentedon Feb 11, 2021
Unfortunately I don't know enough about Pythons threading to debug this alone.
I added time.sleep(3) to run() before the self.smtpd == None check, but the RuntimeError still appeared. So it doesn't seem to be a timing issue.
pepoluan commentedon Feb 12, 2021
I suddenly have an inspiration:
Within the
Controller.run()method, right after this block:can you insert the lines:
(The
ifstatement of the inserted line must be on the same indentation level as theifstatement onif self._thread_exception)It won't fix the problem, but at least we'll get another control point to observe the behavior. If a RuntimeError gets raised there, we can narrow down the problem.
Test newly-implemented TimeoutError
gnugnug commentedon Feb 15, 2021
Hello @pepoluan
I added the following lines inside of
Controller.start()This resulted in the following output:
So unfortunately still the same error.
pepoluan commentedon Feb 15, 2021
Okay, so at least we know it was not caused by timeout.
Let's add another check point.
In the middle of these lines:
Please add
time.sleep(0.2)right before the test forself._thread_exception, so it looks like this:We try giving additional time for
create_serverto finish initialization.Wait until factory _is_ invoked
Pin aiosmtpd to latest working version
gnugnug commentedon Feb 16, 2021
Apparently someone else is running into the same issue, so at least it's not some messed up setting only on my servers.
I added the following to
Controller.start(), which is very similar to what I tried in #244 (comment)However the output is unchanged:
13 remaining items
Fix Controller Bug on hostname="" or IPv6 not available (PR #248, Issue
pepoluan commentedon Feb 18, 2021
I will release v1.3.1 soon; waiting for GA to validate the squamerging to
masterpepoluan commentedon Feb 18, 2021
Hi @gnugnug & @LeoVerto , I've released 1.3.1 to PyPI.
Would be swell if you can verify it has fixed this issue.
gnugnug commentedon Feb 18, 2021
Hello @pepoluan thank you very much! Looks very good, except that on my system the error 97 is thrown:
Errno 97 translates to errno.EAFNOSUPPORT, however get_localhost() is catching errno.EADDRNOTAVAIL. If I replace errno.EADDRNOTAVAIL with errno.EAFNOSUPPORT, version 1.3.1 works!
pepoluan commentedon Feb 18, 2021
Thanks!
Hmm... seems like different errors for different systems? I'll just change the
==toin some_set, and push another bugfix tomorrow.gnugnug commentedon Feb 18, 2021
I never received errno 99 (EADDRNOTAVAIL). Only errno 97. Maybe in the environment of @LeoVerto errno 99 was seen?
pepoluan commentedon Feb 18, 2021
In my test system I got EADDRNOTAVAIL, that's why the equality test was against EADDRNOTAVAIL.
I've changed it so it's
if e.errno in {EADDRNOTAVAIL, EAFNOSUPPORT}, so we'll be good any which way.Edit: After some thinking, I think the difference is because on my test systems I disabled IPv6 using sysctl, so the IPv6 modules are still loaded in the kernel, hence EADDRNOTAVAIL ("you want IPv6 address? Sure I can give you that but I'm currently on vacation.") Your kernel probably didn't load the IPv6 module at all, thus EAFNOSUPPORT ("You want what? Nobody here provides what you want.")
LeoVerto commentedon Feb 18, 2021
This has fixed the issue for me, thank you so much for the quick debugging and fix, @pepoluan!
msztolcman commentedon Mar 5, 2021
Hello,
I have similar problem. My project msztolcman/sendria is using
aiosmtpdto handle incoming smtp connections. It works fine with aiosmtps 1.2.2, but after upgrade to 1.4.1 I have:pepoluan commentedon Mar 5, 2021
Hi, can you create a new issue instead of replying here?
That way we can actually track which issues have been fixed, and by which PR. Would go a long way towards ease of troubleshooting as we can bisect.
Because this seems to be caused by a different bug from the 1.3.x issues.
msztolcman commentedon Mar 5, 2021
Hi, sure. I was thinking it can be similar one :)
New one opened.