<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
  <meta content="text/html;charset=ISO-8859-1" http-equiv="Content-Type">
  <title></title>
</head>
<body bgcolor="#ffffff" text="#000000">
<br>
<blockquote cite="mid:E1JlnZk-0006P9-Ec@cube.twistedmatrix.com"
 type="cite">
  <pre wrap="">Date: Tue, 15 Apr 2008 18:38:28 +0800
From: Chris <a class="moz-txt-link-rfc2396E" href="mailto:chris.yan@saybot.com">&lt;chris.yan@saybot.com&gt;</a>
Subject: [Twisted-Python] about smtp client auth problem.
To: <a class="moz-txt-link-abbreviated" href="mailto:twisted-python@twistedmatrix.com">twisted-python@twistedmatrix.com</a>
Message-ID: <a class="moz-txt-link-rfc2396E" href="mailto:480485A4.6060808@saybot.com">&lt;480485A4.6060808@saybot.com&gt;</a>
Content-Type: text/plain; charset=GB2312

Hi,
I am trying to use twisted to implement a script to send the email,I got
some problem.here is the script:
####################
import StringIO

from twisted.application import service

application = service.Application("SMTP Client Tutorial")

from twisted.application import internet
from twisted.python import log
from twisted.internet import defer, reactor
from twisted.mail import smtp

mailFrom = <a class="moz-txt-link-rfc2396E" href="mailto:chris.yan@xxxx.com">"chris.yan@xxxx.com"</a>
mailTo = [<a class="moz-txt-link-rfc2396E" href="mailto:chrisyan81@gmail.com">"chrisyan81@gmail.com"</a>,]
mail = StringIO.StringIO("""Date: Fri, 3 Nov 2006 230:14:39 +0000
From: <a class="moz-txt-link-abbreviated" href="mailto:chris.yan@xxxx.com">chris.yan@xxxx.com</a>
To: <a class="moz-txt-link-abbreviated" href="mailto:chrisyan81@gmail.com">chrisyan81@gmail.com</a>
Subject: Tutorate!

Hello, how are you, goodbye.
""")

whenDone = defer.Deferred()

def send(r):
print "message sent:", r

whenDone.addCallbacks(send, log.err)

def done(d):
from twisted.internet import reactor
reactor.callLater(1, reactor.stop)

whenDone.addBoth(done)


sender = smtp.ESMTPSenderFactory(
'chris.yan',
'xxxxxx',
mailFrom,
mailTo,
mail,
whenDone,
requireTransportSecurity=False
)

smtpClientService = internet.TCPClient('smtp.xxxx.com', 25, sender)
smtpClientService.setServiceParent(application)

in fact the script from
<a class="moz-txt-link-freetext" href="http://twistedmatrix.com/pipermail/twisted-python/2006-November/014299.html,and">http://twistedmatrix.com/pipermail/twisted-python/2006-November/014299.html,and</a>
I didn't modify anything except my own information.Because the smtp
server doesn't support SSL,so I use requireTransportSecurity=False.

here is the output:

2008/04/15 17:56 +0800 [-] Log opened.
2008/04/15 17:56 +0800 [-] twistd 2.5.0 (C:\Python25\python.exe 2.5.2)
starting up
2008/04/15 17:56 +0800 [-] reactor class: &lt;class
'twisted.internet.selectreactor.SelectReactor'&gt;
2008/04/15 17:56 +0800 [-] Loading smtpclient_tls_001.py...
2008/04/15 17:56 +0800 [-] Loaded.
2008/04/15 17:56 +0800 [-] Starting factory
&lt;twisted.mail.smtp.ESMTPSenderFactory instance at 0x01347878&gt;
2008/04/15 17:56 +0800 [ESMTPSender,client] Unhandled Error
Traceback (most recent call last):
Failure: twisted.mail.smtp.AUTHRequiredError: 502 Server does not
support Client Authentication schemes [CRAM-MD
5, LOGIN, PLAIN]

&lt;&lt;&lt; 250-AUTH
&lt;&lt;&lt; 250-AUTH=PLAIN LOGIN LOGIN
&lt;&lt;&lt; 250-XXXXXXXA
&lt;&lt;&lt; 250 XXXB

2008/04/15 17:56 +0800 [ESMTPSender,client] Stopping factory
&lt;twisted.mail.smtp.ESMTPSenderFactory instance at 0x0134787
8&gt;
2008/04/15 17:56 +0800 [-] Main loop terminated.
2008/04/15 17:56 +0800 [-] Server Shut Down.

but when I use another script which uses smtplib:
SMTP_server='smtp.xxxx.com'
SMTP_user='chris.yan'
SMTP_passwd='xxxxx'

def
send_email(Subject,From,To,Attachment,Body,SMTP_server,SMTP_user,SMTP_passwd):
msg = MIMEMultipart()
msg['Subject'] = Subject
msg['From'] = From
msg['To'] = To


txt = MIMEText(Body,_charset='utf-8')
msg.attach(txt)

filename = Attachment
if not os.path.isfile(filename):
print 'Can not find file %s,please check!' % filename
sys.exit(1)

fp = open(filename,'rb')
ctype,encoding = mimetypes.guess_type(filename)
if ctype is None or encoding is not None:
ctype = 'application/octet-stream'
maintype,subtype = ctype.split('/',1)
m = MIMEBase(maintype,subtype)
m.set_payload(fp.read())
fp.close()
Encoders.encode_base64(m)
m.add_header('Content-disposition','attachment',filename=filename)
msg.attach(m)

s = smtplib.SMTP(SMTP_server)
s.debuglevel = 5
s.ehlo()
s.esmtp_features["auth"] = "LOGIN"

s.login(SMTP_user,SMTP_passwd)
s.sendmail(From,To,msg.as_string())
s.close()

I can get the output:
send: 'ehlo chris.shuobaotang.com\r\n'
reply: '250-mail.saybot.com Hello chris.shuobaotang.com [218.79.132.2]\r\n'
reply: '250-SIZE 52428800\r\n'
reply: '250-PIPELINING\r\n'
reply: '250-AUTH \r\n'
reply: '250-AUTH=PLAIN LOGIN LOGIN\r\n'
reply: '250-XXXXXXXA\r\n'
reply: '250 XXXB\r\n'
reply: retcode (250); Msg: mail.saybot.com Hello chris.shuobaotang.com
[218.79.132.2]
SIZE 52428800
PIPELINING
AUTH
AUTH=PLAIN LOGIN LOGIN
XXXXXXXA
XXXB
send: 'AUTH LOGIN Y2hyaXMueWFu\r\n'
reply: '334 UGFzc3dvcmQ6\r\n'
reply: retcode (334); Msg: UGFzc3dvcmQ6
send: 'd3JpbHV5Yg==\r\n'
reply: '235 Authentication succeeded\r\n'
reply: retcode (235); Msg: Authentication succeeded
send: 'mail FROM:<a class="moz-txt-link-rfc2396E" href="mailto:chris.yan@saybot.com">&lt;chris.yan@saybot.com&gt;</a> size=668\r\n'
reply: '250 OK\r\n'
reply: retcode (250); Msg: OK
send: 'rcpt TO:<a class="moz-txt-link-rfc2396E" href="mailto:chrisyan81@gmail.com">&lt;chrisyan81@gmail.com&gt;</a>\r\n'
reply: '250 Accepted\r\n'
reply: retcode (250); Msg: Accepted
send: 'data\r\n'
reply: '354 Enter message, ending with "." on a line by itself\r\n'
reply: retcode (354); Msg: Enter message, ending with "." on a line by
itself
data: (354, 'Enter message, ending with "." on a line by itself')
send: 'Content-Type: multipart/mixed;
boundary="===============1595669237=="\r\nMIME-Version: 1.0\r\nSubject:
scores fro
m saybot rater.\r\nFrom: <a class="moz-txt-link-abbreviated" href="mailto:chris.yan@saybot.com\r\nTo:">chris.yan@saybot.com\r\nTo:</a>
<a class="moz-txt-link-abbreviated" href="mailto:chrisyan81@gmail.com\r\n\r\n--===============1595669237==\r\nConten">chrisyan81@gmail.com\r\n\r\n--===============1595669237==\r\nConten</a>
t-Type: text/plain; charset="utf-8"\r\nMIME-Version:
1.0\r\nContent-Transfer-Encoding: base64\r\n\r\nSGksCiAgICBUaGlzIGl
zIHRoZSBzY29yZXMgd2hpY2ggZ2VuZXJhdGVkIGJ5IHNheWJvdCByYXRl\r\ncixwbGVhc2UgY2hlY2sgdGhlIGF0dGFjaG1lbnQhCgpCZXN0UmVnYXJkCkN
ocmlzCg==\r\n\r\n--===============1595669237==\r\nContent-Type:
text/plain\r\nMIME-Version: 1.0\r\nContent-Transfer-Enco
ding: base64\r\nContent-disposition: attachment;
filename="scores.txt"\r\n\r\nMTM4MTMwMzE0NzUg17/Hvw0K\r\n\r\n--========
=======1595669237==--\r\n.\r\n'
reply: '250 OK id=1Jlhvl-00071w-1f\r\n'
reply: retcode (250); Msg: OK id=1Jlhvl-00071w-1f
data: (250, 'OK id=1Jlhvl-00071w-1f')
Done.

some guy said,this script force to use the LOGIN auth,because something
wrong with the server,is it true?I don't know very much about the mail
server,does any one can tell me if I can make my twisted script work?I
really like to implement a twisted one.

BestWishes
Chris






------------------------------

Message: 3
Date: Tue, 15 Apr 2008 13:24:12 +0200
From: Gabriel Rossetti <a class="moz-txt-link-rfc2396E" href="mailto:mailing_lists@evotex.ch">&lt;mailing_lists@evotex.ch&gt;</a>
Subject: Re: [Twisted-Python] shared list in factory, mutexes?
To: Twisted general discussion <a class="moz-txt-link-rfc2396E" href="mailto:twisted-python@twistedmatrix.com">&lt;twisted-python@twistedmatrix.com&gt;</a>
Message-ID: <a class="moz-txt-link-rfc2396E" href="mailto:4804905C.5030608@evotex.ch">&lt;4804905C.5030608@evotex.ch&gt;</a>
Content-Type: text/plain; charset=ISO-8859-1; format=flowed

Simon Pickles wrote:
  </pre>
  <blockquote type="cite">
    <pre wrap="">
Gabriel Rossetti wrote:
    </pre>
    <blockquote type="cite">
      <pre wrap="">each thread is an individual self-contained unit that does whatever 
processing it needs to do however long it may need to take, and the 
OS takes care of scheduling each thread, but with twisted, the main 
thread executes each connection one by one sequentially and thus if 
one of them needs to to some lengthy processing, it will block all 
other connections from being processed, so you have to use threads to 
keep it from blocking, but somehow the active connection should 
become inactive while the processing thread does it's work, so that 
another connection can be processed in the meantime.


      </pre>
    </blockquote>
    <pre wrap="">Hi Gabriel,

Have you considered implementing Stackless python in partnership with 
Twisted? I am finding it very useful for handling multiple concurrent 
connections in a single thread. (it uses a scheduler which can switch 
between tasklets, in a yield fashion.)

The programmer has complete control over where this tasklet switching 
takes place, vastly simplifying things over multi-threading. If one 
connection involves some heavy processing, I simply add a 
stackless.schedule() in the blocking loop which allows waiting jobs to 
run too. Overhead for this tasklet switching is almost negligible too, 
unlike threads.

Regards

Simon


    </pre>
  </blockquote>
  <pre wrap=""><!---->Thanks Simon, I'll look into that, but I think that now that I 
understand better how twisted works, I'll stick with it "purely" :-)

Stackless is a python distrib though, from what I see.

Thanks,
Gabriel



------------------------------

Message: 4
Date: Tue, 15 Apr 2008 08:01:13 -0400
From: Jean-Paul Calderone <a class="moz-txt-link-rfc2396E" href="mailto:exarkun@divmod.com">&lt;exarkun@divmod.com&gt;</a>
Subject: Re: [Twisted-Python] about smtp client auth problem.
To: Twisted general discussion <a class="moz-txt-link-rfc2396E" href="mailto:twisted-python@twistedmatrix.com">&lt;twisted-python@twistedmatrix.com&gt;</a>
Message-ID: &lt;20080415120113.6859.490721552.divmod.quotient.30011@ohm&gt;
Content-Type: text/plain; format=flowed

On Tue, 15 Apr 2008 18:38:28 +0800, Chris <a class="moz-txt-link-rfc2396E" href="mailto:chris.yan@saybot.com">&lt;chris.yan@saybot.com&gt;</a> wrote:
  </pre>
  <blockquote type="cite">
    <pre wrap="">Hi,
I am trying to use twisted to implement a script to send the email,I got
some problem.here is the script:
####################
[snip]

&lt;&lt;&lt; 250-AUTH
&lt;&lt;&lt; 250-AUTH=PLAIN LOGIN LOGIN
&lt;&lt;&lt; 250-XXXXXXXA
&lt;&lt;&lt; 250 XXXB

[snip]

some guy said,this script force to use the LOGIN auth,because something
wrong with the server,is it true?I don't know very much about the mail
server,does any one can tell me if I can make my twisted script work?I
really like to implement a twisted one.
    </pre>
  </blockquote>
  <pre wrap=""><!---->
Indeed, the ESMTP server is not correctly advertising its support for the
AUTH extension.  

You can hack around this by going up to the ESMTP protocol implementation
in Twisted and tweaking its behavior a bit with a subclass (untested):

  from twisted.mail.smtp import ESMTPClient

  class ForceLOGINESMTPClient(ESMTPClient):
      def authenticate(self, code, resp, items):
          if 'AUTH=PLAIN' in items:
              items['AUTH'] = 'PLAIN ' + items['AUTH=PLAIN']
          return ESMTPClient.authenticate(self, code, resp, items)

Then, use this protocol with your ESMTPSenderFactory.  The idea here is
that this subclass notices the particular kind of malformed response this
server sends and adjusts it slightly.  This is a bit better than the other
version you gave which just hard-coded LOGIN, since it should manage to
actually correctly interpret the mechanisms the server is advertising.  Of
course, it may be a bit more fragile too, since it depends on the exact
kind of misformatting the server is doing.  If you want to avoid that,
you can hard-code LOGIN by just setting items['AUTH'] = 'LOGIN'.

Hope this helps,

Jean-Paul

  </pre>
</blockquote>
Hi Jean-Paul,<br>
&nbsp;&nbsp;&nbsp; Thank you very much,I think it works.this is the script:<br>
#!/usr/bin/env python<br>
import StringIO<br>
<br>
from twisted.application import service<br>
<br>
application = service.Application("SMTP Client Tutorial")<br>
<br>
from twisted.application import internet<br>
from twisted.python import log<br>
from twisted.internet import defer, reactor<br>
from twisted.mail import smtp<br>
<br>
mailFrom = <a class="moz-txt-link-rfc2396E" href="mailto:chris.yan@saybot.com">"chris.yan@saybot.com"</a><br>
mailTo = [<a class="moz-txt-link-rfc2396E" href="mailto:chrisyan81@gmail.com">"chrisyan81@gmail.com"</a>,]<br>
mail = StringIO.StringIO("""Date: Fri, 3 Nov 2006 230:14:39 +0000<br>
From: <a class="moz-txt-link-abbreviated" href="mailto:chris.yan@saybot.com">chris.yan@saybot.com</a><br>
To: <a class="moz-txt-link-abbreviated" href="mailto:chrisyan81@gmail.com">chrisyan81@gmail.com</a><br>
Subject: Tutorate!<br>
<br>
Hello, how are you, goodbye.<br>
""")<br>
<br>
whenDone = defer.Deferred()<br>
<br>
def send(r):<br>
&nbsp;&nbsp;&nbsp;&nbsp; print "message sent:", r<br>
<br>
whenDone.addCallbacks(send, log.err)<br>
<br>
def done(d):<br>
&nbsp;&nbsp;&nbsp;&nbsp; from twisted.internet import reactor<br>
&nbsp;&nbsp;&nbsp;&nbsp; reactor.callLater(1, reactor.stop)<br>
<br>
whenDone.addBoth(done)<br>
<br>
#this is the class from you<br>
class ForceLOGINESMTPClient(smtp.ESMTPClient):<br>
&nbsp;&nbsp;&nbsp; def authenticate(self, code, resp, items):<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #if 'AUTH=PLAIN' in items:<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #&nbsp;&nbsp; items['AUTH'] = 'PLAIN ' + items['AUTH=PLAIN']<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; items['AUTH'] = 'LOGIN'<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return smtp.ESMTPClient.authenticate(self, code, resp, items)<br>
<br>
&nbsp;#I saw the twisted.mail.smtp.ESMTPSenderFactory use the ESMTPSender as
the protocol,so I copied the implementation here,just make new one&nbsp;
inherit from ForceLOGINESMTPClient,I did not touch anything else. &nbsp;&nbsp;&nbsp; <br>
class ForceLOGINESMTPSender(smtp.SenderMixin,ForceLOGINESMTPClient):<br>
&nbsp;&nbsp;&nbsp; requireAuthentication = True<br>
&nbsp;&nbsp;&nbsp; requireTransportSecurity = True<br>
<br>
&nbsp;&nbsp;&nbsp; def __init__(self, username, secret, contextFactory=None, *args,
**kw):<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.heloFallback = 0<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self.username = username<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if contextFactory is None:<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; contextFactory = self._getContextFactory()<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ForceLOGINESMTPClient.__init__(self, secret, contextFactory,
*args, **kw)<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; self._registerAuthenticators()<br>
<br>
&nbsp;&nbsp;&nbsp; def _registerAuthenticators(self):<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # Register Authenticator in order from most secure to least
secure<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
self.registerAuthenticator(smtp.CramMD5ClientAuthenticator(self.username))<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
self.registerAuthenticator(smtp.LOGINAuthenticator(self.username))<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
self.registerAuthenticator(smtp.PLAINAuthenticator(self.username))<br>
<br>
&nbsp;&nbsp;&nbsp; def _getContextFactory(self):<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if self.context is not None:<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return self.context<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try:<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; from twisted.internet import ssl<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; except ImportError:<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return None<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else:<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try:<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; context = ssl.ClientContextFactory()<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; context.method = ssl.SSL.TLSv1_METHOD<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return context<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; except AttributeError:<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return None<br>
<br>
#use the ForceLOGINESMTPSender as the protocol,&nbsp; inherit the rest from&nbsp;
ESMTPSenderFactory&nbsp;&nbsp;&nbsp; <br>
class ForceLOGNINESMTPSenderFactory(smtp.ESMTPSenderFactory):<br>
&nbsp;&nbsp;&nbsp; protocol = ForceLOGINESMTPSender <br>
<br>
sender = ForceLOGNINESMTPSenderFactory(<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 'chris.yan',<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 'xxxx',<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mailFrom,<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mailTo,<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mail,<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; whenDone,<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; requireTransportSecurity=False<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; )<br>
<br>
smtpClientService = internet.TCPClient('smtp.xxxx.com', 25, sender)<br>
smtpClientService.setServiceParent(application)<br>
<br>
BestRegards<br>
Chris<br>
<br>
<br>
<br>
<br>
</body>
</html>