[Tutor] Mail revisited

Ricardo Aráoz ricaraoz at gmail.com
Tue Feb 12 19:17:47 CET 2008


Ok, so I've started the path to put a GUI to the "MandarMails.py"
program. For starters I've included a progress bar. Any enhancements you
may suggest will be appreciated.
Note: not tested yet

######################
### MandarMails.py ###
######################

#!/usr/bin/env python

import time
import smtplib
import email
import ConfigParser
import logging

class Mensaje(object) :
    def __init__(self) :
        cfg = ConfigParser.ConfigParser()
        try :
            cfg.readfp(open('config.cfg'))
        except Exception, e :
            logging.error('No pude leer "config.cfg" : %s', e.strerror)

        self.direcciones = cfg.get('Archivos', 'Direcciones')
        self.excluidas = cfg.get('Archivos', 'Excluir')
        self.cuantos = cfg.getint('Correo', 'MailsPorVez')
        self.intervalo = cfg.getint('Correo', 'IntervaloEnSegundos')

        try :
            htmlFile = open(cfg.get('Archivos', 'Mensaje'))
            htmlMessage = htmlFile.read()
            htmlFile.close()
        except Exception, e :
            logging.error('No pude leer "%s" : %s',
                            cfg.get('Archivos', 'Mensaje'),
                            e.strerror)

        self.messg = email.MIMEMultipart.MIMEMultipart()
        self.messg['From'] = cfg.get('Encabezados', 'De')
        self.messg['To'] = ''
        self.messg['Subject'] = cfg.get('Encabezados', 'Encabezado')
        self.messg['Reply-To'] = cfg.get('Encabezados', 'ResponderA')
        self.messg.preamble = 'This is a multi-part message in MIME format'
        self.messg.attach(email.MIMEText.MIMEText(htmlMessage, 'html'))

        self.servidor = cfg.get('Correo', 'Servidor')
        self.usuario = cfg.get('Correo', 'Usuario')
        self.contra = cfg.get('Correo', 'Contrasenia')

class Correo(object) :
    def __init__(self, mensaje) :
        self.mensaje = mensaje
        self.conexion = smtplib.SMTP()

    def connect(self) :
        try :
            self.conexion.connect(self.mensaje.servidor)
            self.conexion.set_debuglevel(False)
            self.conexion.ehlo()
            self.conexion.starttls()
            self.conexion.ehlo()
            self.conexion.login(self.mensaje.usuario, self.mensaje.contra)
            return True
        except :
            logging.error('No me pude conectar al Servidor')
            return False

    def disconnect(self) :
        self.conexion.close()

    def enviar(self, addr) :
        self.mensaje.messg.replace_header('To', addr)
        try :
            self.conexion.sendmail(self.mensaje.messg['From'],
                                    self.mensaje.messg['To'],
                                    self.mensaje.messg.as_string())
            logging.info('Enviado a : %s', self.mensaje.messg['To'])
        except smtplib.SMTPRecipientsRefused :
            logging.error('El destinatario fue rechazado por el servidor')
        except smtplib.SMTPHeloError :
            logging.error('El servidor no respondio apropiadamente')
        except smtplib.SMTPSenderRefused :
            logging.error('El From: fue rechazado por el servidor')
        except smtplib.SMTPDataError :
            logging.error('El servidor respondio con un error desconocido')

class Envio(object) :
    def __init__(self, mensaje) :
        self._mensaje = mensaje
        self.totAEnviar = 0
        self.enviados = 0
        self._mails = []
        self._miCorreo = None
        self._timer = 0
        try :
            try :
                fIncl = open(self._mensaje.direcciones)
            except Exception, e :
                logging.error('Error!!! No pude abrir "%s" : %s',
                                self._mensaje.direcciones,
                                e.strerror)
                raise
            try :
                fExcl = open(self._mensaje.excluidas)
            except Exception, e :
                logging.error('No pude abrir "%s" : %s',
                                self._mensaje.excluidas,
                                e.strerror)
                fIncl.close()
                raise
        except : pass
        else :
            self._mails = enumerate(set(addr.strip() for addr in fIncl)
                                    - set(excl.strip() for excl in fExcl))
            fIncl.close()
            fExcl.close()
            self.TotAEnviar = len(self._mails)
            self._miCorreo = Correo(self._mensaje)

    def enviar() :
        dormir = self._mensaje.intervalo - (time.clock() - self._timer)
        if dormir > 0 :
            time.sleep(dormir)
        self._timer = time.clock()
        if not self._miCorreo.connect() :
            logging.info('Terminando')
            return False
        for nro, addr in self._mails[:self._mensaje.cuantos] :
            self._miCorreo.enviar(addr)
        self._miCorreo.disconnect()
        self._mails = self._mails[self._mensaje.cuantos:]
        return (len(self._mails) > 0)

if __name__ == '__main__' :
    from Tkinter import *
    from ProgressBar import ProgressBar

    logging.basicConfig(level=logging.INFO,
                        format='%(asctime)s %(levelname)-8s %(message)s',
                        datefmt='%a, %d %b %Y %H:%M:%S',

filename=time.strftime('informe-%Y-%m-%d-%H-%M-%S.log'),
                        filemode='w')
    miEnvio = Envio(Mensaje())
    root = Tk()
    labelfont = ('times', 12, 'bold')
    titulo = Label(root, text='Progreso del Envio')
    titulo.config(font=labelfont)
    titulo.config(height=1, width=20)
    titulo.pack(expand=YES, fill=X)
    myBar = ProgressBar(root, width=200, max=miEnvio.totAEnviar)
    myBar.pack()
    while miEnvio.enviar() :
        myBar.updateProgress(miEnvio.enviados)



######################
### ProgressBar.py ###
######################

from Tkinter import *
import time

class ProgressBar(Frame) :
    def __init__(self, parent=None, orientation="horizontal",
                 min=0, max=100, width=100, height=18,
                 doLabel=1, relief="sunken",
                 fillColor="blue", background="gray",
                 labelColor="yellow", labelFont="Verdana",
                 labelText="", labelFormat="%d%%",
                 value=0, bd=2) :
        self.parent = parent
        self.orientation = orientation
        self.min = min
        self.max = max
        self.width = width
        self.height = height
        self.doLabel = doLabel
        self.fillColor = fillColor
        self.labelFont = labelFont
        self.labelColor = labelColor
        self.background = background
        self.labelText = labelText
        self.labelFormat = labelFormat
        self.value = value
        Frame.__init__(self, parent, relief=relief, bd=bd)
        self.pack()
        self.canvas=Canvas(self, height=height, width=width, bd=0,
                           highlightthickness=0, background=background)
        self.scale=self.canvas.create_rectangle(0, 0, width, height,
                                                fill=fillColor)
        self.label=self.canvas.create_text(self.canvas.winfo_reqwidth() / 2,
                                            height / 2, text=labelText,
                                            anchor="c", fill=labelColor,
                                            font=self.labelFont)
        self.update()
        self.canvas.pack(side='top', fill='x', expand='no')

    def updateProgress(self, newValue, newMax=None):
        if newMax:
            self.max = newMax
        self.value = newValue
        self.update()

    def update(self):
        cnvs = self.canvas
        # Trim the values to be between min and max
        value=self.value
        if value > self.max:
            value = self.max
        if value < self.min:
            value = self.min
        # Adjust the rectangle
        if self.orientation == "horizontal":
            cnvs.coords(self.scale, 0, 0,
                        float(value) / self.max * self.width, self.height)
        else:
            cnvs.coords(self.scale, 0,
                        self.height - (float(value) / self.max*self.height),
                        self.width, self.height)
        # Now update the colors
        cnvs.itemconfig(self.scale, fill=self.fillColor)
        cnvs.itemconfig(self.label, fill=self.labelColor)
        # And update the label
        if self.doLabel:
            if value:
                if value >= 0:
                    pvalue = int((float(value) / float(self.max)) * 100.0)
                else:
                    pvalue = 0
                cnvs.itemconfig(self.label,
                                text=self.labelFormat % pvalue)
            else:
                cnvs.itemconfig(self.label,
                                text='')
        else:
            cnvs.itemconfig(self.label,
                            text=self.labelFormat % self.labelText)
        cnvs.update_idletasks()

if __name__ == '__main__' :
    root = Tk()
    labelfont = ('times', 12, 'bold')
    titulo = Label(root, text='Progreso')
    titulo.config(font=labelfont)
    titulo.config(height=1, width=10)
    titulo.pack(expand=YES, fill=X)
    myBar = ProgressBar(root, width=200)
    myBar.pack()
    for i in range(100) :
        myBar.updateProgress(i)
        time.sleep(0.1)
    root.quit()


More information about the Tutor mailing list