##// END OF EJS Templates
emails: set References header for threading in mail user agents even with different subjects...
marcink -
r4447:ae62a3cc default
parent child Browse files
Show More
@@ -578,8 +578,7 b' class AdminSettingsView(BaseAppView):'
578 'user': self._rhodecode_db_user
578 'user': self._rhodecode_db_user
579 }
579 }
580
580
581 (subject, headers, email_body,
581 (subject, email_body, email_body_plaintext) = EmailNotificationModel().render_email(
582 email_body_plaintext) = EmailNotificationModel().render_email(
583 EmailNotificationModel.TYPE_EMAIL_TEST, **email_kwargs)
582 EmailNotificationModel.TYPE_EMAIL_TEST, **email_kwargs)
584
583
585 recipients = [test_email] if test_email else None
584 recipients = [test_email] if test_email else None
@@ -376,8 +376,7 b' users: description edit fixes'
376 }
376 }
377
377
378 template_type = email_id.split('+')[0]
378 template_type = email_id.split('+')[0]
379 (c.subject, c.headers, c.email_body,
379 (c.subject, c.email_body, c.email_body_plaintext) = EmailNotificationModel().render_email(
380 c.email_body_plaintext) = EmailNotificationModel().render_email(
381 template_type, **email_kwargs.get(email_id, {}))
380 template_type, **email_kwargs.get(email_id, {}))
382
381
383 test_email = self.request.GET.get('email')
382 test_email = self.request.GET.get('email')
@@ -29,6 +29,7 b' import time'
29 from pyramid import compat
29 from pyramid import compat
30 from pyramid_mailer.mailer import Mailer
30 from pyramid_mailer.mailer import Mailer
31 from pyramid_mailer.message import Message
31 from pyramid_mailer.message import Message
32 from email.utils import formatdate
32
33
33 import rhodecode
34 import rhodecode
34 from rhodecode.lib import audit_logger
35 from rhodecode.lib import audit_logger
@@ -40,7 +41,8 b' from rhodecode.model.db import ('
40
41
41
42
42 @async_task(ignore_result=True, base=RequestContextTask)
43 @async_task(ignore_result=True, base=RequestContextTask)
43 def send_email(recipients, subject, body='', html_body='', email_config=None):
44 def send_email(recipients, subject, body='', html_body='', email_config=None,
45 extra_headers=None):
44 """
46 """
45 Sends an email with defined parameters from the .ini files.
47 Sends an email with defined parameters from the .ini files.
46
48
@@ -50,6 +52,7 b' def send_email(recipients, subject, body'
50 :param body: body of the mail
52 :param body: body of the mail
51 :param html_body: html version of body
53 :param html_body: html version of body
52 :param email_config: specify custom configuration for mailer
54 :param email_config: specify custom configuration for mailer
55 :param extra_headers: specify custom headers
53 """
56 """
54 log = get_logger(send_email)
57 log = get_logger(send_email)
55
58
@@ -108,13 +111,23 b' def send_email(recipients, subject, body'
108 # sendmail_template='',
111 # sendmail_template='',
109 )
112 )
110
113
114 if extra_headers is None:
115 extra_headers = {}
116
117 extra_headers.setdefault('Date', formatdate(time.time()))
118
119 if 'thread_ids' in extra_headers:
120 thread_ids = extra_headers.pop('thread_ids')
121 extra_headers['References'] = ' '.join('<{}>'.format(t) for t in thread_ids)
122
111 try:
123 try:
112 mailer = Mailer(**email_conf)
124 mailer = Mailer(**email_conf)
113
125
114 message = Message(subject=subject,
126 message = Message(subject=subject,
115 sender=email_conf['default_sender'],
127 sender=email_conf['default_sender'],
116 recipients=recipients,
128 recipients=recipients,
117 body=body, html=html_body)
129 body=body, html=html_body,
130 extra_headers=extra_headers)
118 mailer.send_immediately(message)
131 mailer.send_immediately(message)
119
132
120 except Exception:
133 except Exception:
@@ -143,8 +143,7 b' def send_exc_email(request, exc_id, exc_'
143 'exc_traceback': read_exception(exc_id, prefix=None),
143 'exc_traceback': read_exception(exc_id, prefix=None),
144 }
144 }
145
145
146 (subject, headers, email_body,
146 (subject, email_body, email_body_plaintext) = EmailNotificationModel().render_email(
147 email_body_plaintext) = EmailNotificationModel().render_email(
148 EmailNotificationModel.TYPE_EMAIL_EXCEPTION, **email_kwargs)
147 EmailNotificationModel.TYPE_EMAIL_EXCEPTION, **email_kwargs)
149
148
150 run_task(tasks.send_email, recipients, subject,
149 run_task(tasks.send_email, recipients, subject,
@@ -370,13 +370,18 b' class CommentsModel(BaseModel):'
370 repo.repo_name,
370 repo.repo_name,
371 h.route_url('repo_summary', repo_name=repo.repo_name))
371 h.route_url('repo_summary', repo_name=repo.repo_name))
372
372
373 commit_url = h.route_url('repo_commit', repo_name=repo.repo_name,
374 commit_id=commit_id)
375
373 # commit specifics
376 # commit specifics
374 kwargs.update({
377 kwargs.update({
375 'commit': commit_obj,
378 'commit': commit_obj,
376 'commit_message': commit_obj.message,
379 'commit_message': commit_obj.message,
377 'commit_target_repo_url': target_repo_url,
380 'commit_target_repo_url': target_repo_url,
378 'commit_comment_url': commit_comment_url,
381 'commit_comment_url': commit_comment_url,
379 'commit_comment_reply_url': commit_comment_reply_url
382 'commit_comment_reply_url': commit_comment_reply_url,
383 'commit_url': commit_url,
384 'thread_ids': [commit_url, commit_comment_url],
380 })
385 })
381
386
382 elif pull_request_obj:
387 elif pull_request_obj:
@@ -421,15 +426,14 b' class CommentsModel(BaseModel):'
421 'pr_comment_url': pr_comment_url,
426 'pr_comment_url': pr_comment_url,
422 'pr_comment_reply_url': pr_comment_reply_url,
427 'pr_comment_reply_url': pr_comment_reply_url,
423 'pr_closing': closing_pr,
428 'pr_closing': closing_pr,
429 'thread_ids': [pr_url, pr_comment_url],
424 })
430 })
425
431
426 recipients += [self._get_user(u) for u in (extra_recipients or [])]
432 recipients += [self._get_user(u) for u in (extra_recipients or [])]
427
433
428 if send_email:
434 if send_email:
429 # pre-generate the subject for notification itself
435 # pre-generate the subject for notification itself
430 (subject,
436 (subject, _e, body_plaintext) = EmailNotificationModel().render_email(
431 _h, _e, # we don't care about those
432 body_plaintext) = EmailNotificationModel().render_email(
433 notification_type, **kwargs)
437 notification_type, **kwargs)
434
438
435 mention_recipients = set(
439 mention_recipients = set(
@@ -131,15 +131,17 b' class NotificationModel(BaseModel):'
131 # inject current recipient
131 # inject current recipient
132 email_kwargs['recipient'] = recipient
132 email_kwargs['recipient'] = recipient
133 email_kwargs['mention'] = recipient in mention_recipients
133 email_kwargs['mention'] = recipient in mention_recipients
134 (subject, headers, email_body,
134 (subject, email_body, email_body_plaintext) = EmailNotificationModel().render_email(
135 email_body_plaintext) = EmailNotificationModel().render_email(
136 notification_type, **email_kwargs)
135 notification_type, **email_kwargs)
137
136
138 log.debug(
137 extra_headers = None
139 'Creating notification email task for user:`%s`', recipient)
138 if 'thread_ids' in email_kwargs:
139 extra_headers = {'thread_ids': email_kwargs.pop('thread_ids')}
140
141 log.debug('Creating notification email task for user:`%s`', recipient)
140 task = run_task(
142 task = run_task(
141 tasks.send_email, recipient.email, subject,
143 tasks.send_email, recipient.email, subject,
142 email_body_plaintext, email_body)
144 email_body_plaintext, email_body, extra_headers=extra_headers)
143 log.debug('Created email task: %s', task)
145 log.debug('Created email task: %s', task)
144
146
145 return notification
147 return notification
@@ -342,8 +344,7 b' class EmailNotificationModel(BaseModel):'
342 """
344 """
343 Example usage::
345 Example usage::
344
346
345 (subject, headers, email_body,
347 (subject, email_body, email_body_plaintext) = EmailNotificationModel().render_email(
346 email_body_plaintext) = EmailNotificationModel().render_email(
347 EmailNotificationModel.TYPE_TEST, **email_kwargs)
348 EmailNotificationModel.TYPE_TEST, **email_kwargs)
348
349
349 """
350 """
@@ -387,12 +388,6 b' class EmailNotificationModel(BaseModel):'
387 subject = email_template.render('subject', **_kwargs)
388 subject = email_template.render('subject', **_kwargs)
388
389
389 try:
390 try:
390 headers = email_template.render('headers', **_kwargs)
391 except AttributeError:
392 # it's not defined in template, ok we can skip it
393 headers = ''
394
395 try:
396 body_plaintext = email_template.render('body_plaintext', **_kwargs)
391 body_plaintext = email_template.render('body_plaintext', **_kwargs)
397 except AttributeError:
392 except AttributeError:
398 # it's not defined in template, ok we can skip it
393 # it's not defined in template, ok we can skip it
@@ -408,4 +403,4 b' class EmailNotificationModel(BaseModel):'
408 log.exception('Failed to parse body with premailer')
403 log.exception('Failed to parse body with premailer')
409 pass
404 pass
410
405
411 return subject, headers, body, body_plaintext
406 return subject, body, body_plaintext
@@ -1344,12 +1344,11 b' class PullRequestModel(BaseModel):'
1344 'pull_request_source_repo_url': pr_source_repo_url,
1344 'pull_request_source_repo_url': pr_source_repo_url,
1345
1345
1346 'pull_request_url': pr_url,
1346 'pull_request_url': pr_url,
1347 'thread_ids': [pr_url],
1347 }
1348 }
1348
1349
1349 # pre-generate the subject for notification itself
1350 # pre-generate the subject for notification itself
1350 (subject,
1351 (subject, _e, body_plaintext) = EmailNotificationModel().render_email(
1351 _h, _e, # we don't care about those
1352 body_plaintext) = EmailNotificationModel().render_email(
1353 notification_type, **kwargs)
1352 notification_type, **kwargs)
1354
1353
1355 # create notification objects, and emails
1354 # create notification objects, and emails
@@ -1414,11 +1413,10 b' class PullRequestModel(BaseModel):'
1414 'added_files': file_changes.added,
1413 'added_files': file_changes.added,
1415 'modified_files': file_changes.modified,
1414 'modified_files': file_changes.modified,
1416 'removed_files': file_changes.removed,
1415 'removed_files': file_changes.removed,
1416 'thread_ids': [pr_url],
1417 }
1417 }
1418
1418
1419 (subject,
1419 (subject, _e, body_plaintext) = EmailNotificationModel().render_email(
1420 _h, _e, # we don't care about those
1421 body_plaintext) = EmailNotificationModel().render_email(
1422 EmailNotificationModel.TYPE_PULL_REQUEST_UPDATE, **email_kwargs)
1420 EmailNotificationModel.TYPE_PULL_REQUEST_UPDATE, **email_kwargs)
1423
1421
1424 # create notification objects, and emails
1422 # create notification objects, and emails
@@ -422,9 +422,7 b' class UserModel(BaseModel):'
422 }
422 }
423 notification_type = EmailNotificationModel.TYPE_REGISTRATION
423 notification_type = EmailNotificationModel.TYPE_REGISTRATION
424 # pre-generate the subject for notification itself
424 # pre-generate the subject for notification itself
425 (subject,
425 (subject, _e, body_plaintext) = EmailNotificationModel().render_email(
426 _h, _e, # we don't care about those
427 body_plaintext) = EmailNotificationModel().render_email(
428 notification_type, **kwargs)
426 notification_type, **kwargs)
429
427
430 # create notification objects, and emails
428 # create notification objects, and emails
@@ -659,8 +657,7 b' class UserModel(BaseModel):'
659 'first_admin_email': User.get_first_super_admin().email
657 'first_admin_email': User.get_first_super_admin().email
660 }
658 }
661
659
662 (subject, headers, email_body,
660 (subject, email_body, email_body_plaintext) = EmailNotificationModel().render_email(
663 email_body_plaintext) = EmailNotificationModel().render_email(
664 EmailNotificationModel.TYPE_PASSWORD_RESET, **email_kwargs)
661 EmailNotificationModel.TYPE_PASSWORD_RESET, **email_kwargs)
665
662
666 recipients = [user_email]
663 recipients = [user_email]
@@ -718,8 +715,7 b' class UserModel(BaseModel):'
718 'first_admin_email': User.get_first_super_admin().email
715 'first_admin_email': User.get_first_super_admin().email
719 }
716 }
720
717
721 (subject, headers, email_body,
718 (subject, email_body, email_body_plaintext) = EmailNotificationModel().render_email(
722 email_body_plaintext) = EmailNotificationModel().render_email(
723 EmailNotificationModel.TYPE_PASSWORD_RESET_CONFIRMATION,
719 EmailNotificationModel.TYPE_PASSWORD_RESET_CONFIRMATION,
724 **email_kwargs)
720 **email_kwargs)
725
721
@@ -8,11 +8,6 b''
8 SUBJECT:
8 SUBJECT:
9 <pre>${c.subject}</pre>
9 <pre>${c.subject}</pre>
10
10
11 HEADERS:
12 <pre>
13 ${c.headers}
14 </pre>
15
16 PLAINTEXT:
11 PLAINTEXT:
17 <pre>
12 <pre>
18 ${c.email_body_plaintext|n}
13 ${c.email_body_plaintext|n}
@@ -68,9 +68,6 b' text_monospace = "\'Menlo\', \'Liberation M'
68
68
69 %>
69 %>
70
70
71 ## headers we additionally can set for email
72 <%def name="headers()" filter="n,trim"></%def>
73
74 <%def name="plaintext_footer()" filter="trim">
71 <%def name="plaintext_footer()" filter="trim">
75 ${_('This is a notification from RhodeCode.')} ${instance_url}
72 ${_('This is a notification from RhodeCode.')} ${instance_url}
76 </%def>
73 </%def>
@@ -15,17 +15,18 b' data = {'
15 'comment_id': comment_id,
15 'comment_id': comment_id,
16
16
17 'commit_id': h.show_id(commit),
17 'commit_id': h.show_id(commit),
18 'mention_prefix': '[mention] ' if mention else '',
18 }
19 }
19 %>
20 %>
20
21
21
22
22 % if comment_file:
23 % if comment_file:
23 ${(_('[mention]') if mention else '')} ${_('{user} left a {comment_type} on file `{comment_file}` in commit `{commit_id}`').format(**data)} ${_('in the `{repo_name}` repository').format(**data) |n}
24 ${_('{mention_prefix}{user} left a {comment_type} on file `{comment_file}` in commit `{commit_id}`').format(**data)} ${_('in the `{repo_name}` repository').format(**data) |n}
24 % else:
25 % else:
25 % if status_change:
26 % if status_change:
26 ${(_('[mention]') if mention else '')} ${_('[status: {status}] {user} left a {comment_type} on commit `{commit_id}`').format(**data) |n} ${_('in the `{repo_name}` repository').format(**data) |n}
27 ${_('{mention_prefix}[status: {status}] {user} left a {comment_type} on commit `{commit_id}`').format(**data) |n} ${_('in the `{repo_name}` repository').format(**data) |n}
27 % else:
28 % else:
28 ${(_('[mention]') if mention else '')} ${_('{user} left a {comment_type} on commit `{commit_id}`').format(**data) |n} ${_('in the `{repo_name}` repository').format(**data) |n}
29 ${_('{mention_prefix}{user} left a {comment_type} on commit `{commit_id}`').format(**data) |n} ${_('in the `{repo_name}` repository').format(**data) |n}
29 % endif
30 % endif
30 % endif
31 % endif
31
32
@@ -16,17 +16,18 b' data = {'
16
16
17 'pr_title': pull_request.title,
17 'pr_title': pull_request.title,
18 'pr_id': pull_request.pull_request_id,
18 'pr_id': pull_request.pull_request_id,
19 'mention_prefix': '[mention] ' if mention else '',
19 }
20 }
20 %>
21 %>
21
22
22
23
23 % if comment_file:
24 % if comment_file:
24 ${(_('[mention]') if mention else '')} ${_('{user} left a {comment_type} on file `{comment_file}` in pull request !{pr_id}: "{pr_title}"').format(**data) |n}
25 ${_('{mention_prefix}{user} left a {comment_type} on file `{comment_file}` in pull request !{pr_id}: "{pr_title}"').format(**data) |n}
25 % else:
26 % else:
26 % if status_change:
27 % if status_change:
27 ${(_('[mention]') if mention else '')} ${_('[status: {status}] {user} left a {comment_type} on pull request !{pr_id}: "{pr_title}"').format(**data) |n}
28 ${_('{mention_prefix}[status: {status}] {user} left a {comment_type} on pull request !{pr_id}: "{pr_title}"').format(**data) |n}
28 % else:
29 % else:
29 ${(_('[mention]') if mention else '')} ${_('{user} left a {comment_type} on pull request !{pr_id}: "{pr_title}"').format(**data) |n}
30 ${_('{mention_prefix}{user} left a {comment_type} on pull request !{pr_id}: "{pr_title}"').format(**data) |n}
30 % endif
31 % endif
31 % endif
32 % endif
32
33
@@ -5,10 +5,6 b''
5 Test "Subject" ${_('hello "world"')|n}
5 Test "Subject" ${_('hello "world"')|n}
6 </%def>
6 </%def>
7
7
8 <%def name="headers()" filter="n,trim">
9 X=Y
10 </%def>
11
12 ## plain text version of the email. Empty by default
8 ## plain text version of the email. Empty by default
13 <%def name="body_plaintext()" filter="n,trim">
9 <%def name="body_plaintext()" filter="n,trim">
14 Email Plaintext Body
10 Email Plaintext Body
@@ -35,15 +35,12 b' def test_get_template_obj(app, request_s'
35
35
36 def test_render_email(app, http_host_only_stub):
36 def test_render_email(app, http_host_only_stub):
37 kwargs = {}
37 kwargs = {}
38 subject, headers, body, body_plaintext = EmailNotificationModel().render_email(
38 subject, body, body_plaintext = EmailNotificationModel().render_email(
39 EmailNotificationModel.TYPE_TEST, **kwargs)
39 EmailNotificationModel.TYPE_TEST, **kwargs)
40
40
41 # subject
41 # subject
42 assert subject == 'Test "Subject" hello "world"'
42 assert subject == 'Test "Subject" hello "world"'
43
43
44 # headers
45 assert headers == 'X=Y'
46
47 # body plaintext
44 # body plaintext
48 assert body_plaintext == 'Email Plaintext Body'
45 assert body_plaintext == 'Email Plaintext Body'
49
46
@@ -80,7 +77,7 b' def test_render_pr_email(app, user_admin'
80 'pull_request_url': 'http://localhost/pr1',
77 'pull_request_url': 'http://localhost/pr1',
81 }
78 }
82
79
83 subject, headers, body, body_plaintext = EmailNotificationModel().render_email(
80 subject, body, body_plaintext = EmailNotificationModel().render_email(
84 EmailNotificationModel.TYPE_PULL_REQUEST, **kwargs)
81 EmailNotificationModel.TYPE_PULL_REQUEST, **kwargs)
85
82
86 # subject
83 # subject
@@ -133,7 +130,7 b' def test_render_pr_update_email(app, use'
133 'removed_files': file_changes.removed,
130 'removed_files': file_changes.removed,
134 }
131 }
135
132
136 subject, headers, body, body_plaintext = EmailNotificationModel().render_email(
133 subject, body, body_plaintext = EmailNotificationModel().render_email(
137 EmailNotificationModel.TYPE_PULL_REQUEST_UPDATE, **kwargs)
134 EmailNotificationModel.TYPE_PULL_REQUEST_UPDATE, **kwargs)
138
135
139 # subject
136 # subject
@@ -188,7 +185,6 b' def test_render_comment_subject_no_newli'
188
185
189 'pull_request_url': 'http://code.rc.com/_pr/123'
186 'pull_request_url': 'http://code.rc.com/_pr/123'
190 }
187 }
191 subject, headers, body, body_plaintext = EmailNotificationModel().render_email(
188 subject, body, body_plaintext = EmailNotificationModel().render_email(email_type, **kwargs)
192 email_type, **kwargs)
193
189
194 assert '\n' not in subject
190 assert '\n' not in subject
General Comments 0
You need to be logged in to leave comments. Login now