[IMP] mass_mailing: add 'view in browser' link in mailings
PURPOSE Add a block that allows recipients to check the email in a browser in case their mail service provider does not render it well or to see it full screen. SPECIFICATIONS A thumbnail has been added in the snippet thumbnails list of the mail editor. It allows to add an header snippet. This snippet contains a link allowing the recipient to see the mail in its browser instead of its mail client. Add a route to display a mailing content. This route should be recipient dependent as mailings could contain jinja markers. Using the same access token and check as unsubscribe route this public route allows to display a mailing content directly rendered for a given customer. _get_unsubscribe_url method is moved from mail_mail to mailing as it does not really belong to the mail model. Indeed it is mailing dependent. A view URL leading to the view in browser route is added. It is managed like the unsubscribe url: magically avoid shortening, magically rewrite when sending email. Task ID-2239327 PR #49886
This commit is contained in:
committed by
Thibault Delavallée
parent
0809601d6d
commit
ac0579263b
@@ -105,6 +105,35 @@ class MassMailController(http.Controller):
|
||||
|
||||
return response
|
||||
|
||||
@http.route(['/mailing/<int:mailing_id>/view'], type='http', website=True, auth='public')
|
||||
def view(self, mailing_id, email=None, res_id=None, token=""):
|
||||
mailing = request.env['mailing.mailing'].sudo().browse(mailing_id)
|
||||
if mailing.exists():
|
||||
res_id = int(res_id) if res_id else False
|
||||
if not self._valid_unsubscribe_token(mailing_id, res_id, email, str(token)) and not request.env.user.has_group('mass_mailing.group_mass_mailing_user'):
|
||||
raise exceptions.AccessDenied()
|
||||
|
||||
res = mailing.convert_links()
|
||||
base_url = request.env['ir.config_parameter'].sudo().get_param('web.base.url').rstrip('/')
|
||||
urls_to_replace = [
|
||||
(base_url + '/unsubscribe_from_list', mailing._get_unsubscribe_url(email, res_id)),
|
||||
(base_url + '/view', mailing._get_view_url(email, res_id))
|
||||
]
|
||||
for url_to_replace, new_url in urls_to_replace:
|
||||
if url_to_replace in res[mailing_id]:
|
||||
res[mailing_id] = res[mailing_id].replace(url_to_replace, new_url if new_url else '#')
|
||||
|
||||
res[mailing_id] = res[mailing_id].replace(
|
||||
'class="o_snippet_view_in_browser"',
|
||||
'class="o_snippet_view_in_browser" style="display: none;"'
|
||||
)
|
||||
|
||||
return request.render('mass_mailing.view', {
|
||||
'body': res[mailing_id],
|
||||
})
|
||||
|
||||
return request.redirect('/web')
|
||||
|
||||
@http.route('/r/<string:code>/m/<int:mailing_trace_id>', type='http', auth="public")
|
||||
def full_url_redirect(self, code, mailing_trace_id, **post):
|
||||
# don't assume geoip is set, it is part of the website module
|
||||
|
||||
@@ -29,21 +29,6 @@ class MailMail(models.Model):
|
||||
token = tools.hmac(self.env(su=True), 'mass_mailing-mail_mail-open', self.id)
|
||||
return werkzeug.urls.url_join(base_url, 'mail/track/%s/%s/blank.gif' % (self.id, token))
|
||||
|
||||
def _get_unsubscribe_url(self, email_to):
|
||||
base_url = self.env['ir.config_parameter'].sudo().get_param('web.base.url')
|
||||
url = werkzeug.urls.url_join(
|
||||
base_url, 'mail/mailing/%(mailing_id)s/unsubscribe?%(params)s' % {
|
||||
'mailing_id': self.mailing_id.id,
|
||||
'params': werkzeug.urls.url_encode({
|
||||
'res_id': self.res_id,
|
||||
'email': email_to,
|
||||
'token': self.mailing_id._unsubscribe_token(
|
||||
self.res_id, email_to),
|
||||
}),
|
||||
}
|
||||
)
|
||||
return url
|
||||
|
||||
def _send_prepare_body(self):
|
||||
""" Override to add the tracking URL to the body and to add
|
||||
trace ID in shortened urls """
|
||||
@@ -81,10 +66,15 @@ class MailMail(models.Model):
|
||||
if self.mailing_id and res.get('body') and res.get('email_to'):
|
||||
emails = tools.email_split(res.get('email_to')[0])
|
||||
email_to = emails and emails[0] or False
|
||||
unsubscribe_url = self._get_unsubscribe_url(email_to)
|
||||
link_to_replace = base_url + '/unsubscribe_from_list'
|
||||
if link_to_replace in res['body']:
|
||||
res['body'] = res['body'].replace(link_to_replace, unsubscribe_url if unsubscribe_url else '#')
|
||||
|
||||
urls_to_replace = [
|
||||
(base_url + '/unsubscribe_from_list', self.mailing_id._get_unsubscribe_url(email_to, self.res_id)),
|
||||
(base_url + '/view', self.mailing_id._get_view_url(email_to, self.res_id))
|
||||
]
|
||||
|
||||
for url_to_replace, new_url in urls_to_replace:
|
||||
if url_to_replace in res['body']:
|
||||
res['body'] = res['body'].replace(url_to_replace, new_url if new_url else '#')
|
||||
return res
|
||||
|
||||
def _postprocess_sent_message(self, success_pids, failure_reason=False, failure_type=None):
|
||||
|
||||
@@ -18,6 +18,6 @@ class MailRenderMixin(models.AbstractModel):
|
||||
rendered[res_id] = self._shorten_links(
|
||||
html,
|
||||
self.env.context['post_convert_links'],
|
||||
blacklist=['/unsubscribe_from_list']
|
||||
blacklist=['/unsubscribe_from_list', '/view']
|
||||
)
|
||||
return rendered
|
||||
|
||||
@@ -8,6 +8,7 @@ import lxml
|
||||
import random
|
||||
import re
|
||||
import threading
|
||||
import werkzeug.urls
|
||||
from ast import literal_eval
|
||||
from datetime import datetime
|
||||
from dateutil.relativedelta import relativedelta
|
||||
@@ -528,6 +529,34 @@ class MassMailing(models.Model):
|
||||
done_res_ids = [record['res_id'] for record in already_mailed]
|
||||
return [rid for rid in res_ids if rid not in done_res_ids]
|
||||
|
||||
def _get_unsubscribe_url(self, email_to, res_id):
|
||||
base_url = self.env['ir.config_parameter'].sudo().get_param('web.base.url')
|
||||
url = werkzeug.urls.url_join(
|
||||
base_url, 'mail/mailing/%(mailing_id)s/unsubscribe?%(params)s' % {
|
||||
'mailing_id': self.id,
|
||||
'params': werkzeug.urls.url_encode({
|
||||
'res_id': res_id,
|
||||
'email': email_to,
|
||||
'token': self._unsubscribe_token(res_id, email_to),
|
||||
}),
|
||||
}
|
||||
)
|
||||
return url
|
||||
|
||||
def _get_view_url(self, email_to, res_id):
|
||||
base_url = self.env['ir.config_parameter'].sudo().get_param('web.base.url')
|
||||
url = werkzeug.urls.url_join(
|
||||
base_url, 'mailing/%(mailing_id)s/view?%(params)s' % {
|
||||
'mailing_id': self.id,
|
||||
'params': werkzeug.urls.url_encode({
|
||||
'res_id': res_id,
|
||||
'email': email_to,
|
||||
'token': self._unsubscribe_token(res_id, email_to),
|
||||
}),
|
||||
}
|
||||
)
|
||||
return url
|
||||
|
||||
def action_send_mail(self, res_ids=None):
|
||||
author_id = self.env.user.partner_id.id
|
||||
|
||||
@@ -583,7 +612,7 @@ class MassMailing(models.Model):
|
||||
if mass_mailing.medium_id:
|
||||
vals['medium_id'] = mass_mailing.medium_id.id
|
||||
|
||||
res[mass_mailing.id] = mass_mailing._shorten_links(html, vals, blacklist=['/unsubscribe_from_list'])
|
||||
res[mass_mailing.id] = mass_mailing._shorten_links(html, vals, blacklist=['/unsubscribe_from_list', '/view'])
|
||||
|
||||
return res
|
||||
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 376 B |
@@ -97,6 +97,11 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template id="view" name="Browser View">
|
||||
<!-- Raw body inserted here because it is a rendered mailing, therefore internal content -->
|
||||
<t t-raw="body"/>
|
||||
</template>
|
||||
|
||||
<template id="page_unsubscribe" name="Unsubscribe">
|
||||
<t t-call="mass_mailing.layout">
|
||||
<t t-call="mass_mailing.unsubscribe"/>
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
<t t-snippet="mass_mailing.s_mail_block_header_text_social" t-thumbnail="/mass_mailing/static/src/img/blocks/block_header_text_social.png"/>
|
||||
<t t-snippet="mass_mailing.s_mail_block_header_logo" t-thumbnail="/mass_mailing/static/src/img/blocks/block_header_logo.png"/>
|
||||
<t t-snippet="mass_mailing.s_mail_block_banner" t-thumbnail="/mass_mailing/static/src/img/blocks/block_banner.png"/>
|
||||
<t t-snippet="mass_mailing.s_mail_block_header_view" t-thumbnail="/mass_mailing/static/src/img/blocks/block_header_browser.png"/>
|
||||
</div>
|
||||
</div>
|
||||
<div id="email_designer_default_body" class="o_panel">
|
||||
@@ -154,6 +155,24 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template id="s_mail_block_header_view" name="View in browser">
|
||||
<div class="o_snippet_view_in_browser">
|
||||
<div class="o_mail_snippet_general">
|
||||
<table align="center" cellspacing="0" cellpadding="0" border="0" class="o_mail_table_styles">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td width="100%" class="o_mail_h_padding o_mail_v_padding o_mail_no_colorpicker text-center">
|
||||
<a href="/view">
|
||||
View this email in your browser
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template id="s_mail_block_title_text" name="Title Content">
|
||||
<div class="o_mail_block_title_text">
|
||||
<div class="o_mail_snippet_general">
|
||||
|
||||
Reference in New Issue
Block a user