diff --git a/mail_tracking/README.rst b/mail_tracking/README.rst index 4c3f34548..1313f1840 100644 --- a/mail_tracking/README.rst +++ b/mail_tracking/README.rst @@ -52,28 +52,31 @@ status icon will appear just right to name of notified partner. These are all available status icons: -.. |sent| image:: ../static/src/img/sent.png +.. |sent| image:: https://raw.githubusercontent.com/OCA/social/12.0/mail_tracking/static/src/img/sent.png :width: 10px -.. |delivered| image:: ../static/src/img/delivered.png +.. |delivered| image:: https://raw.githubusercontent.com/OCA/social/12.0/mail_tracking/static/src/img/delivered.png :width: 15px -.. |opened| image:: ../static/src/img/opened.png +.. |opened| image:: https://raw.githubusercontent.com/OCA/social/12.0/mail_tracking/static/src/img/opened.png :width: 15px -.. |error| image:: ../static/src/img/error.png +.. |error| image:: https://raw.githubusercontent.com/OCA/social/12.0/mail_tracking/static/src/img/error.png :width: 10px -.. |waiting| image:: ../static/src/img/waiting.png +.. |waiting| image:: https://raw.githubusercontent.com/OCA/social/12.0/mail_tracking/static/src/img/waiting.png :width: 10px -.. |unknown| image:: ../static/src/img/unknown.png +.. |unknown| image:: https://raw.githubusercontent.com/OCA/social/12.0/mail_tracking/static/src/img/unknown.png :width: 10px -.. |cc| image:: ../static/src/img/cc.png +.. |cc| image:: https://raw.githubusercontent.com/OCA/social/12.0/mail_tracking/static/src/img/cc.png :width: 10px -.. |noemail| image:: ../static/src/img/no_email.png +.. |noemail| image:: https://raw.githubusercontent.com/OCA/social/12.0/mail_tracking/static/src/img/no_email.png + :width: 10px + +.. |anonuser| image:: https://raw.githubusercontent.com/OCA/social/12.0/mail_tracking/static/src/img/anon_user.png :width: 10px |unknown| **Unknown**: No email tracking info available. Maybe this notified partner has 'Receive Inbox Notifications by Email' == 'Never' @@ -92,6 +95,8 @@ These are all available status icons: |noemail| **No Email**: The partner doesn't have a defined email +|anonuser| **No Partner**: The recipient doesn't have a defined partner + If you want to see all tracking emails and events you can go to diff --git a/mail_tracking/models/__init__.py b/mail_tracking/models/__init__.py index 896721a63..0f2e248a4 100644 --- a/mail_tracking/models/__init__.py +++ b/mail_tracking/models/__init__.py @@ -9,3 +9,4 @@ from . import mail_tracking_event from . import res_partner from . import mail_thread from . import mail_resend_message +from . import mail_alias diff --git a/mail_tracking/models/mail_alias.py b/mail_tracking/models/mail_alias.py new file mode 100644 index 000000000..45b7cfee4 --- /dev/null +++ b/mail_tracking/models/mail_alias.py @@ -0,0 +1,34 @@ +# Copyright 2020 Alexandre Díaz +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from odoo import api, models, tools + + +class MailAlias(models.Model): + _inherit = 'mail.alias' + + @api.model + @tools.ormcache() + def get_aliases(self): + return set(x['display_name'] for x in self.search_read([ + ('alias_name', '!=', False), + ], ['display_name'])) + + @api.model_create_multi + def create(self, vals_list): + res = super().create(vals_list) + self.clear_caches() + return res + + @api.multi + def write(self, vals): + res = super().write(vals) + if 'alias_name' in vals: + self.clear_caches() + return res + + @api.multi + def unlink(self): + res = super().unlink() + self.clear_caches() + return res diff --git a/mail_tracking/models/mail_message.py b/mail_tracking/models/mail_message.py index 6f407c276..8d8fa60a3 100644 --- a/mail_tracking/models/mail_message.py +++ b/mail_tracking/models/mail_message.py @@ -3,6 +3,7 @@ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). from odoo import _, models, api, fields +from email.utils import getaddresses from odoo.tools import email_split @@ -12,6 +13,7 @@ class MailMessage(models.Model): # Recipients email_cc = fields.Char("Cc", help='Additional recipients that receive a ' '"Carbon Copy" of the e-mail') + email_to = fields.Char("To", help='Raw TO recipients') mail_tracking_ids = fields.One2many( comodel_name='mail.tracking.email', inverse_name='mail_message_id', @@ -94,11 +96,16 @@ class MailMessage(models.Model): trackings = self.env['mail.tracking.email'].sudo().search([ ('mail_message_id', '=', message.id), ]) - # Get Cc recipients - email_cc_list = email_split(message.email_cc) - if any(email_cc_list): - partners |= partners.search([('email', 'in', email_cc_list)]) + # String to List + email_cc_list = self._drop_aliases(email_split(message.email_cc)) + email_to_list = self._drop_aliases(email_split(message.email_to)) + # Search related partners recipients + partners |= partners.search([ + ('email', 'in', email_cc_list + email_to_list), + ]) + # Operate over set's instead of lists email_cc_list = set(email_cc_list) + email_to_list = set(email_to_list) - email_cc_list # Search all trackings for this message for tracking in trackings: status = self._partner_tracking_status_get(tracking) @@ -117,16 +124,19 @@ class MailMessage(models.Model): 'isCc': False, }) if tracking.partner_id: + # Discard mails with tracking email_cc_list.discard(tracking.partner_id.email) + email_to_list.discard(tracking.partner_id.email) partners_already |= tracking.partner_id - # Search all recipients for this message + # Search all partner recipients for this message if message.partner_ids: partners |= message.partner_ids if message.needaction_partner_ids: partners |= message.needaction_partner_ids - # Remove recipients already included + # Discard partner recipients already included partners -= partners_already - tracking_unkown_values = { + # Default tracking values + tracking_unknown_values = { 'status': 'unknown', 'status_human': self._partner_tracking_status_human_get( 'unknown'), @@ -134,33 +144,50 @@ class MailMessage(models.Model): 'error_description': False, 'tracking_id': False, } + # Process tracking status of partner recipients without tracking for partner in partners: + # Discard 'To' with partner + if partner.email in email_to_list: + email_to_list.discard(partner.email) # If there is partners not included, then status is 'unknown' # and perhaps a Cc recipient isCc = False if partner.email in email_cc_list: email_cc_list.discard(partner.email) isCc = True - tracking_unkown_values.update({ + tracking_status = tracking_unknown_values.copy() + tracking_status.update({ 'recipient': partner.name, 'partner_id': partner.id, 'isCc': isCc, }) - partner_trackings.append(tracking_unkown_values.copy()) - for email in email_cc_list: - # If there is Cc without partner - tracking_unkown_values.update({ - 'recipient': email, - 'partner_id': False, - 'isCc': True, - }) - partner_trackings.append(tracking_unkown_values.copy()) + partner_trackings.append(tracking_status) + # Process Cc/To recipients without partner + for cc, lst in [(True, email_cc_list), (False, email_to_list)]: + for email in lst: + tracking_status = tracking_unknown_values.copy() + tracking_status.update({ + 'recipient': email, + 'partner_id': False, + 'isCc': cc, + }) + partner_trackings.append(tracking_status) res[message.id] = { 'partner_trackings': partner_trackings, 'is_failed_message': message.is_failed_message, } return res + @api.model + def _drop_aliases(self, mail_list): + aliases = self.env['mail.alias'].get_aliases() + + def _filter_alias(email): + email_wn = getaddresses([email])[0][1] + if email_wn not in aliases: + return email_wn + return list(filter(_filter_alias, mail_list)) + @api.model def _message_read_dict_postprocess(self, messages, message_tree): """Preare values to be used by the chatter widget""" diff --git a/mail_tracking/models/mail_thread.py b/mail_tracking/models/mail_thread.py index 4022781ed..ccf27e0c8 100644 --- a/mail_tracking/models/mail_thread.py +++ b/mail_tracking/models/mail_thread.py @@ -30,43 +30,51 @@ class MailThread(models.AbstractModel): def message_post(self, *args, **kwargs): """Adds CC recipient to the message. - Because Odoo implementation avoid store cc recipients we ensure that - this information its written into the mail.message record. + Because Odoo implementation avoid store 'from, to, cc' recipients we + ensure that this information its written into the mail.message record. """ - new_message = super().message_post(*args, **kwargs) - email_cc = kwargs.get('cc') - if email_cc: - new_message.sudo().write({ - 'email_cc': email_cc, - }) - return new_message + kwargs.update({ + 'email_cc': kwargs.get('cc', False), + 'email_to': kwargs.get('to', False), + }) + return super().message_post(*args, **kwargs) @api.multi def message_get_suggested_recipients(self): - """Adds email Cc recipients as suggested recipients. + """Adds email 'extra' recipients as suggested recipients. If the recipient has a res.partner, use it. """ res = super().message_get_suggested_recipients() + self._add_extra_recipients_suggestions(res, 'email_cc', _('Cc')) + self._add_extra_recipients_suggestions(res, 'email_to', _('Anon. To')) + return res + + def _add_extra_recipients_suggestions(self, suggestions, field_mail, + reason): ResPartnerObj = self.env['res.partner'] - email_cc_formated_list = [] + aliases = self.env['mail.alias'].get_aliases() + email_extra_formated_list = [] for record in self: - emails_cc = record.message_ids.mapped('email_cc') - for email in emails_cc: - email_cc_formated_list.extend(email_split_and_format(email)) - email_cc_formated_list = set(email_cc_formated_list) - for cc in email_cc_formated_list: - email_parts = getaddresses([cc])[0] - partner_id = record.message_partner_info_from_emails( - [email_parts[1]])[0].get('partner_id') + emails_extra = record.message_ids.mapped(field_mail) + for email in emails_extra: + email_extra_formated_list.extend(email_split_and_format(email)) + email_extra_formated_list = set(email_extra_formated_list) + email_extra_list = [ + x[1] for x in getaddresses(email_extra_formated_list)] + partners_info = record.message_partner_info_from_emails( + email_extra_list) + for pinfo in partners_info: + partner_id = pinfo['partner_id'] + email = pinfo['full_name'] if not partner_id: - record._message_add_suggested_recipient( - res, email=cc, reason=_('Cc')) + if email not in aliases: + record._message_add_suggested_recipient( + suggestions, email=email, reason=reason) else: partner = ResPartnerObj.browse(partner_id, self._prefetch) record._message_add_suggested_recipient( - res, partner=partner, reason=_('Cc')) - return res + suggestions, partner=partner, reason=reason) @api.model def _fields_view_get(self, view_id=None, view_type='form', toolbar=False, diff --git a/mail_tracking/readme/USAGE.rst b/mail_tracking/readme/USAGE.rst index aa633338f..2488328ec 100644 --- a/mail_tracking/readme/USAGE.rst +++ b/mail_tracking/readme/USAGE.rst @@ -28,6 +28,9 @@ These are all available status icons: .. |noemail| image:: ../static/src/img/no_email.png :width: 10px +.. |anonuser| image:: ../static/src/img/anon_user.png + :width: 10px + |unknown| **Unknown**: No email tracking info available. Maybe this notified partner has 'Receive Inbox Notifications by Email' == 'Never' |waiting| **Waiting**: Waiting to be sent @@ -44,6 +47,8 @@ These are all available status icons: |noemail| **No Email**: The partner doesn't have a defined email +|anonuser| **No Partner**: The recipient doesn't have a defined partner + If you want to see all tracking emails and events you can go to diff --git a/mail_tracking/static/description/index.html b/mail_tracking/static/description/index.html index 36ea5bcba..edc176fbb 100644 --- a/mail_tracking/static/description/index.html +++ b/mail_tracking/static/description/index.html @@ -404,14 +404,15 @@ For example, --load=web,mail_trac form, then an email tracking is created for each email notification. Then a status icon will appear just right to name of notified partner.
These are all available status icons:
- Unknown: No email tracking info available. Maybe this notified partner has ‘Receive Inbox Notifications by Email’ == ‘Never’
Waiting: Waiting to be sent
Error: Error while sending
Sent: Sent to SMTP server configured
Delivered: Delivered to final MX server
Opened: Opened by partner
Cc: It’s a Carbon-Copy recipient. Can’t know the status so is ‘Unknown’
No Email: The partner doesn’t have a defined email
Unknown: No email tracking info available. Maybe this notified partner has ‘Receive Inbox Notifications by Email’ == ‘Never’
Waiting: Waiting to be sent
Error: Error while sending
Sent: Sent to SMTP server configured
Delivered: Delivered to final MX server
Opened: Opened by partner
Cc: It’s a Carbon-Copy recipient. Can’t know the status so is ‘Unknown’
No Email: The partner doesn’t have a defined email
No Partner: The recipient doesn’t have a defined partner
If you want to see all tracking emails and events you can go to
This is a test message
', cc='unnamed@test.com, sender@example.com'