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'^(?Psmtps?)://(?P[\w.-]+)(:(?P\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 ', 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} ', f'Membership and Accounts ', { 'Subject': f'New {desc}: {user.uid}', 'Cc': f'{auth_user}@{self.base_domain}', }, body, )