Python CSC Electronic Office
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
pyceo/ceod/model/MailService.py

153 lines
5.5 KiB

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')
if match.group('port') is not None:
self.port = int(match.group('port'))
elif self.smtps:
self.port = 465
else:
self.port = 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'),
keep_trailing_newline=True,
)
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')
first_name = user.given_name
if not first_name:
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.non_member_terms:
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,
)
def send_membership_renewal_reminder(self, user: IUser):
template = self.jinja_env.get_template('membership_renewal_reminder.j2')
body = template.render(user=user)
self.send(
f'Computer Science Club <ceo+memberships@{self.base_domain}>',
f'{user.cn} <{user.uid}@{self.base_domain}>',
{
'Subject': 'Computer Science Club membership renewal reminder',
'Reply-To': f'syscom@{self.base_domain}',
},
body,
)
def send_cloud_account_will_be_deleted_message(self, user: IUser):
template = self.jinja_env.get_template('cloud_account_will_be_deleted.j2')
body = template.render(user=user)
self.send(
f'cloudaccounts <ceo+cloudaccounts@{self.base_domain}>',
f'{user.cn} <{user.uid}@{self.base_domain}>',
{
'Subject': 'Your CSC Cloud account will be deleted',
'Cc': f'root@{self.base_domain}',
'Reply-To': f'syscom@{self.base_domain}',
},
body,
)
def send_cloud_account_has_been_deleted_message(self, user: IUser):
template = self.jinja_env.get_template('cloud_account_has_been_deleted.j2')
body = template.render(user=user)
self.send(
f'cloudaccounts <ceo+cloudaccounts@{self.base_domain}>',
f'{user.cn} <{user.uid}@{self.base_domain}>',
{
'Subject': 'Your CSC Cloud account has been deleted',
'Cc': f'root@{self.base_domain}',
'Reply-To': f'syscom@{self.base_domain}',
},
body,
)
def send_club_website_has_been_disabled_message(self, club: str, address: str):
template = self.jinja_env.get_template('club_website_has_been_disabled.j2')
body = template.render(club=club)
self.send(
f'Computer Science Club <ceo+webhosting@{self.base_domain}>',
f'{club} <{address}>',
{
'Subject': 'Your club website has been disabled',
'Cc': f'root@{self.base_domain}',
'Reply-To': f'syscom@{self.base_domain}',
},
body,
)