Monitoring number of smtp bytes sent through python e-mail socket

William Connery wconnery at dodo.com.au
Mon Dec 4 20:18:08 EST 2006


Hi,

I have a small python program with e-mail capabilities that I have 
pieced together from code snippets found on the internet.

The program uses the smtplib module to successfully send an e-mail with 
an attachment.

I want to give users an indication of the percentage of the e-mail that 
has already been sent so as to avoid frustration when dealing with large 
attachments or a slow smtp server. But the smtplib module doesn't seem 
to provide access to the number of bytes that have already been sent.

Can anyone help, or provide a working example of sending an e-mail 
attachment using basic python sockets whilst having access to the number 
of bytes that have already been sent through the socket?

Many thanks.

William Connery


#!/usr/bin/python

import wx
import smtplib
from email import Encoders
from email.MIMEMultipart import MIMEMultipart
from email.Utils import COMMASPACE, formatdate
from email.MIMEBase import MIMEBase
from email.MIMEText import MIMEText
import os

# set a few variables to make testing less tedious

# you need to set your smtp server domain name
smtp_server = 'smtp.your_isp_domain.com'

toemail = 'toemail at somedomain.org'
fromemail = 'fromemail at anotherdomain.org'
subject = 'Testing python smtplib module'
emailmsg = 'How do I determine the number of bytes that ' +\
'have been forwarded whilst the e-mail is being sent ?\n\n' +\
'Sending large (or many) attachments may take some ' +\
'time, and I\'d like to use a gauge control to give users ' +\
'an indication of the percentage of the e-mail that has ' +\
'already been sent.\n\nThe smtplib module relies on ' +\
'sockets, but I don\'t know how to use python sockets ' +\
'to send an e-mail with attachments and concurrently ' +\
'monitor the number of bytes that have already been ' +\
'sent.\n\nHelp !'

# attachment file
attachment = 'C:\\Documents and Settings\\-\\Desktop\\test.zip'
#attachment = '/home/user1/Desktop/test.zip'


# variable to hold bytes that have been sent
bytes_sent = 0




class MainFrame(wx.Frame):
    def __init__(self, *args, **kwargs):
        wx.Frame.__init__(self, *args, **kwargs)
        self.SetSize(wx.Size(750,550))
        self.SetTitle('Monitoring the number of bytes sent during ' +\
        'a python e-mail send  -  How ?')
       
        panel = wx.Panel(self)
       
        vertsizer = wx.BoxSizer(wx.VERTICAL)
       
        flexsizer = wx.FlexGridSizer(rows=8, cols=2, hgap=10, \
        vgap=10)
        flexsizer.AddGrowableCol(1)
        flexsizer.AddGrowableRow(4)
       
        tolabel = wx.StaticText(panel, -1, "To E-mail Address:")
        flexsizer.Add(tolabel,0,wx.ALIGN_RIGHT|\
        wx.ALIGN_CENTER_VERTICAL)
        self.toemailaddress = wx.TextCtrl(panel)
        flexsizer.Add(self.toemailaddress,0,wx.EXPAND)
       
        fromlabel = wx.StaticText(panel, -1, "From E-mail Address:")
        flexsizer.Add(fromlabel,0,wx.ALIGN_RIGHT|\
        wx.ALIGN_CENTER_VERTICAL)
        self.fromemailaddress = wx.TextCtrl(panel)
        flexsizer.Add(self.fromemailaddress,0,wx.EXPAND)
       
        attachmentbutton = wx.Button(panel, 1001, "File Attachment")
        attachmentbutton.Bind(wx.EVT_BUTTON, \
        self.SelectAttachmentFile)
        flexsizer.Add(attachmentbutton,0,wx.ALIGN_RIGHT|\
        wx.ALIGN_CENTER_VERTICAL)
        self.attachmenteditbox = wx.TextCtrl(panel,\
        style = wx.TE_CENTRE)
        self.attachmenteditbox.Disable()
        flexsizer.Add(self.attachmenteditbox,0,wx.EXPAND)
       
        subjectlabel = wx.StaticText(panel, -1, "Subject:")
        flexsizer.Add(subjectlabel,0,wx.ALIGN_RIGHT|\
        wx.ALIGN_CENTER_VERTICAL)
        self.subject = wx.TextCtrl(panel)
        flexsizer.Add(self.subject,0,wx.EXPAND)
       
        messagelabel = wx.StaticText(panel, -1, "E-mail Message:")
        flexsizer.Add(messagelabel,0,wx.ALIGN_RIGHT)
        self.emailmessage = wx.TextCtrl(panel, \
        style = wx.TE_MULTILINE)
        flexsizer.Add(self.emailmessage,1,wx.EXPAND)
       
        flexsizer.AddSpacer(wx.Size(1,1))
                               
        self.gauge = wx.Gauge(panel)
        self.gauge.SetRange(100)
        self.gauge.SetValue(30)
        sendbutton = wx.Button(panel, 1001, "Send E-mail")
        sendbutton.Bind(wx.EVT_BUTTON, self.SendTheEmail)
        hsizer = wx.BoxSizer(wx.HORIZONTAL)
        hsizer.Add(self.gauge,1,wx.RIGHT,15)
        hsizer.Add(sendbutton,0,wx.ALIGN_CENTER_VERTICAL)
        flexsizer.Add(hsizer,0,wx.EXPAND)
       
        byteslabel1 = wx.StaticText(panel, -1, "Bytes to Send:")
        self.bytestosend = wx.StaticText(panel, -1, "0")
        flexsizer.Add(byteslabel1,0,wx.ALIGN_RIGHT)
        flexsizer.Add(self.bytestosend,0,wx.EXPAND)

        byteslabel2 = wx.StaticText(panel, -1, "Bytes Sent:")
        self.bytessent = wx.StaticText(panel, -1, "0")
        flexsizer.Add(byteslabel2,0,wx.ALIGN_RIGHT)
        flexsizer.Add(self.bytessent,0,wx.EXPAND)
       
       
        vertsizer.Add(flexsizer,1, wx.EXPAND|wx.ALL,30)
       
        # place values into appropriate text fields
        # (these values can be initialized at the top of this script)
       
        self.toemailaddress.SetValue(toemail)
        self.fromemailaddress.SetValue(fromemail)
        self.subject.SetValue(subject)
        self.emailmessage.SetValue(emailmsg)
       
        if os.path.exists(os.path.abspath(attachment)):
            self.attachmenteditbox.SetValue(\
            os.path.split(os.path.abspath(attachment))[1])
       
        panel.SetSizer(vertsizer)

        self.bytestosend.SetLabel(str(self.GetMimeSize()))



    # select an attachment file for the e-mail
    def SelectAttachmentFile(self, event):

        filedlgbox = wx.FileDialog(self,\
            message="Select  an Attachment  File", \
            defaultDir=os.getcwd(), \
            defaultFile='', \
            wildcard="Any File (*.*)|*.*", \
            style=wx.OPEN | wx.CHANGE_DIR | \
            wx.HIDE_READONLY)
           
        if filedlgbox.ShowModal() == wx.ID_OK:
            global attachment
            attachment = filedlgbox.GetFilenames()[0].strip()
            self.attachmenteditbox.SetValue(\
            os.path.split(attachment)[1])
           
        filedlgbox.Destroy()
           
        self.bytestosend.SetLabel(str(self.GetMimeSize()))
           
        event.Skip()



    def GetMimeSize(self):
       
        # get size of current e-mail mime object
       
        tempmime = MIMEMultipart()
        tempmime['To'] = self.toemailaddress.GetValue().strip()
        tempmime['From'] = self.fromemailaddress.GetValue().strip()
        tempmime['Subject'] = self.subject.GetValue().strip()

        # add the e-mail message to the mime object
        tempmime.attach(MIMEText(self.emailmessage.GetValue()))

        # add an attachment file to the mime object if selected
        if attachment.strip() != '':
            thisfile = os.path.abspath(attachment)
            if os.path.exists(thisfile):
                attachmentmime = MIMEBase('application', \
                "octet-stream")
                attachmentmime.set_payload(\
                open(thisfile,"rb").read())
                Encoders.encode_base64(attachmentmime)
                attachmentmime.add_header('Content-Disposition',\
                'attachment; filename="%s"' % \
                os.path.basename(thisfile))
                tempmime.attach(attachmentmime)
       
        mimesize = len(tempmime.as_string())
       
        tempmime = None
       
        return mimesize
       

    # send the e-mail using python's smtplib module
    def SendTheEmail(self, event):
       
        # how can I determine the number of bytes that have
        # been forwarded whilst the e-mail is being sent ?
        global bytes_sent
        bytes_sent = 0
       
        # set gauge value to zero - max value = 100 (%)
        self.gauge.SetValue(0)
       
        self.bytestosend.SetLabel(str(self.GetMimeSize()))
        self.bytessent.SetLabel('0')
       
        # create a multi-part mime object for the
        # e-mail message and file attachment
       
        thismime = MIMEMultipart()
        thismime['To'] = self.toemailaddress.GetValue().strip()
        thismime['From'] = self.fromemailaddress.GetValue().strip()
        thismime['Subject'] = self.subject.GetValue().strip()

        # add the e-mail message to the mime object
        thismime.attach(MIMEText(self.emailmessage.GetValue()))

        # add an attachment file to the mime object if selected
        if attachment.strip() != '':
            thisfile = os.path.abspath(attachment)
            if os.path.exists(thisfile):
                attachmentmime = MIMEBase('application', \
                "octet-stream")
                attachmentmime.set_payload(\
                open(thisfile,"rb").read())
                Encoders.encode_base64(attachmentmime)
                attachmentmime.add_header('Content-Disposition',\
                'attachment; filename="%s"' % \
                os.path.basename(thisfile))
                thismime.attach(attachmentmime)
            else:
                dlg = wx.MessageDialog(self,\
                message='Attachment file ' + thisfile + ' is missing.',\
                caption='Attachment Missing',style=wx.OK|\
                wx.ICON_INFORMATION)
                dlg.ShowModal()
                dlg.Destroy()
       
        # send the e-mail
        smtpobj = smtplib.SMTP(smtp_server)
        smtpobj.sendmail(self.fromemailaddress.GetValue().strip(), \
                            self.toemailaddress.GetValue().strip(), \
                            thismime.as_string())
                           
        smtpobj.close()


        event.Skip()



if __name__ == '__main__':
    app = wx.App()
    theframe = MainFrame(None)
    theframe.Show()
    app.MainLoop()





More information about the Python-list mailing list