I love the idea of twisted but I think I must have a twisted learning 
disability, as I have gotten nowhere in what ought to be a simple matter. 

I need to send out emails to small groups from my apache server running a 
python cgi using mod_python, but my hosting service doesn't have a MTA. Instead 
of learning how to install and configure exim I thought I would use twisted to 
make a simple mail client. I started with the tutorial example that appears at:

http://twistedmatrix.com/projects/mail/documentation/tutorial/smtpclient/smtpclient.html

(.... is indenting)
============ tutorial code ================
import StringIO
from twisted.application import service
application = service.Application("SMTP Client Tutorial")
from twisted.application import internet
from twisted.internet import protocol
from twisted.internet import defer
from twisted.mail import smtp, relaymanager
class SMTPTutorialClient(smtp.ESMTPClient):
....mailFrom = "tutorial_sen...@example.com"
....mailTo = "tutorial_recipi...@example.net"
....mailData = '''\
Date: Fri, 6 Feb 2004 10:14:39 -0800
From: Tutorial Guy <tutorial_sen...@example.com>
To: Tutorial Gal <tutorial_recipi...@example.net>
Subject: Tutorate!

Hello, how are you, goodbye.
'''
....def getMailFrom(self):
........result = self.mailFrom
........self.mailFrom = None
........return result
....def getMailTo(self):
........return [self.mailTo]
....def getMailData(self):
........return StringIO.StringIO(self.mailData)
....def sentMail(self, code, resp, numOk, addresses, log):
........print 'Sent', numOk, 'messages'
........from twisted.internet import reactor
........reactor.stop()
class SMTPClientFactory(protocol.ClientFactory):
....protocol = SMTPTutorialClient
....def buildProtocol(self, addr):
........return self.protocol(secret=None, identity='example.com')
def getMailExchange(host):
....def cbMX(mxRecord):
........return str(mxRecord.exchange)
....return relaymanager.MXCalculator().getMX(host).addCallback(cbMX)
def cbMailExchange(exchange):
....smtpClientFactory = SMTPClientFactory()
....smtpClientService = internet.TCPClient(exchange, 25, smtpClientFactory)
....smtpClientService.setServiceParent(application)
getMailExchange('example.net').addCallback(cbMailExchange)
============ end tutorial code ============

This nicely looks up the right MX record and sends out an email, just what I 
need. Now I want to expand it to allow me to give it a list of email addresses 
to send the message to (not just call this same routine multple times, which 
seems wasteful and slow and doesn't use twisted's power to process the multiple 
emails in multiple threads), but I'm having terrible trouble figuring out how 
to do that, which tells me I'm missing a paradigm somewhere, there's something 
I'm not getting.

Trouble 1 is figuring out the right way to pass additional parameters to 
callbacks. Is this right:

Dosomething(that-returns-a-deferred).addCallback(Then-do-the-next-thing, 
extra-parameter1, extraparameter2)

The function Then-do-the-next-thing() will receive the deferred returned 
results from Dosomething() as its first argument, and extra-parameter1 and 
extraparameter2 as the next two. That is as if calling:
Then-do-the-next-thing(Result-returned-by-Dosomething(),extra-parameter1, 
extraparameter2). Have I got this correct?

So, if this is right, then where do I want to put the additional argument that 
contains the next email address to send, if I iterate through the list and hand 
each one to the email sending process like this:

elist=['ad...@domain.com','ad...@nextdomain.com'...]
for e in elist:
.... e2={'mxhost':'','toaddr':e}
.... getMailExchange(e2).addCallback(cbMailExchange)

In the tutorial, getMailExchange() is passed just the domain of the addressee, 
and the sending out of the email happens when the callback returns the MX 
exchange. I changed that to split the email address, so now it returns both the 
full address and the mx:

def getMailExchange(addr):
.... host=addr.split('@')[1]
.... def cbMX(mxRecord):
.... .... return [addr,str(mxRecord.name)]
.... return relaymanager.MXCalculator().getMX(host).addCallback(cbMX)


At this point I can't figure out how to get the email address passed to 
wherever it needs to go. And I don't know really where it needs to go... yikes.

In the tutorial the actual email address is hard coded into the class 
SMTPTutorialClient(smtp.ESMTPClient) as a class attribute, mailTo. I need to 
change that to be variable.

How do I get this value (of mailTo) changed for each of the instances created 
by smtpClientFactory = SMTPClientFactory()? I think I must be confused about 
the roles of Factories and Protocols.

I can't seem to figure out a way that works to get the email address passed 
into the system as a variable. Rather than waste people's time by describing my 
various failures, I thought I'd just ask for suggestions about the right 
twisted way to do it. 

Thanks for any suggestions and directions!

-Dave

_______________________________________________
Twisted-Python mailing list
Twisted-Python@twistedmatrix.com
http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python

Reply via email to