[PATCH 2 of 5] e-mail: send comment and pullrequest mails with the author's name in From
Thomas De Schampheleire
patrickdepinguin at gmail.com
Mon Jul 13 04:45:08 EDT 2015
# HG changeset patch
# User Thomas De Schampheleire <thomas.de.schampheleire at gmail.com>
# Date 1436471455 -7200
# Thu Jul 09 21:50:55 2015 +0200
# Node ID 95c18c5fdb59f2d985e2cd8ac6db093cb3e5f884
# Parent c22a219636b830bac4b6125b306f6c8506f81d99
e-mail: send comment and pullrequest mails with the author's name in From
When e-mails are sent for comments and pullrequest invitations, set the From
header to:
Author's Name <generic e-mail address>
The sender used for other e-mail types, e.g. password reset mails, is
untouched and remains the value configured in app_email_from.
The sender used for the SMTP envelope is untouched as well.
Based on code by Cedric De Herdt.
diff --git a/kallithea/lib/celerylib/tasks.py b/kallithea/lib/celerylib/tasks.py
--- a/kallithea/lib/celerylib/tasks.py
+++ b/kallithea/lib/celerylib/tasks.py
@@ -247,7 +247,7 @@ def get_commits_stats(repo_name, ts_min_
@task(ignore_result=True)
@dbsession
-def send_email(recipients, subject, body='', html_body='', headers=None):
+def send_email(recipients, subject, body='', html_body='', headers=None, author=None):
"""
Sends an email with defined parameters from the .ini files.
@@ -259,6 +259,8 @@ def send_email(recipients, subject, body
"""
log = get_logger(send_email)
assert isinstance(recipients, list), recipients
+ if headers is None:
+ headers = {}
email_config = config
email_prefix = email_config.get('email_prefix', '')
@@ -274,7 +276,23 @@ def send_email(recipients, subject, body
log.error("No recipients specified")
return False
- mail_from = email_config.get('app_email_from', 'Kallithea')
+ # SMTP sender
+ envelope_from = email_config.get('app_email_from', 'Kallithea')
+ # From header
+ if author is None:
+ headers['From'] = envelope_from
+ else:
+ # set From header based on author but with a generic e-mail address
+ # In case app_email_from is in "Some Name <e-mail>" format, we first
+ # extract the e-mail address.
+ import re
+ m = re.match('.*<(.*)>', envelope_from)
+ if m is not None:
+ envelope_addr = m.group(1)
+ else:
+ envelope_addr = envelope_from
+ headers['From'] = '%s <%s>' % (author.full_name_or_username, envelope_addr)
+
user = email_config.get('smtp_username')
passwd = email_config.get('smtp_password')
mail_server = email_config.get('smtp_server')
@@ -285,13 +303,18 @@ def send_email(recipients, subject, body
smtp_auth = email_config.get('smtp_auth')
if not mail_server:
- log.error("SMTP mail server not configured - cannot send mail '%s' to %s", subject, ' '.join(recipients))
- log.warning("body:\n%s", body)
- log.warning("html:\n%s", html_body)
+ log.error("SMTP mail server not configured - cannot send mail to %s", ' '.join(recipients))
+ log.warning("Mail details:\n"
+ "envelope_from: %s\n"
+ "headers: %s\n"
+ "subject: %s\n"
+ "body:\n%s\n"
+ "html:\n%s\n"
+ % (envelope_from, headers, subject, body, html_body))
return False
try:
- m = SmtpMailer(mail_from, user, passwd, mail_server, smtp_auth,
+ m = SmtpMailer(envelope_from, user, passwd, mail_server, smtp_auth,
mail_port, ssl, tls, debug=debug)
m.send(recipients, subject, body, html_body, headers=headers)
except:
diff --git a/kallithea/model/notification.py b/kallithea/model/notification.py
--- a/kallithea/model/notification.py
+++ b/kallithea/model/notification.py
@@ -145,7 +145,7 @@ class NotificationModel(BaseModel):
.get_email_tmpl(type_, 'html', **html_kwargs)
run_task(tasks.send_email, [rec.email], email_subject, email_txt_body,
- email_html_body, headers)
+ email_html_body, headers, author=created_by_obj)
return notif
diff --git a/kallithea/tests/other/test_mail.py b/kallithea/tests/other/test_mail.py
new file mode 100644
--- /dev/null
+++ b/kallithea/tests/other/test_mail.py
@@ -0,0 +1,94 @@
+import mock
+
+from kallithea.tests import *
+from kallithea.model.db import User
+import kallithea.lib.celerylib.tasks as t
+
+class smtplib_mock(object):
+
+ @classmethod
+ def SMTP(cls, server, port, local_hostname):
+ return smtplib_mock()
+ print 'mocked'
+
+ def ehlo(self):
+ pass
+ def quit(self):
+ pass
+ def sendmail(self, sender, dest, msg):
+ smtplib_mock.lastsender = sender
+ smtplib_mock.lastdest = dest
+ smtplib_mock.lastmsg = msg
+ pass
+
+ at mock.patch('kallithea.lib.rcmail.smtp_mailer.smtplib', smtplib_mock)
+class TestMail(BaseTestCase):
+
+ def test_send_mail_trivial(self):
+ mailserver = 'smtp.mailserver.org'
+ recipients = ['rcpt1', 'rcpt2']
+ envelope_from = 'noreply at mailserver.org'
+ subject = 'subject'
+ body = 'body'
+ html_body = 'html_body'
+
+ config_mock = {
+ 'smtp_server': mailserver,
+ 'app_email_from': envelope_from,
+ }
+ with mock.patch('kallithea.lib.celerylib.tasks.config', config_mock):
+ t.send_email(recipients, subject, body, html_body)
+
+ self.assertSetEqual(smtplib_mock.lastdest, set(recipients))
+ self.assertEqual(smtplib_mock.lastsender, envelope_from)
+ self.assertIn('From: %s' % envelope_from, smtplib_mock.lastmsg)
+ self.assertIn('Subject: %s' % subject, smtplib_mock.lastmsg)
+ self.assertIn(body, smtplib_mock.lastmsg)
+ self.assertIn(html_body, smtplib_mock.lastmsg)
+
+ def test_send_mail_with_author(self):
+ mailserver = 'smtp.mailserver.org'
+ recipients = ['rcpt1', 'rcpt2']
+ envelope_from = 'noreply at mailserver.org'
+ subject = 'subject'
+ body = 'body'
+ html_body = 'html_body'
+ author = User.get_by_username(TEST_USER_REGULAR_LOGIN)
+
+ config_mock = {
+ 'smtp_server': mailserver,
+ 'app_email_from': envelope_from,
+ }
+ with mock.patch('kallithea.lib.celerylib.tasks.config', config_mock):
+ t.send_email(recipients, subject, body, html_body, author=author)
+
+ self.assertSetEqual(smtplib_mock.lastdest, set(recipients))
+ self.assertEqual(smtplib_mock.lastsender, envelope_from)
+ self.assertIn('From: Kallithea Admin <%s>' % envelope_from, smtplib_mock.lastmsg)
+ self.assertIn('Subject: %s' % subject, smtplib_mock.lastmsg)
+ self.assertIn(body, smtplib_mock.lastmsg)
+ self.assertIn(html_body, smtplib_mock.lastmsg)
+
+ def test_send_mail_with_author_full_mail_from(self):
+ mailserver = 'smtp.mailserver.org'
+ recipients = ['rcpt1', 'rcpt2']
+ envelope_addr = 'noreply at mailserver.org'
+ envelope_from = 'Some Name <%s>' % envelope_addr
+ subject = 'subject'
+ body = 'body'
+ html_body = 'html_body'
+ author = User.get_by_username(TEST_USER_REGULAR_LOGIN)
+
+ config_mock = {
+ 'smtp_server': mailserver,
+ 'app_email_from': envelope_from,
+ }
+ with mock.patch('kallithea.lib.celerylib.tasks.config', config_mock):
+ t.send_email(recipients, subject, body, html_body, author=author)
+
+ self.assertSetEqual(smtplib_mock.lastdest, set(recipients))
+ self.assertEqual(smtplib_mock.lastsender, envelope_from)
+ self.assertIn('From: Kallithea Admin <%s>' % envelope_addr, smtplib_mock.lastmsg)
+ self.assertIn('Subject: %s' % subject, smtplib_mock.lastmsg)
+ self.assertIn(body, smtplib_mock.lastmsg)
+ self.assertIn(html_body, smtplib_mock.lastmsg)
More information about the kallithea-general
mailing list