From 27eb42fd28e6ae229e8c34da82b75919fe366284 Mon Sep 17 00:00:00 2001 From: Ivan Yelizariev Date: Thu, 6 Feb 2014 16:19:37 +0600 Subject: [PATCH] more radical solution --- mail_fix_553.py | 109 ++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 100 insertions(+), 9 deletions(-) diff --git a/mail_fix_553.py b/mail_fix_553.py index 378b4cb..84a5604 100644 --- a/mail_fix_553.py +++ b/mail_fix_553.py @@ -1,23 +1,114 @@ # -*- coding: utf-8 -*- +import base64 +import logging import re -from openerp.osv import osv, fields +from urllib import urlencode +from urlparse import urljoin + +from openerp import tools from openerp import SUPERUSER_ID +from openerp.addons.base.ir.ir_mail_server import MailDeliveryException +from openerp.osv import fields, osv +from openerp.tools.translate import _ + +_logger = logging.getLogger(__name__) class mail_mail(osv.Model): _inherit = "mail.mail" - def send(self, cr, uid, ids, context=None, **kwargs): + def send(self, cr, uid, ids, auto_commit=False, raise_exception=False, context=None): + """ Sends the selected emails immediately, ignoring their current + state (mails that have already been sent should not be passed + unless they should actually be re-sent). + Emails successfully delivered are marked as 'sent', and those + that fail to be deliver are marked as 'exception', and the + corresponding error mail is output in the server logs. + + :param bool auto_commit: whether to force a commit of the mail status + after sending each mail (meant only for scheduler processing); + should never be True during normal transactions (default: False) + :param bool raise_exception: whether to raise an exception if the + email sending process has failed + :return: True + """ catchall_alias = self.pool['ir.config_parameter'].get_param(cr, uid, "mail.catchall.alias", context=context) catchall_domain = self.pool['ir.config_parameter'].get_param(cr, uid, "mail.catchall.domain", context=context) - fix_ids = [] + correct_email_from = '@%s>?\s*$'%catchall_domain + default_email_from = '%s@%s' % (catchall_alias, catchall_domain) + + ir_mail_server = self.pool.get('ir.mail_server') + for mail in self.browse(cr, SUPERUSER_ID, ids, context=context): - if re.search('@%s>?\s*$'%catchall_domain, mail.email_from) is None: - fix_ids.append(mail.id) + try: + # handle attachments + attachments = [] + for attach in mail.attachment_ids: + attachments.append((attach.datas_fname, base64.b64decode(attach.datas))) + # specific behavior to customize the send email for notified partners + email_list = [] + if mail.email_to: + email_list.append(self.send_get_email_dict(cr, uid, mail, context=context)) + for partner in mail.recipient_ids: + email_list.append(self.send_get_email_dict(cr, uid, mail, partner=partner, context=context)) + # headers + headers = {} + bounce_alias = self.pool['ir.config_parameter'].get_param(cr, uid, "mail.bounce.alias", context=context) + catchall_domain = self.pool['ir.config_parameter'].get_param(cr, uid, "mail.catchall.domain", context=context) + if bounce_alias and catchall_domain: + if mail.model and mail.res_id: + headers['Return-Path'] = '%s-%d-%s-%d@%s' % (bounce_alias, mail.id, mail.model, mail.res_id, catchall_domain) + else: + headers['Return-Path'] = '%s-%d@%s' % (bounce_alias, mail.id, catchall_domain) + + # build an RFC2822 email.message.Message object and send it without queuing + res = None + for email in email_list: + email_from = mail.email_from + if re.search(correct_email_from, email_from) is None: + email_from = default_email_from - email_from = '%s@%s' % (catchall_alias, catchall_domain) + msg = ir_mail_server.build_email( + email_from=email_from, + email_to=email.get('email_to'), + subject=email.get('subject'), + body=email.get('body'), + body_alternative=email.get('body_alternative'), + email_cc=tools.email_split(mail.email_cc), + reply_to=mail.reply_to, + attachments=attachments, + message_id=mail.message_id, + references=mail.references, + object_id=mail.res_id and ('%s-%s' % (mail.res_id, mail.model)), + subtype='html', + subtype_alternative='plain', + headers=headers) + res = ir_mail_server.send_email(cr, uid, msg, + mail_server_id=mail.mail_server_id.id, + context=context) + + if res: + mail.write({'state': 'sent', 'message_id': res}) + mail_sent = True + else: + mail.write({'state': 'exception'}) + mail_sent = False - if fix_ids: - self.write(cr, uid, fix_ids, {'email_from': email_from}, context=context) + # /!\ can't use mail.state here, as mail.refresh() will cause an error + # see revid:odo@openerp.com-20120622152536-42b2s28lvdv3odyr in 6.1 + if mail_sent: + self._postprocess_sent_message(cr, uid, mail, context=context) + except Exception as e: + _logger.exception('failed sending mail.mail %s', mail.id) + mail.write({'state': 'exception'}) + if raise_exception: + if isinstance(e, AssertionError): + # get the args of the original error, wrap into a value and throw a MailDeliveryException + # that is an except_orm, with name and value as arguments + value = '. '.join(e.args) + raise MailDeliveryException(_("Mail Delivery Failed"), value) + raise - return super(mail_mail, self).send(cr, uid, ids, context=context, **kwargs) + if auto_commit == True: + cr.commit() + return True