[Tutor] Program review

Ricardo Aráoz ricaraoz at gmail.com
Sun Jan 6 17:04:04 CET 2008


Ok, new version.
In procesar() I tried getting rid of the outer try block and having
'return' instead of 'raise' in the inner try blocks but I didn't like
the result. I'd rather have one more indent level but have only one exit
point from the function.
Redesigned class Mensaje so that it now includes a MIME message, I think
it simplifies the code and less attributes are going around, now
Correo.__init__() is simpler.
I was tempted to put 'messg = self.mensage.messg' as the first line of
Correo.enviar() so as to shorten things like
self.mensaje.messg.replace_header('To', addr) to
messg.replace_header('To', addr) but I didn't like it, I'd rather stress
the fact that 'messg' belongs to Correo's attribute 'mensaje'.

Here's the code (untested):

#!/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'))
            self.html = 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(mensaje.html, '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 SMTPRecipientsRefused :
            logging.error('El destinatario fue rechazado por el servidor')
        except SMTPHeloError :
            logging.error('El servidor no respondio apropiadamente')
        except SMTPSenderRefused :
            logging.error('El From: fue rechazado por el servidor')
        except SMTPDataError :
            logging.error('El servidor respondio con un error desconocido')

def procesar(mensaje):
    try :
        try :
            fIncl = open(mensaje.direcciones)
        except Exception, e :
            logging.error('Error!!! No pude abrir "%s" : %s',
                            mensaje.direcciones,
                            e.strerror)
            raise
        try :
            fExcl = open(mensaje.excluidas)
        except Exception, e :
            logging.error('No pude abrir "%s" : %s',
                            mensaje.excluidas,
                            e.strerror)
            fIncl.close()
            raise
    except : pass
    else :
        mails = enumerate(
                        set(addr.strip() for addr in fIncl)
                        - set(excl.strip() for excl in fExcl))
        fIncl.close()
        fExcl.close()
        miCorreo = Correo(mensaje)
        miCorreo.connect()
        empiezo = time.clock()
        for nro, addr in mails :
            if nro%mensaje.cuantos == 0 and nro > 0 :
                miCorreo.disconnect()
                time.sleep(mensaje.intervalo - (time.clock() - empiezo))
                if not miCorreo.connect() :
                    logging.info('Terminando')
                    return
                empiezo = time.clock()
            miCorreo.enviar(addr)
        miCorreo.disconnect()


if __name__ == '__main__' :
    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')
    procesar(Mensaje())

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


More information about the Tutor mailing list