Log message for revision 78983: added support for asynchronous mail delivery using zope.sendmail queue mechanism
Changed: U Zope/trunk/doc/CHANGES.txt U Zope/trunk/lib/python/Products/MailHost/MailHost.py U Zope/trunk/lib/python/Products/MailHost/dtml/manageMailHost.dtml -=- Modified: Zope/trunk/doc/CHANGES.txt =================================================================== --- Zope/trunk/doc/CHANGES.txt 2007-08-19 07:24:24 UTC (rev 78982) +++ Zope/trunk/doc/CHANGES.txt 2007-08-19 09:05:12 UTC (rev 78983) @@ -66,7 +66,11 @@ - MailHost: now uses zope.sendmail for delivering the mail providing integration with the Zope transaction system (avoids sending dupe - emails in case of conflict errors) + emails in case of conflict errors). In addition MailHost now provides + support for asynchronous mail delivery. The 'Use queue' configuration + option will create a mail queue on the filesystem (under + 'Queue directory') and start a queue thread that checks the queue every + three seconds. This decouples the sending of mail from its delivery. - integrated ZODB 3.8 Modified: Zope/trunk/lib/python/Products/MailHost/MailHost.py =================================================================== --- Zope/trunk/lib/python/Products/MailHost/MailHost.py 2007-08-19 07:24:24 UTC (rev 78982) +++ Zope/trunk/lib/python/Products/MailHost/MailHost.py 2007-08-19 09:05:12 UTC (rev 78983) @@ -17,6 +17,7 @@ import mimetools import rfc822 +import time from cStringIO import StringIO import Acquisition @@ -31,10 +32,13 @@ from zope.interface import implements from zope.sendmail.mailer import SMTPMailer -from zope.sendmail.delivery import DirectMailDelivery +from zope.sendmail.delivery import DirectMailDelivery, QueuedMailDelivery, \ + QueueProcessorThread from interfaces import IMailHost +queue_threads = {} + class MailHostError(Exception): pass @@ -64,6 +68,8 @@ security = ClassSecurityInfo() smtp_uid='' # Class attributes for smooth upgrades smtp_pwd='' + smtp_queue = False + smtp_queue_directory = '/tmp' timeout=1.0 @@ -79,7 +85,7 @@ def __init__( self, id='', title='', smtp_host='localhost', smtp_port=25, - smtp_uid='', smtp_pwd=''): + smtp_uid='', smtp_pwd='', smtp_queue=False, smtp_queue_directory='/tmp'): """Initialize a new MailHost instance """ self.id = id self.title = title @@ -87,6 +93,8 @@ self.smtp_port = int(smtp_port) self.smtp_uid = smtp_uid self.smtp_pwd = smtp_pwd + self.smtp_queue = smtp_queue + self.smtp_queue_directory = smtp_queue_directory # staying for now... (backwards compatibility) @@ -95,7 +103,9 @@ self.smtp_port=smtp_port security.declareProtected(change_configuration, 'manage_makeChanges') - def manage_makeChanges(self,title,smtp_host,smtp_port,smtp_uid='',smtp_pwd='', REQUEST=None): + def manage_makeChanges(self,title,smtp_host,smtp_port,smtp_uid='',smtp_pwd='', + smtp_queue=False, smtp_queue_directory='/tmp', + REQUEST=None): 'make the changes' title=str(title) @@ -107,6 +117,17 @@ self.smtp_port=smtp_port self.smtp_uid = smtp_uid self.smtp_pwd = smtp_pwd + self.smtp_queue = smtp_queue + self.smtp_queue_directory = smtp_queue_directory + + # restart queue processor thread + if self.smtp_queue: + self._stopQueueProcessorThread() + self._startQueueProcessorThread() + else: + self._stopQueueProcessorThread() + + if REQUEST is not None: msg = 'MailHost %s updated' % self.id return self.manage_main( self @@ -153,18 +174,56 @@ self._send( mfrom, mto, body ) + + def _makeMailer(self): + """ Create a SMTPMailer """ + return SMTPMailer(self.smtp_host, + int(self.smtp_port), + self.smtp_uid or None, + self.smtp_pwd or None + ) + + def _stopQueueProcessorThread(self): + """ Stop thread for processing the mail queue """ + + path = self.absolute_url(1) + if queue_threads.has_key(path): + thread = queue_threads[path] + thread.stop() + while thread.isAlive(): + # wait until thread is really dead + time.sleep(0.1) + + + def _startQueueProcessorThread(self): + """ Start thread for processing the mail queue """ + + path = self.absolute_url(1) + + if not queue_threads.has_key(path): + + thread = QueueProcessorThread() + thread.setMailer(self._makeMailer()) + thread.setQueuePath(self.smtp_queue_directory) + thread.start() + queue_threads[path] = thread + + security.declarePrivate('_send') def _send(self, mfrom, mto, messageText): """ Send the message """ - mailer = SMTPMailer(self.smtp_host, - int(self.smtp_port), - self.smtp_uid or None, - self.smtp_pwd or None - ) - delivery = DirectMailDelivery(mailer) - delivery.send(mfrom, mto, messageText) + if self.smtp_queue: + + # Start queue processor thread, if necessary + self._startQueueProcessorThread() + delivery = QueuedMailDelivery(self.smtp_queue_directory) + else: + delivery = DirectMailDelivery(self._makeMailer()) + + delivery.send(mfrom, mto, messageText) + InitializeClass(MailBase) Modified: Zope/trunk/lib/python/Products/MailHost/dtml/manageMailHost.dtml =================================================================== --- Zope/trunk/lib/python/Products/MailHost/dtml/manageMailHost.dtml 2007-08-19 07:24:24 UTC (rev 78982) +++ Zope/trunk/lib/python/Products/MailHost/dtml/manageMailHost.dtml 2007-08-19 09:05:12 UTC (rev 78983) @@ -51,7 +51,7 @@ <tr> <td align="left" valign="top"> <div class="form-label"> - Authentication ID: + Username: </div> </td> <td align="left" valign="top"> @@ -72,8 +72,31 @@ </tr> <tr> <td align="left" valign="top"> + <div class="form-label"> + Use queue + </div> </td> <td align="left" valign="top"> + <input type="checkbox" name="smtp_queue:boolean" value="1" + <dtml-if "smtp_queue">checked</dtml-if> + + </td> + </tr> + <tr> + <td align="left" valign="top"> + <div class="form-label"> + Queue directory: + </div> + </td> + <td align="left" valign="top"> + <input type="text" name="smtp_queue_directory" size="30" + value="&dtml-smtp_queue_directory;"/> + </td> + </tr> + <tr> + <td align="left" valign="top"> + </td> + <td align="left" valign="top"> <div class="form-element"> <input class="form-element" type="submit" name="submit" value="Save Changes" /> _______________________________________________ Zope-Checkins maillist - Zope-Checkins@zope.org http://mail.zope.org/mailman/listinfo/zope-checkins