[MERGE] mail_gateway: handling of processing failures using fallback email

bzr revid: odo@openerp.com-20110504144617-3xlrimbfaqrbq0fy
This commit is contained in:
Stephane Wirtel 2011-05-04 16:46:17 +02:00 committed by Olivier Dony
commit fb9104f4bf
1 changed files with 132 additions and 28 deletions

View File

@ -19,15 +19,71 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>
#
###########################################################################################
##############################################################################
"""
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: