.

Python smtplib progress indication

A few days ago I was in wanted to send an email with attachments through Python's smtplib, when I realised there was no way of keeping track of the sending progress.

After some analysis of smtplib, I finally made the choice to subclass and extend the smtplib.SMTP class.

It feels like a big dirty hack and I just wanted to throw it out there to see if anyone knows of a better way to accomplish this.

from smtplib import SMTP, quotedata, CRLF, SMTPDataError
from sys import stderr

class ExtendedSMTP(SMTP): 	
    def data(self,msg):
        """
			This is a modified copy of smtplib.SMTP.data()
			
			Sending data in chunks and calling self.callback
			to keep track of progress,
		"""
        self.putcmd("data")
        (code,repl)=self.getreply()
        if self.debuglevel >0 : print>>stderr, "data:", (code,repl)
        if code != 354:
            raise SMTPDataError(code,repl)
        else:
            q = quotedata(msg)
            if q[-2:] != CRLF:
                q = q + CRLF
            q = q + "." + CRLF
            
            # begin modified send code
            chunk_size = 2048
            bytes_sent = 0
            
            while bytes_sent != len(q):
                chunk = q[bytes_sent:bytes_sent+chunk_size]
                self.send(chunk)
                bytes_sent += len(chunk)
                if hasattr(self, "callback"):
                    self.callback(bytes_sent, len(q)):
            # end modified send code
            
            (code,msg)=self.getreply()
            if self.debuglevel >0 : print>>stderr, "data:", (code,msg)
            return (code,msg)

To use this, we instantiate the class as normal and attach a callback function to it, which will be called by the data() method.

def callback(progress, total):
    print "%s bytes sent of %s" % (progress, total)

s = ExtendedSMTP() # instead of smtplib.SMTP()
s.callback = callback
s.sendmail("billg@microsoft.com", "steveb@microsoft.com", msg)
s.quit()

Let me know if there are better ways to do this.

posted on 21 Oct, 2009 to Python » view comments
blog comments powered by Disqus