pyceo/ceod/model/MailService.py

92 lines
3.1 KiB
Python

import datetime
from email.message import EmailMessage
import re
import smtplib
from typing import Dict, List
from flask import g
import jinja2
from zope import component
from zope.interface import implementer
from ceo_common.interfaces import IMailService, IConfig, IUser
smtp_url_re = re.compile(r'^(?P<scheme>smtps?)://(?P<host>[\w.-]+)(:(?P<port>\d+))?$')
@implementer(IMailService)
class MailService:
def __init__(self):
cfg = component.getUtility(IConfig)
smtp_url = cfg.get('mail_smtp_url')
match = smtp_url_re.match(smtp_url)
if match is None:
raise Exception('Invalid SMTP URL: %s' % smtp_url)
self.smtps = match.group('scheme') == 'smtps'
self.host = match.group('host')
self.port = int(match.group('port') or 25)
self.starttls = cfg.get('mail_smtp_starttls')
assert not (self.smtps and self.starttls)
self.base_domain = cfg.get('base_domain')
self.jinja_env = jinja2.Environment(
loader=jinja2.PackageLoader('ceod.model'),
)
def send(self, _from: str, to: str, headers: Dict[str, str], content: str):
msg = EmailMessage()
msg.set_content(content)
msg['From'] = _from
msg['To'] = to
msg['Date'] = datetime.datetime.now().astimezone().strftime('%a, %d %b %Y %H:%M:%S %z')
for key, val in headers.items():
msg[key] = val
if self.smtps:
client = smtplib.SMTP_SSL(self.host, self.port)
else:
client = smtplib.SMTP(self.host, self.port)
if self.starttls:
client.starttls()
client.ehlo()
client.send_message(msg)
client.quit()
def send_welcome_message_to(self, user: IUser, password: str):
template = self.jinja_env.get_template('welcome_message.j2')
# TODO: store surname and givenName in LDAP
first_name = user.cn.split(' ', 1)[0]
body = template.render(name=first_name, user=user.uid, password=password)
self.send(
f'Computer Science Club <exec@{self.base_domain}>',
f'{user.cn} <{user.uid}@{self.base_domain}>',
{'Subject': 'Welcome to the Computer Science Club'},
body,
)
def announce_new_user(self, user: IUser, operations: List[str]):
# The person who added the new user
auth_user = g.auth_user
if '@' in auth_user:
auth_user = auth_user[:auth_user.index('@')]
if user.is_club():
prog = 'addclubrep'
desc = 'Club Rep'
else:
prog = 'addmember'
desc = 'Member'
operations_str = '\n'.join(operations)
template = self.jinja_env.get_template('announce_new_user.j2')
body = template.render(
user=user, auth_user=auth_user, prog=prog,
operations_str=operations_str)
self.send(
f'{prog} <ceo+{prog}@{self.base_domain}>',
f'Membership and Accounts <ceo@{self.base_domain}>',
{
'Subject': f'New {desc}: {user.uid}',
'Cc': f'{auth_user}@{self.base_domain}',
},
body,
)