From b06fded288a7bfd4390378c394976f71a2d4880d Mon Sep 17 00:00:00 2001 From: Stephane Wirtel Date: Fri, 25 Feb 2011 14:56:54 +0100 Subject: [PATCH] [IMP] Allow to send an email if there is a bug in the OpenERP Server, avoid to lose the email. The email will send the full trace back with the original email and the parameters of the mailgateway [IMP] Add a new class for the configuration bzr revid: stephane@openerp.com-20110225135654-kjwzgb2ucyoy7syn --- .../openerp_mailgate/openerp_mailgate.py | 160 +++++++++++++++--- 1 file changed, 132 insertions(+), 28 deletions(-) diff --git a/addons/mail_gateway/scripts/openerp_mailgate/openerp_mailgate.py b/addons/mail_gateway/scripts/openerp_mailgate/openerp_mailgate.py index 204cb2d5d03..bcff408ef46 100644 --- a/addons/mail_gateway/scripts/openerp_mailgate/openerp_mailgate.py +++ b/addons/mail_gateway/scripts/openerp_mailgate/openerp_mailgate.py @@ -19,15 +19,71 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see # -########################################################################################### +############################################################################## +""" + openerp_mailgate.py +""" -import logging +import cgitb +import time import optparse import sys import xmlrpclib +import smtplib +from email.MIMEMultipart import MIMEMultipart +from email.MIMEBase import MIMEBase +from email.MIMEText import MIMEText +from email.Utils import COMMASPACE, formatdate +from email import Encoders -class rpc_proxy(object): - def __init__(self, uid, passwd, host='localhost', port=8069, path='object', dbname='openerp'): +class DefaultConfig(object): + """ + Default configuration + """ + OPENERP_DEFAULT_USER_ID = 1 + OPENERP_DEFAULT_PASSWORD = 'admin' + OPENERP_HOSTNAME = 'localhost' + OPENERP_PORT = 8069 + OPENERP_DEFAULT_DATABASE = 'openerp' + MAIL_ERROR = 'error@example.com' + MAIL_SERVER = 'localhost' + MAIL_ADMINS = ('admin@example.com',) + +config = DefaultConfig() + + +def send_mail(_from_, to_, subject, text, files=None, server=config.MAIL_SERVER): + assert isinstance(to_, (list, tuple)) + + if files is None: + files = [] + + msg = MIMEMultipart() + msg['From'] = _from_ + msg['To'] = COMMASPACE.join(to_) + msg['Date'] = formatdate(localtime=True) + msg['Subject'] = subject + + msg.attach( MIMEText(text) ) + + for file_name, file_content in files: + part = MIMEBase('application', "octet-stream") + part.set_payload( file_content ) + Encoders.encode_base64(part) + part.add_header('Content-Disposition', 'attachment; filename="%s"' + % file_name) + msg.attach(part) + + smtp = smtplib.SMTP(server) + smtp.sendmail(_from_, to_, msg.as_string() ) + smtp.close() + +class RPCProxy(object): + def __init__(self, uid, passwd, + host=config.OPENERP_HOSTNAME, + port=config.OPENERP_PORT, + path='object', + dbname=config.OPENERP_DEFAULT_DATABASE): self.rpc = xmlrpclib.ServerProxy('http://%s:%s/xmlrpc/%s' % (host, port, path), allow_none=True) self.user_id = uid self.passwd = passwd @@ -36,9 +92,9 @@ class rpc_proxy(object): def __call__(self, *request, **kwargs): return self.rpc.execute(self.dbname, self.user_id, self.passwd, *request, **kwargs) -class email_parser(object): +class EmailParser(object): def __init__(self, uid, password, model, email_default, dbname, host, port): - self.rpc = rpc_proxy(uid, password, host=host, port=port, dbname=dbname) + self.rpc = RPCProxy(uid, password, host=host, port=port, dbname=dbname) try: self.model_id = int(model) self.model = str(model) @@ -51,44 +107,92 @@ class email_parser(object): def parse(self, message, custom_values=None): if custom_values is None: custom_values = {} - try: - # pass message as bytes because we don't know its encoding until we parse its headers - # and hence can't convert it to utf-8 for transport - res_id = self.rpc('email.server.tools', 'process_email', self.model, xmlrpclib.Binary(message), custom_values) - except Exception: - logger = logging.getLogger('mail-gateway') - logger.warning('Failed to process incoming email. Source of the failed mail is available at debug level.', exc_info=True) - logger.debug('Source of the mail that failed to parse:', message) + # pass message as bytes because we don't know its encoding until we parse its headers + # and hence can't convert it to utf-8 for transport + self.rpc('email.server.tools', + 'process_email', + self.model, + xmlrpclib.Binary(message), + custom_values) -if __name__ == '__main__': - parser = optparse.OptionParser(usage='usage: %prog [options]', version='%prog v1.0') +def configure_parser(): + parser = optparse.OptionParser(usage='usage: %prog [options]', version='%prog v1.1') group = optparse.OptionGroup(parser, "Note", "This program parse a mail from standard input and communicate " "with the OpenERP server for case management in the CRM module.") parser.add_option_group(group) - parser.add_option("-u", "--user", dest="userid", help="ID of the user in OpenERP", default=1, type='int') - parser.add_option("-p", "--password", dest="password", help="Password of the user in OpenERP", default='admin') - parser.add_option("-o", "--model", dest="model", help="Name or ID of crm model", default="crm.lead") - parser.add_option("-m", "--default", dest="default", help="Default eMail in case of any trouble.", default=None) - parser.add_option("-d", "--dbname", dest="dbname", help="Database name (default: openerp)", default='openerp') - parser.add_option("--host", dest="host", help="Hostname of the OpenERP Server", default="localhost") - parser.add_option("--port", dest="port", help="Port of the OpenERP Server", default="8069") - parser.add_option("--custom-values", dest="custom_values", help="Add Custom Values to the object", default=None) + parser.add_option("-u", "--user", dest="userid", + help="ID of the user in OpenERP", + default=config.OPENERP_DEFAULT_USER_ID, type='int') + parser.add_option("-p", "--password", dest="password", + help="Password of the user in OpenERP", + default=config.OPENERP_DEFAULT_PASSWORD) + parser.add_option("-o", "--model", dest="model", + help="Name or ID of crm model", + default="crm.lead") + parser.add_option("-m", "--default", dest="default", + help="Default eMail in case of any trouble.", + default=None) + parser.add_option("-d", "--dbname", dest="dbname", + help="Database name (default: %default)", + default=config.OPENERP_DEFAULT_DATABASE) + parser.add_option("--host", dest="host", + help="Hostname of the OpenERP Server", + default=config.OPENERP_HOSTNAME) + parser.add_option("--port", dest="port", + help="Port of the OpenERP Server", + default=config.OPENERP_PORT) + parser.add_option("--custom-values", dest="custom_values", + help="Add Custom Values to the object", + default=None) + return parser + +def main(): + """ + Receive the email via the stdin and send it to the OpenERP Server + """ + parser = configure_parser() (options, args) = parser.parse_args() - logging.basicConfig(level=logging.DEBUG, format="%(asctime)s %(levelname)s %(message)s") - parser = email_parser(options.userid, options.password, options.model, options.default, dbname=options.dbname, host=options.host, port=options.port) + email_parser = EmailParser(options.userid, + options.password, + options.model, + options.default, + dbname=options.dbname, + host=options.host, + port=options.port) + msg_txt = sys.stdin.read() custom_values = {} try: - custom_values = dict(eval(options.custom_values)) + custom_values = dict(eval(options.custom_values or {} )) except: pass - parser.parse(msg_txt, custom_values) + try: + email_parser.parse(msg_txt, custom_values) + except Exception: + msg = '\n'.join([ + 'parameters', + '==========', + '%r' % (options,), + 'traceback', + '=========', + '%s' % (cgitb.text(sys.exc_info())), + ]) + + subject = '[OPENERP]:ERROR: Mailgateway - %s' % time.strftime('%Y-%m-%d %H:%M:%S') + send_mail( + config.MAIL_ERROR, + config.MAIL_ADMINS, + subject, msg, files=[('message.txt', msg_txt)] + ) + +if __name__ == '__main__': + main() # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: