##// 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 39 ``app_email_from`` setting in the configuration file. This setting can either
40 40 contain only an email address, like `kallithea-noreply@example.com`, or both
41 41 a name and an address in the following format: `Kallithea
42 <kallithea-noreply@example.com>`. The subject of these emails can
43 optionally be prefixed with the value of ``email_prefix`` in the configuration
44 file.
42 <kallithea-noreply@example.com>`. However, if the email is sent due to an
43 action of a particular user, for example when a comment is given or a pull
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 52 Error emails
@@ -31,6 +31,7 b' from celery.decorators import task'
31 31 import os
32 32 import traceback
33 33 import logging
34 import rfc822
34 35 from os.path import join as jn
35 36
36 37 from time import mktime
@@ -45,6 +46,7 b' from kallithea.lib.celerylib import run_'
45 46 from kallithea.lib.helpers import person
46 47 from kallithea.lib.rcmail.smtp_mailer import SmtpMailer
47 48 from kallithea.lib.utils import add_cache, action_logger
49 from kallithea.lib.vcs.utils import author_email
48 50 from kallithea.lib.compat import json, OrderedDict
49 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 250 @task(ignore_result=True)
249 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 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 258 :param subject: subject of the mail
257 259 :param body: body of the mail
258 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 264 log = get_logger(send_email)
261 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 272 email_config = config
264 273 email_prefix = email_config.get('email_prefix', '')
@@ -280,7 +289,18 b' def send_email(recipients, subject, body'
280 289
281 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 304 user = email_config.get('smtp_username')
285 305 passwd = email_config.get('smtp_password')
286 306 mail_server = email_config.get('smtp_server')
@@ -306,7 +326,7 b' def send_email(recipients, subject, body'
306 326 return False
307 327
308 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 330 mail_port, ssl, tls, debug=debug)
311 331 m.send(recipients, subject, body, html_body, headers=headers)
312 332 except:
@@ -145,7 +145,7 b' class NotificationModel(BaseModel):'
145 145 .get_email_tmpl(type_, 'html', **html_kwargs)
146 146
147 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 150 return notif
151 151
@@ -2,6 +2,7 b' import mock'
2 2
3 3 import kallithea
4 4 from kallithea.tests import *
5 from kallithea.model.db import User
5 6
6 7 class smtplib_mock(object):
7 8
@@ -89,3 +90,78 b' class TestMail(BaseTestCase):'
89 90 self.assertIn('Subject: %s' % subject, smtplib_mock.lastmsg)
90 91 self.assertIn(body, smtplib_mock.lastmsg)
91 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