@@ -292,40 +292,46 @@ def process_message(self, Peer, From, To, Data, **kwargs):
292292 return _deliver (self , Peer , From , To , Data , ** kwargs )
293293
294294
295- class SMTPOnlyOneRcpt (SMTP ):
296- async def smtp_RCPT (self , arg ):
297- if self .envelope .rcpt_tos :
298- await self .push (SMTP_MULTIPLE_RCPTS_ERROR )
299- else :
300- await super ().smtp_RCPT (arg )
301-
302-
303295class SMTPHandler :
304296 def __init__ (self , executor = None ):
305297 self .executor = executor
306298
307299 async def handle_DATA (self , server , session , envelope ):
308- status = await server .loop .run_in_executor (self .executor , partial (
309- _deliver ,
310- self ,
311- session .peer ,
312- envelope .mail_from ,
313- envelope .rcpt_tos [0 ],
314- envelope .content ,
315- ))
316- return status or "250 Ok"
300+ try :
301+ status = await server .loop .run_in_executor (self .executor , partial (
302+ self .queue .queue .push ,
303+ envolope .content ,
304+ session .peer ,
305+ envolope .mail_from ,
306+ envolope .rcpt_tos ,
307+ ))
308+ status = "250 Ok"
309+ except Exception :
310+ logging .exception ("Raised exception while trying to push to Queue: %r, Peer: %r, From: %r, To: %r" )
311+ status = "550 Server error"
312+ return status
317313
318314
319315class AsyncSMTPReceiver (Controller ):
320316 """Receives emails and hands it to the Router for further processing."""
321- def __init__ (self , handler = None , ** kwargs ):
317+ def __init__ (self , handler = None , queue = None , ** kwargs ):
322318 if handler is None :
323319 handler = SMTPHandler ()
320+ if queue is None :
321+ queue = QueueReceiver (queue .QueueWithMetadata (IN_QUEUE ))
322+ self .queue = queue
324323 super ().__init__ (handler , ** kwargs )
325324
326325 def factory (self ):
327- # TODO implement a queue
328- return SMTPOnlyOneRcpt (self .handler , enable_SMTPUTF8 = self .enable_SMTPUTF8 , ident = ROUTER_VERSION_STRING )
326+ return SMTP (self .handler , enable_SMTPUTF8 = self .enable_SMTPUTF8 , ident = ROUTER_VERSION_STRING )
327+
328+ def start (self ):
329+ super ().start ()
330+ self .queue .start ()
331+
332+ def stop (self ):
333+ super ().stop ()
334+ self .queue .stop ()
329335
330336
331337class LMTPHandler :
@@ -340,7 +346,8 @@ async def handle_DATA(self, server, session, envelope):
340346 self ,
341347 session .peer ,
342348 envelope .mail_from ,
343- rcpt , envelope .content ,
349+ rcpt ,
350+ envelope .content ,
344351 ))
345352 statuses .append (status or "250 Ok" )
346353 return "\r \n " .join (statuses )
@@ -389,20 +396,25 @@ class QueueReceiver:
389396 same way otherwise.
390397 """
391398
392- def __init__ (self , queue_dir , sleep = 10 , size_limit = 0 , oversize_dir = None , workers = 10 ):
399+ def __init__ (self , queue , sleep = 10 , size_limit = 0 , oversize_dir = None , workers = 10 ):
393400 """
394401 The router should be fully configured and ready to work, the queue_dir
395402 can be a fully qualified path or relative. The option workers dictates
396403 how many threads are started to process messages. Consider adding
397404 ``@nolocking`` to your handlers if you are able to.
398405 """
399- self .queue = queue .Queue (queue_dir , pop_limit = size_limit ,
400- oversize_dir = oversize_dir )
406+ if isinstance (queue , str ):
407+ self .queue = queue .Queue (queue , pop_limit = size_limit ,
408+ oversize_dir = oversize_dir )
409+ else :
410+ self .queue = queue
401411 self .sleep = sleep
402412
403413 # Pool is from multiprocess.dummy which uses threads rather than processes
404414 self .workers = Pool (workers )
405415
416+ self ._running = True
417+
406418 def start (self , one_shot = False ):
407419 """
408420 Start simply loops indefinitely sleeping and pulling messages
@@ -412,25 +424,32 @@ def start(self, one_shot=False):
412424 """
413425
414426 logging .info ("Queue receiver started on queue dir %s" , self .queue .dir )
415- logging .debug ("Sleeping for %d seconds..." , self .sleep )
416-
417- # if there are no messages left in the maildir and this a one-shot, the
418- # while loop terminates
419- while not (len (self .queue ) == 0 and one_shot ):
420- # if there's nothing in the queue, take a break
421- if len (self .queue ) == 0 :
422- time .sleep (self .sleep )
423- continue
424427
425- try :
426- key , msg = self .queue .pop ()
427- except KeyError :
428- logging .debug ("Could not find message in Queue" )
429- continue
430-
431- logging .debug ("Pulled message with key: %r off" , key )
432- self .workers .apply_async (self .process_message , args = (msg ,))
428+ def _run ()
429+ while self ._running :
430+ # if there's nothing in the queue, take a break
431+ if len (self .queue ) == 0 :
432+ if one_shot :
433+ break
434+ else :
435+ logging .debug ("Sleeping for %d seconds..." , self .sleep )
436+ time .sleep (self .sleep )
437+ continue
438+
439+ try :
440+ key , msg = self .queue .pop ()
441+ except KeyError :
442+ logging .debug ("Could not find message in Queue" )
443+ continue
444+
445+ logging .debug ("Pulled message with key: %r off" , key )
446+ self .workers .apply_async (self .process_message , args = (msg ,))
447+ self .main_thread = threading .Thread (target = _run )
448+ self .main_thread .start ()
433449
450+ def stop (self ):
451+ self ._running = False
452+ self .main_thread .join ()
434453 self .workers .close ()
435454 self .workers .join ()
436455
@@ -441,12 +460,13 @@ def process_message(self, msg):
441460 """
442461
443462 try :
444- logging .debug ("Message received from Peer: %r, From: %r, to To %r." , msg .Peer , msg .From , msg .To )
463+ logging .debug ("Message received from Queue: %r, Peer: %r, From: %r, to To %r." ,
464+ self .queue , msg .Peer , msg .From , msg .To )
445465 routing .Router .deliver (msg )
446466 except SMTPError as err :
447467 logging .exception ("Raising SMTPError when running in a QueueReceiver is unsupported." )
448468 undeliverable_message (msg .Data , err .message )
449469 except Exception :
450- logging .exception ("Exception while processing message from Peer: "
451- "%r, From: %r, to To %r." , msg .Peer , msg .From , msg .To )
470+ logging .exception ("Exception while processing message from Queue: %r, Peer: "
471+ "%r, From: %r, to To %r." , self . queue , msg .Peer , msg .From , msg .To )
452472 undeliverable_message (msg .Data , "Router failed to catch exception." )
0 commit comments