On Mon, 29 Nov 2004, Mika Bostrom wrote:
On Fri, 26 Nov 2004, Jp Calderone wrote:
ESMTP will call getMessageDelivery on its deliveryFactory attribute, now that it isn't None. On the object it returns, it will call receivedHeader, validateFrom, and validateTo. And on the object returned by calling the object returned by validateTo, it will pass the contents of the message being delivered, letting you relay it wherever is appropriate.
This part felt a little like black magic, [...]
This part still feels a little voodooish, but I have figured out at least something. I don't need to use SMTPClient at all; just use smtp.sendmail() to forward the mail to next point of entry. However, since my intention was to multiplex outgoing mails to different scanning engines, just forwarding blindly is not exactly productive. Let's assume I have 5 or 6 different scanning engines running in localhost, all of them accepting inbound mail via SMTP in irregular ports. smtp.sendmail() uses the standard port, so I came up with this: [--snip--] diff -uN twisted/protocols/smtp.py twisted/protocols/smtp.py.new --- twisted/protocols/smtp.py 2004-04-09 06:06:54.000000000 +0300 +++ twisted/protocols/smtp.py.new 2004-11-29 14:16:01.000000000 +0200 @@ -1318,7 +1318,7 @@ p.factory = self return p -def sendmail(smtphost, from_addr, to_addrs, msg): +def sendmail(smtphost, from_addr, to_addrs, msg, port=25): """Send an email This interface is intended to be a direct replacement for @@ -1338,6 +1338,9 @@ to pass an email.Message directly, but doing the conversion with email.Generator manually will give you more control over the process). + @param port: The port to connect to on smtphost. If none is + provided, standard 25 is used. + @rtype: L{Deferred} @returns: A L{Deferred}, its callback will be called if a message is sent @@ -1354,7 +1357,7 @@ d = defer.Deferred() factory = SMTPSenderFactory(from_addr, to_addrs, msg, d) - reactor.connectTCP(smtphost, 25, factory) + reactor.connectTCP(smtphost, port, factory) return d [--snap--] It should allow me to inject the mail to any destination, host:port not being a hindrance. It should also retain compatibility with all existing scripts that use smtp.sendmail() Now, to _use_ that, I came up with something like this: (referring to previous mails with complete code) [--schnippel--] class RelayMessage: __implements__ = smtp.IMessage def __init__(self): # Clear before adding util.connup() self.msg = [] def lineReceived(self, line): self.msg.append(line) def eomReceived(self): # Add message to outgoing queue # XXX Does not work yet, address information needs to be dug out dd = smtp.sendmail('localhost', self._from, self._to, self.msg, 10050) dd.addCallBack(util.conndown) # When mail has been passed, update counter # Return a success return defer.succeed('Tally ho.') def connectionLost(self): # If connection is ever lost in this stage, it is a delivery error self.conndown() self.msg = [] [--schnappel--] The problem here is naturally that to use smtp.sendmail() I need to extract addresses for sender and recipient(s). I *know* they are there somewhere, but after experimentation and minor excavation I feel utterly lost. smtp.SMTP.{_cbFromValidate,_cbToValidate} routines place these strings in SMTP._from and SMTP._to, but I haven't been able to dig them out so I could use them. This feels like the most straightforward way of doing this and as such, one I would like to implement. There must be some clean path from smtp.IMessage interfaces to access items in a smtp.STMP instance. If anyone feels generous and knowledgeable, I for one would gladly welcome the hint as to how this is done. For what it's worth, if the patch really works I'll naturally try to submit it for inclusion. -- Mika Boström \-/ "World peace will be achieved Bostik@stinghorn.com X when the last man has killed Software slave /-\ the second-to-last." -anon?