[Zope3-checkins] CVS: Zope3/src/zope/app/mail - meta.zcml:1.1.14.2 metaconfigure.py:1.2.2.2 service.py:1.2.2.2
Albertas Agejevas
alga@codeworks.lt
Mon, 26 May 2003 14:26:20 -0400
Update of /cvs-repository/Zope3/src/zope/app/mail
In directory cvs.zope.org:/tmp/cvs-serv4417
Modified Files:
Tag: cw-mail-branch
meta.zcml metaconfigure.py service.py
Log Message:
ZCML directives for the mailers.
A thread for queued mail delivery.
=== Zope3/src/zope/app/mail/meta.zcml 1.1.14.1 => 1.1.14.2 ===
--- Zope3/src/zope/app/mail/meta.zcml:1.1.14.1 Thu May 22 04:51:40 2003
+++ Zope3/src/zope/app/mail/meta.zcml Mon May 26 14:25:49 2003
@@ -28,6 +28,12 @@
</description>
</attribute>
+ <attribute name="mailer" required="yes">
+ <description>
+ The name of the mailer used by this service.
+ </description>
+ </attribute>
+
</directive>
<directive name="directService" handler=".metaconfigure.directService">
@@ -58,51 +64,64 @@
</directive>
- <!-- example of a mailer directive
+ <directive name="sendmailMailer" handler=".metaconfigure.sendmailMailer">
- <directive name="smtp" handler=".metaconfigure.smtp">
+ <description>
+ Registers a new Sendmail mailer.
+ </description>
+
+ <attribute name="name" required="yes">
+ <description>
+ Name of the mailer.
+ </description>
+ </attribute>
+
+ <attribute name="command" required="no">
+ <description>
+ A template command for sending out mail, containing %(from)s
+ and %(to)s for respective addresses.
+ </description>
+ </attribute>
+
+ </directive>
+
+ <directive name="smtpMailer" handler=".metaconfigure.smtpMailer">
<description>
Registers a new SMTP mailer.
</description>
- <attribute name="id" required="yes">
+ <attribute name="name" required="yes">
<description>
- ID of the mailer.
+ Name of the mailer.
</description>
</attribute>
<attribute name="hostname" required="no">
<description>
- Name of the server that is used to send the mail. Default is set to
- 'localhost'.
+ Hostname of the SMTP host.
</description>
</attribute>
<attribute name="port" required="no">
<description>
- Port on the server that is used to send the mail. Default is set to
- to the standard port '25'.
+ Port of the SMTP server.
</description>
</attribute>
<attribute name="username" required="no">
<description>
- Some SMTP servers support authentication. If no username is given,
- then the Mail Service will not try to use authentication.
+ A username for SMTP AUTH.
</description>
</attribute>
<attribute name="password" required="no">
<description>
- Password that is used for authentication. Makes only sense in
- combination with username.
+ A password for SMTP AUTH.
</description>
</attribute>
</directive>
-
- -->
</directives>
=== Zope3/src/zope/app/mail/metaconfigure.py 1.2.2.1 => 1.2.2.2 ===
--- Zope3/src/zope/app/mail/metaconfigure.py:1.2.2.1 Thu May 22 04:51:40 2003
+++ Zope3/src/zope/app/mail/metaconfigure.py Mon May 26 14:25:49 2003
@@ -15,39 +15,71 @@
$Id$
"""
+
from zope.component import getService
from zope.configuration.action import Action
from zope.app.component.metaconfigure import provideService
from zope.app.mail.service import QueuedMailService, DirectMailService
+from zope.app.mail.service import QueueProcessorThread
+from zope.app.mail.mailer import SendmailMailer, SMTPMailer
-
-def queuedService(_context, permission, queuePath, name="Mail"):
+def queuedService(_context, permission, queuePath, mailer, name="Mail"):
# XXX what if queuePath is relative? I'd like to make it absolute here,
# but should it be relative to $CWD or $INSTANCE_HOME (if there is one
# in Zope 3)?
- component = QueuedMailService(queuePath)
+
+ def createQueuedService():
+ component = QueuedMailService(queuePath)
+ provideService(name, component, permission)
+
+ thread = QueueProcessorThread()
+ thread.setMailer(queryMailer(mailer))
+ thread.setQueuePath(queuePath)
+ thread.setDaemon(True)
+ thread.start()
+
return [
Action(
discriminator = ('service', name),
- callable = provideService,
- args = (name, component, permission),
+ callable = createQueuedService,
+ args = (),
)
]
def directService(_context, permission, mailer, name="Mail"):
- mailer_component = queryMailer(mailer)
- if mailer_component is None:
- raise ConfigurationError("Mailer %r is not defined" % mailer)
- component = DirectMailService(mailer_component)
+
+ def makeService():
+ mailer_component = queryMailer(mailer)
+ if mailer_component is None:
+ raise ConfigurationError("Mailer %r is not defined" % mailer)
+ component = DirectMailService(mailer_component)
+ provideService(name, component, permission)
+
return [
Action(
discriminator = ('service', name),
- callable = provideService,
- args = (name, component, permission),
+ callable = makeService,
+ args = (),
)
]
+
+def sendmailMailer(_context, name, command):
+ return [Action(discriminator=('mailer', name),
+ callable=provideMailer,
+ args=(name, SendmailMailer(command)),)
+ ]
+
+
+def smtpMailer(_context, name, hostname="localhost", port="25",
+ username=None, password=None):
+ return [Action(discriminator=('mailer', name),
+ callable=provideMailer,
+ args=(name, SMTPMailer(hostname, port,
+ username, password)),)
+ ]
+
# Example of mailer configuration:
#
# def smtp(_context, id, hostname, port):
@@ -65,6 +97,7 @@
mailerRegistry = {}
queryMailer = mailerRegistry.get
provideMailer = mailerRegistry.__setitem__
+
# Register our cleanup with Testing.CleanUp to make writing unit tests simpler.
try:
=== Zope3/src/zope/app/mail/service.py 1.2.2.1 => 1.2.2.2 ===
--- Zope3/src/zope/app/mail/service.py:1.2.2.1 Thu May 22 04:51:40 2003
+++ Zope3/src/zope/app/mail/service.py Mon May 26 14:25:49 2003
@@ -16,11 +16,15 @@
$Id$
"""
import rfc822
+import threading
+import os.path
+from os import listdir
from cStringIO import StringIO
from random import randrange
from time import strftime
from socket import gethostname
from os import getpid
+from time import sleep
from zope.interface import implements
from zope.app.interfaces.mail import IDirectMailService, IQueuedMailService
from zope.app.mail.maildir import Maildir
@@ -102,5 +106,70 @@
def createDataManager(self, fromaddr, toaddrs, message):
maildir = Maildir(self.queuePath, True)
msg = maildir.newMessage()
+ msg.write('X-Zope-From: %s\n' % fromaddr)
+ msg.write('X-Zope-To: %s\n' % ", ".join(toaddrs))
msg.write(message)
return MailDataManager(msg.commit, onAbort=msg.abort)
+
+class QueueProcessorThread(threading.Thread):
+ """This thread is started at configuration time from the
+ mail:queuedService directive handler.
+ """
+
+ def setMaildir(self, maildir):
+ self.maildir = maildir
+
+ def setQueuePath(self, path):
+ self.maildir = Maildir(path)
+
+ def setMailer(self, mailer):
+ self.mailer = mailer
+
+ def _parseMessage(self, message):
+ """Extract fromaddr and toaddrs from the first two lines of
+ the message.
+
+ Returns a fromaddr string, a toaddrs tuple and the message
+ string.
+ """
+
+ fromaddr = ""
+ toaddrs = ()
+ rest = ""
+
+ try:
+ first, second, rest = message.split('\n', 2)
+ except ValueError:
+ return fromaddr, toaddrs, message
+
+ if first.startswith("X-Zope-From: "):
+ i = len("X-Zope-From: ")
+ fromaddr = first[i:]
+
+ if second.startswith("X-Zope-To: "):
+ i = len("X-Zope-To: ")
+ toaddrs = tuple(second[i:].split(", "))
+
+ return fromaddr, toaddrs, rest
+
+ def run(self, forever=True):
+ while True:
+ for message in self.maildir:
+ try:
+
+ fromaddr, toaddrs, message = self._parseMessage(message)
+ self.mailer.send(fromaddr, toaddrs, message)
+ # XXX add log reporting
+ # Blanket except because we don't want this thread to ever die
+ except:
+ from traceback import print_exc
+ print_exc()
+ # XXX maybe throw away erroring messages here?
+ # XXX add log reporting
+ pass
+ else:
+ sleep(3)
+
+ # A testing plug
+ if not forever:
+ break