I have implemented a basic SMTPServer which works great but I'm encountering an issue and I don't know how I can fix it.
When checking the file descriptors opened for the $PID of the process running my script (ls -l /proc/$PID/fd/ | grep "socket:" | wc -l), the quantity of file descriptors keep increasing.
Since I'm filtering by "socket:", this clearly some sockets left open, certainly because some mail providers doesn't quit clearly.
I've tested locally some Python scripts connecting to that SMTPServer code, and even if I don't close the connection, when the client process stops, the client close the connection, and the file descriptor is removed.
I thought about implementing a timeout for waiting, or restarting the process every N connections, but these are just bad patches for a bigger problem.
Do you know where that would come from?
For information, my process_message wrapper is surounded by a
try:
# ...
except:
return '450 Please try again later"
So an exception coming from my code should be well handled.
Here's my code (simplified):
class MyMXServer(SMTPServer):
def __init__(self, host='127.0.0.1', port=25):
self.srs = SRS.new(os.getenv('SRS_KEY', 'some passwd'))
return SMTPServer.__init__(self, (host, port), None)
def process_message(self, greeting, peer, mailfrom, recipients, data, **kwargs):
try:
return self._process_message(greeting, peer, mailfrom, recipients, data, **kwargs)
except:
logging.getLogger('err').exception('[EXCEPTION]')
return '450 Please try again later.'
def _process_message(self, greeting, peer, mailfrom, recipients, data, **kwargs):
# Various things like checking DNSBL, SPF, Spam, etc
Hard to answer without seeing your code. However, you've already implemented the initial components of exception handling.
elsemay not be necessary, but it sounds like afinallyclause is a requirement in this situation. Finish the block to ensure the socket is closed: