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>`. |
|
|
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( |
|
|
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