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
Expand|Select|Wrap|Line Numbers
- #!/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@somedomain.org'
- fromemail = 'fromemail@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\nSending 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()