diff options
author | David Baker <dave@matrix.org> | 2016-04-21 19:19:07 +0100 |
---|---|---|
committer | David Baker <dave@matrix.org> | 2016-04-21 19:19:07 +0100 |
commit | c10ed26c303741fe0e43f11e2fbeeb148f466b17 (patch) | |
tree | bdd406d8db391cf0f2182a65666971d39953f3e0 /synapse/push | |
parent | Generate mails from a template (diff) | |
download | synapse-c10ed26c303741fe0e43f11e2fbeeb148f466b17.tar.xz |
Flesh out email templating
Mostly WIP porting the room name calculation logic from the web client so our room names in the email mirror the clients.
Diffstat (limited to 'synapse/push')
-rw-r--r-- | synapse/push/emailpusher.py | 7 | ||||
-rw-r--r-- | synapse/push/mailer.py | 61 |
2 files changed, 65 insertions, 3 deletions
diff --git a/synapse/push/emailpusher.py b/synapse/push/emailpusher.py index 4e21221fb7..7c810029fa 100644 --- a/synapse/push/emailpusher.py +++ b/synapse/push/emailpusher.py @@ -83,6 +83,13 @@ class EmailPusher(object): yield self._process() @defer.inlineCallbacks + def on_new_receipts(self, min_stream_id, max_stream_id): + # We could wake up and cancel the timer but there tend to be quite a + # lot of read receipts so it's probably less work to just let the + # timer fire + return defer.succeed(None) + + @defer.inlineCallbacks def on_timer(self): self.timed_call = None yield self._process() diff --git a/synapse/push/mailer.py b/synapse/push/mailer.py index 0f20d43f75..e68d701ffd 100644 --- a/synapse/push/mailer.py +++ b/synapse/push/mailer.py @@ -14,18 +14,23 @@ # limitations under the License. from twisted.internet import defer - from twisted.mail.smtp import sendmail + import email.utils import email.mime.multipart from email.mime.text import MIMEText +from synapse.util.async import concurrently_execute +from synapse.util.room_name import calculate_room_name + import jinja2 class Mailer(object): def __init__(self, hs): self.hs = hs + self.store = self.hs.get_datastore() + self.state_handler = self.hs.get_state_handler() loader = jinja2.FileSystemLoader(self.hs.config.email_template_dir) env = jinja2.Environment(loader=loader) self.notif_template = env.get_template(self.hs.config.email_notif_template_html) @@ -38,9 +43,41 @@ class Mailer(object): if raw_to == '': raise RuntimeError("Invalid 'to' address") - plainText = self.notif_template.render() + rooms_in_order = deduped_ordered_list( + [pa['room_id'] for pa in push_actions] + ) + + notifs_by_room = {} + for pa in push_actions: + notifs_by_room.setdefault(pa["room_id"], []).append(pa) + + # collect the current state for all the rooms in which we have + # notifications + state_by_room = {} + + @defer.inlineCallbacks + def _fetch_room_state(room_id): + room_state = yield self.state_handler.get_current_state(room_id) + state_by_room[room_id] = room_state + + # Run at most 3 of these at once: sync does 10 at a time but email + # notifs are much realtime than sync so we can afford to wait a bit. + yield concurrently_execute(_fetch_room_state, rooms_in_order, 3) - text_part = MIMEText(plainText, "plain") + rooms = [ + self.get_room_vars( + r, user_id, notifs_by_room[r], state_by_room[r] + ) for r in rooms_in_order + ] + + template_vars = { + "unsubscribe_link": self.make_unsubscribe_link(), + "rooms": rooms, + } + + plainText = self.notif_template.render(**template_vars) + + text_part = MIMEText(plainText, "html") text_part['Subject'] = "New Matrix Notifications" text_part['From'] = self.hs.config.email_notif_from text_part['To'] = email_address @@ -50,3 +87,21 @@ class Mailer(object): raw_from, raw_to, text_part.as_string(), port=self.hs.config.email_smtp_port ) + + def get_room_vars(self, room_id, user_id, notifs, room_state): + room_vars = {} + room_vars['title'] = calculate_room_name(room_state, user_id) + return room_vars + + def make_unsubscribe_link(self): + return "https://vector.im/#/settings" # XXX: matrix.to + + +def deduped_ordered_list(l): + seen = set() + ret = [] + for item in l: + if item not in seen: + seen.add(item) + ret.append(item) + return ret \ No newline at end of file |