##// END OF EJS Templates
email: send comment and pullrequest mails with the author's name in 'From'...
Thomas De Schampheleire -
r5455:c935bcaf default
parent child Browse files
Show More
@@ -39,9 +39,14 b' Recipients will see these emails origina'
39 ``app_email_from`` setting in the configuration file. This setting can either
39 ``app_email_from`` setting in the configuration file. This setting can either
40 contain only an email address, like `kallithea-noreply@example.com`, or both
40 contain only an email address, like `kallithea-noreply@example.com`, or both
41 a name and an address in the following format: `Kallithea
41 a name and an address in the following format: `Kallithea
42 <kallithea-noreply@example.com>`. The subject of these emails can
42 <kallithea-noreply@example.com>`. However, if the email is sent due to an
43 optionally be prefixed with the value of ``email_prefix`` in the configuration
43 action of a particular user, for example when a comment is given or a pull
44 file.
44 request created, the name of that user will be combined with the email address
45 specified in ``app_email_from`` to form the sender (and any name part in that
46 configuration setting disregarded).
47
48 The subject of these emails can optionally be prefixed with the value of
49 ``email_prefix`` in the configuration file.
45
50
46
51
47 Error emails
52 Error emails
@@ -31,6 +31,7 b' from celery.decorators import task'
31 import os
31 import os
32 import traceback
32 import traceback
33 import logging
33 import logging
34 import rfc822
34 from os.path import join as jn
35 from os.path import join as jn
35
36
36 from time import mktime
37 from time import mktime
@@ -45,6 +46,7 b' from kallithea.lib.celerylib import run_'
45 from kallithea.lib.helpers import person
46 from kallithea.lib.helpers import person
46 from kallithea.lib.rcmail.smtp_mailer import SmtpMailer
47 from kallithea.lib.rcmail.smtp_mailer import SmtpMailer
47 from kallithea.lib.utils import add_cache, action_logger
48 from kallithea.lib.utils import add_cache, action_logger
49 from kallithea.lib.vcs.utils import author_email
48 from kallithea.lib.compat import json, OrderedDict
50 from kallithea.lib.compat import json, OrderedDict
49 from kallithea.lib.hooks import log_create_repository
51 from kallithea.lib.hooks import log_create_repository
50
52
@@ -247,7 +249,7 b' def get_commits_stats(repo_name, ts_min_'
247
249
248 @task(ignore_result=True)
250 @task(ignore_result=True)
249 @dbsession
251 @dbsession
250 def send_email(recipients, subject, body='', html_body='', headers=None):
252 def send_email(recipients, subject, body='', html_body='', headers=None, author=None):
251 """
253 """
252 Sends an email with defined parameters from the .ini files.
254 Sends an email with defined parameters from the .ini files.
253
255
@@ -256,9 +258,16 b' def send_email(recipients, subject, body'
256 :param subject: subject of the mail
258 :param subject: subject of the mail
257 :param body: body of the mail
259 :param body: body of the mail
258 :param html_body: html version of body
260 :param html_body: html version of body
261 :param headers: dictionary of prepopulated e-mail headers
262 :param author: User object of the author of this mail, if known and relevant
259 """
263 """
260 log = get_logger(send_email)
264 log = get_logger(send_email)
261 assert isinstance(recipients, list), recipients
265 assert isinstance(recipients, list), recipients
266 if headers is None:
267 headers = {}
268 else:
269 # do not modify the original headers object passed by the caller
270 headers = headers.copy()
262
271
263 email_config = config
272 email_config = config
264 email_prefix = email_config.get('email_prefix', '')
273 email_prefix = email_config.get('email_prefix', '')
@@ -280,7 +289,18 b' def send_email(recipients, subject, body'
280
289
281 log.warning("No recipients specified for '%s' - sending to admins %s", subject, ' '.join(recipients))
290 log.warning("No recipients specified for '%s' - sending to admins %s", subject, ' '.join(recipients))
282
291
283 mail_from = email_config.get('app_email_from', 'Kallithea')
292 # SMTP sender
293 envelope_from = email_config.get('app_email_from', 'Kallithea')
294 # 'From' header
295 if author is not None:
296 # set From header based on author but with a generic e-mail address
297 # In case app_email_from is in "Some Name <e-mail>" format, we first
298 # extract the e-mail address.
299 envelope_addr = author_email(envelope_from)
300 headers['From'] = '"%s" <%s>' % (
301 rfc822.quote('%s (no-reply)' % author.full_name_or_username),
302 envelope_addr)
303
284 user = email_config.get('smtp_username')
304 user = email_config.get('smtp_username')
285 passwd = email_config.get('smtp_password')
305 passwd = email_config.get('smtp_password')
286 mail_server = email_config.get('smtp_server')
306 mail_server = email_config.get('smtp_server')
@@ -306,7 +326,7 b' def send_email(recipients, subject, body'
306 return False
326 return False
307
327
308 try:
328 try:
309 m = SmtpMailer(mail_from, user, passwd, mail_server, smtp_auth,
329 m = SmtpMailer(envelope_from, user, passwd, mail_server, smtp_auth,
310 mail_port, ssl, tls, debug=debug)
330 mail_port, ssl, tls, debug=debug)
311 m.send(recipients, subject, body, html_body, headers=headers)
331 m.send(recipients, subject, body, html_body, headers=headers)
312 except:
332 except:
@@ -145,7 +145,7 b' class NotificationModel(BaseModel):'
145 .get_email_tmpl(type_, 'html', **html_kwargs)
145 .get_email_tmpl(type_, 'html', **html_kwargs)
146
146
147 run_task(tasks.send_email, [rec.email], email_subject, email_txt_body,
147 run_task(tasks.send_email, [rec.email], email_subject, email_txt_body,
148 email_html_body, headers)
148 email_html_body, headers, author=created_by_obj)
149
149
150 return notif
150 return notif
151
151
@@ -2,6 +2,7 b' import mock'
2
2
3 import kallithea
3 import kallithea
4 from kallithea.tests import *
4 from kallithea.tests import *
5 from kallithea.model.db import User
5
6
6 class smtplib_mock(object):
7 class smtplib_mock(object):
7
8
@@ -89,3 +90,78 b' class TestMail(BaseTestCase):'
89 self.assertIn('Subject: %s' % subject, smtplib_mock.lastmsg)
90 self.assertIn('Subject: %s' % subject, smtplib_mock.lastmsg)
90 self.assertIn(body, smtplib_mock.lastmsg)
91 self.assertIn(body, smtplib_mock.lastmsg)
91 self.assertIn(html_body, smtplib_mock.lastmsg)
92 self.assertIn(html_body, smtplib_mock.lastmsg)
93
94 def test_send_mail_with_author(self):
95 mailserver = 'smtp.mailserver.org'
96 recipients = ['rcpt1', 'rcpt2']
97 envelope_from = 'noreply@mailserver.org'
98 subject = 'subject'
99 body = 'body'
100 html_body = 'html_body'
101 author = User.get_by_username(TEST_USER_REGULAR_LOGIN)
102
103 config_mock = {
104 'smtp_server': mailserver,
105 'app_email_from': envelope_from,
106 }
107 with mock.patch('kallithea.lib.celerylib.tasks.config', config_mock):
108 kallithea.lib.celerylib.tasks.send_email(recipients, subject, body, html_body, author=author)
109
110 self.assertSetEqual(smtplib_mock.lastdest, set(recipients))
111 self.assertEqual(smtplib_mock.lastsender, envelope_from)
112 self.assertIn('From: "Kallithea Admin (no-reply)" <%s>' % envelope_from, smtplib_mock.lastmsg)
113 self.assertIn('Subject: %s' % subject, smtplib_mock.lastmsg)
114 self.assertIn(body, smtplib_mock.lastmsg)
115 self.assertIn(html_body, smtplib_mock.lastmsg)
116
117 def test_send_mail_with_author_full_mail_from(self):
118 mailserver = 'smtp.mailserver.org'
119 recipients = ['rcpt1', 'rcpt2']
120 envelope_addr = 'noreply@mailserver.org'
121 envelope_from = 'Some Name <%s>' % envelope_addr
122 subject = 'subject'
123 body = 'body'
124 html_body = 'html_body'
125 author = User.get_by_username(TEST_USER_REGULAR_LOGIN)
126
127 config_mock = {
128 'smtp_server': mailserver,
129 'app_email_from': envelope_from,
130 }
131 with mock.patch('kallithea.lib.celerylib.tasks.config', config_mock):
132 kallithea.lib.celerylib.tasks.send_email(recipients, subject, body, html_body, author=author)
133
134 self.assertSetEqual(smtplib_mock.lastdest, set(recipients))
135 self.assertEqual(smtplib_mock.lastsender, envelope_from)
136 self.assertIn('From: "Kallithea Admin (no-reply)" <%s>' % envelope_addr, smtplib_mock.lastmsg)
137 self.assertIn('Subject: %s' % subject, smtplib_mock.lastmsg)
138 self.assertIn(body, smtplib_mock.lastmsg)
139 self.assertIn(html_body, smtplib_mock.lastmsg)
140
141 def test_send_mail_extra_headers(self):
142 mailserver = 'smtp.mailserver.org'
143 recipients = ['rcpt1', 'rcpt2']
144 envelope_from = 'noreply@mailserver.org'
145 subject = 'subject'
146 body = 'body'
147 html_body = 'html_body'
148 author = User(name='foo', lastname='(fubar) "baz"')
149 headers = {'extra': 'yes'}
150
151 config_mock = {
152 'smtp_server': mailserver,
153 'app_email_from': envelope_from,
154 }
155 with mock.patch('kallithea.lib.celerylib.tasks.config', config_mock):
156 kallithea.lib.celerylib.tasks.send_email(recipients, subject, body, html_body,
157 author=author, headers=headers)
158
159 self.assertSetEqual(smtplib_mock.lastdest, set(recipients))
160 self.assertEqual(smtplib_mock.lastsender, envelope_from)
161 self.assertIn(r'From: "foo (fubar) \"baz\" (no-reply)" <%s>' % envelope_from, smtplib_mock.lastmsg)
162 self.assertIn('Subject: %s' % subject, smtplib_mock.lastmsg)
163 self.assertIn(body, smtplib_mock.lastmsg)
164 self.assertIn(html_body, smtplib_mock.lastmsg)
165 self.assertIn('Extra: yes', smtplib_mock.lastmsg)
166 # verify that headers dict hasn't mutated by send_email
167 self.assertDictEqual(headers, {'extra': 'yes'})
General Comments 0
You need to be logged in to leave comments. Login now