[IMP] mail, mass_mailing: store the bounce email and allow the user to read it
Purpose ======= The bounce emails aren't stored in Odoo, which can complicate the debugging of the email sending. Now, we store this bounce email, and we allow the user to read it from the interface, so he can easily find the issue when an email sending fail. Specifications ============== The bounce email is stored on the mail notification for standard emails sending, and on the mailing traces when using mass mailing. For some email providers (e.g. Yahoo), the "Final-Recipient" header is not present. Normally, it allows us to retrieve the original recipient of the email which bounced and then the partner. So if this header is not there in a bounce email, we take the first recipient of the parent <mail.message>. Change the way that we parse the email body, for the bounce email. For most email providers, the first mail body is the one that contains the error and the next one contains the parent email body. So, the current logic might ignore this body for Outlook and Yahoo. Task-2116296 closes odoo/odoo#105923 Related: odoo/enterprise#34051 Signed-off-by: Warnon Aurélien (awa) <awa@odoo.com>
This commit is contained in:
@@ -34,13 +34,16 @@ class MailResendMessage(models.TransientModel):
|
||||
if message_id:
|
||||
mail_message_id = self.env['mail.message'].browse(message_id)
|
||||
notification_ids = mail_message_id.notification_ids.filtered(lambda notif: notif.notification_type == 'email' and notif.notification_status in ('exception', 'bounce'))
|
||||
partner_ids = [Command.create({
|
||||
"partner_id": notif.res_partner_id.id,
|
||||
"name": notif.res_partner_id.name,
|
||||
"email": notif.res_partner_id.email,
|
||||
partner_values = [({
|
||||
"notification_id": notif.id,
|
||||
"resend": True,
|
||||
"message": notif.format_failure_reason(),
|
||||
}) for notif in notification_ids]
|
||||
|
||||
# mail.resend.partner need to exist to be able to execute an action
|
||||
partner_ids = self.env['mail.resend.partner'].create(partner_values).ids
|
||||
partner_commands = [Command.link(partner_id) for partner_id in partner_ids]
|
||||
|
||||
has_user = any(notif.res_partner_id.user_ids for notif in notification_ids)
|
||||
if has_user:
|
||||
partner_readonly = not self.env['res.users'].check_access_rights('write', raise_exception=False)
|
||||
@@ -49,7 +52,7 @@ class MailResendMessage(models.TransientModel):
|
||||
rec['partner_readonly'] = partner_readonly
|
||||
rec['notification_ids'] = [Command.set(notification_ids.ids)]
|
||||
rec['mail_message_id'] = mail_message_id.id
|
||||
rec['partner_ids'] = partner_ids
|
||||
rec['partner_ids'] = partner_commands
|
||||
else:
|
||||
raise UserError(_('No message_id found in context'))
|
||||
return rec
|
||||
@@ -60,26 +63,14 @@ class MailResendMessage(models.TransientModel):
|
||||
for wizard in self:
|
||||
"If a partner disappeared from partner list, we cancel the notification"
|
||||
to_cancel = wizard.partner_ids.filtered(lambda p: not p.resend).mapped("partner_id")
|
||||
to_send = wizard.partner_ids.filtered(lambda p: p.resend).mapped("partner_id")
|
||||
to_send = wizard.partner_ids.filtered(lambda p: p.resend)
|
||||
notif_to_cancel = wizard.notification_ids.filtered(lambda notif: notif.notification_type == 'email' and notif.res_partner_id in to_cancel and notif.notification_status in ('exception', 'bounce'))
|
||||
notif_to_cancel.sudo().write({'notification_status': 'canceled'})
|
||||
if to_send:
|
||||
message = wizard.mail_message_id
|
||||
record = self.env[message.model].browse(message.res_id) if message.is_thread_message() else self.env['mail.thread']
|
||||
|
||||
email_partners_data = []
|
||||
recipients_data = self.env['mail.followers']._get_recipient_data(None, 'comment', False, pids=to_send.ids)[0]
|
||||
for pid, pdata in recipients_data.items():
|
||||
if pid and pdata.get('notif', 'email') == 'email':
|
||||
email_partners_data.append(pdata)
|
||||
|
||||
record._notify_thread_by_email(
|
||||
message, email_partners_data,
|
||||
resend_existing=True,
|
||||
send_after_commit=False
|
||||
)
|
||||
|
||||
self.mail_message_id._notify_message_notification_update()
|
||||
# this will update the notification already
|
||||
to_send.action_resend()
|
||||
else:
|
||||
self.mail_message_id._notify_message_notification_update()
|
||||
return {'type': 'ir.actions.act_window_close'}
|
||||
|
||||
def cancel_mail_action(self):
|
||||
@@ -94,9 +85,54 @@ class PartnerResend(models.TransientModel):
|
||||
_name = 'mail.resend.partner'
|
||||
_description = 'Partner with additional information for mail resend'
|
||||
|
||||
partner_id = fields.Many2one('res.partner', string='Partner', required=True, ondelete='cascade')
|
||||
notification_id = fields.Many2one('mail.notification', string='Notification', required=True, ondelete='cascade')
|
||||
partner_id = fields.Many2one('res.partner', string='Partner', related='notification_id.res_partner_id')
|
||||
name = fields.Char(related='partner_id.name', string='Recipient Name', related_sudo=False, readonly=False)
|
||||
email = fields.Char(related='partner_id.email', string='Email Address', related_sudo=False, readonly=False)
|
||||
failure_reason = fields.Text('Failure Reason', related='notification_id.failure_reason')
|
||||
resend = fields.Boolean(string='Try Again', default=True)
|
||||
resend_wizard_id = fields.Many2one('mail.resend.message', string="Resend wizard")
|
||||
message = fields.Char(string='Error message')
|
||||
partner_readonly = fields.Boolean('Partner Readonly', related='resend_wizard_id.partner_readonly')
|
||||
|
||||
def action_open_record(self):
|
||||
self.ensure_one()
|
||||
message = self.notification_id.mail_message_id
|
||||
return {
|
||||
'type': 'ir.actions.act_window',
|
||||
'res_model': message.model,
|
||||
'res_id': message.res_id,
|
||||
'view_ids': [(False, 'form')],
|
||||
'view_mode': 'form',
|
||||
'target': 'current',
|
||||
}
|
||||
|
||||
def action_open_resend_partner(self):
|
||||
self.ensure_one()
|
||||
action = self.env['ir.actions.act_window']._for_xml_id('mail.mail_resend_partner_action')
|
||||
action['res_id'] = self.id
|
||||
return action
|
||||
|
||||
def action_resend(self):
|
||||
message = self.resend_wizard_id.mail_message_id
|
||||
if len(message) != 1:
|
||||
raise UserError(_('All partners must belong to the same message'))
|
||||
|
||||
recipients_data = self.env['mail.followers']._get_recipient_data(None, 'comment', False, pids=self.partner_id.ids)
|
||||
email_partners_data = [
|
||||
pdata
|
||||
for pid, pdata in recipients_data[0].items()
|
||||
if pid and pdata.get('notif', 'email') == 'email'
|
||||
]
|
||||
|
||||
record = self.env[message.model].browse(message.res_id) if message.is_thread_message() else self.env['mail.thread']
|
||||
record._notify_thread_by_email(
|
||||
message, email_partners_data,
|
||||
resend_existing=True,
|
||||
send_after_commit=False
|
||||
)
|
||||
|
||||
message._notify_message_notification_update()
|
||||
|
||||
if len(self) == 1:
|
||||
return self.action_open_record()
|
||||
|
||||
@@ -16,8 +16,9 @@
|
||||
<field name="name" readonly="1"/>
|
||||
<field name="email" attrs="{'readonly': [('parent.partner_readonly', '=', True)]}"/>
|
||||
<field name="message" readonly="1" class="text-wrap"/>
|
||||
<field name="partner_id" invisible="1"/>
|
||||
<field name="resend" widget="boolean_toggle"/>
|
||||
<button name="action_open_resend_partner" type="object"
|
||||
string="See Error Details" class="btn-link"/>
|
||||
</tree>
|
||||
</field>
|
||||
<footer>
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data>
|
||||
<record id="mail_resend_partner_view_form" model="ir.ui.view">
|
||||
<field name="name">mail.resend.partner.view.form</field>
|
||||
<field name="model">mail.resend.partner</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Partner">
|
||||
<header>
|
||||
<button name="action_resend" type="object" string="Resend" class="oe_highlight"
|
||||
attrs="{'invisible': [('failure_reason', '=', False)]}"/>
|
||||
</header>
|
||||
<sheet>
|
||||
<div class="oe_button_box" name="button_box">
|
||||
<button class="oe_stat_button" name="action_open_record" type="object" icon="fa-user">
|
||||
<span>Open Record</span>
|
||||
</button>
|
||||
</div>
|
||||
<group col="2">
|
||||
<group colspan="1">
|
||||
<field name="notification_id" invisible="1"/>
|
||||
<field name="partner_readonly" invisible="1"/>
|
||||
<field name="name" readonly="1" required="1"/>
|
||||
<field name="email" attrs="{'readonly': [('partner_readonly', '=', True)]}"/>
|
||||
</group>
|
||||
</group>
|
||||
<notebook>
|
||||
<page string="Failure Reason" name="page_failure_reason">
|
||||
<field name="failure_reason"
|
||||
class="text-wrap w-100 overflow-auto"
|
||||
nolabel="1"/>
|
||||
</page>
|
||||
</notebook>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
<record id="mail_resend_partner_action" model="ir.actions.act_window">
|
||||
<field name="name">Resend Email</field>
|
||||
<field name="res_model">mail.resend.partner</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="target">current</field>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
Reference in New Issue
Block a user