extensions-website/emails/util.py
2024-02-24 00:31:00 +01:00

88 lines
2.7 KiB
Python

"""Utilities for rendering email templates."""
from typing import List, Optional, Tuple, Dict, Any
import logging
from django.conf import settings
from django.contrib.sites.shortcuts import get_current_site
from django.template import loader
from django.core.mail import get_connection, EmailMultiAlternatives
from django.urls import reverse
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
def _get_site_url():
domain = get_current_site(None).domain
return f'https://{domain}'
def absolute_url(
view_name: str, args: Optional[tuple] = None, kwargs: Optional[dict] = None
) -> str:
"""Same as django.urls.reverse() but then as absolute URL.
For simplicity this assumes HTTPS is used.
"""
from urllib.parse import urljoin
relative_url = reverse(view_name, args=args, kwargs=kwargs)
return urljoin(_get_site_url(), relative_url)
def is_noreply(email: str) -> bool:
"""Return True if the email address is a no-reply address."""
return email.startswith('noreply@') or email.startswith('no-reply@')
def get_template_context() -> Dict[str, str]:
"""Return additional context for use in an email template."""
return {
'site_url': _get_site_url(),
# 'profile_url': absolute_url('profile_update'),
'DEFAULT_REPLY_TO_EMAIL': settings.DEFAULT_REPLY_TO_EMAIL,
}
def construct_email(email_name: str, context: Dict[str, Any]) -> Tuple[str, str, str]:
"""Construct an email message.
:return: tuple (html, text, subject)
"""
base_path = 'emails'
subj_tmpl, html_tmpl, txt_tmpl = (
f'{base_path}/{email_name}_subject.txt',
f'{base_path}/{email_name}.html',
f'{base_path}/{email_name}.txt',
)
subject: str = loader.render_to_string(subj_tmpl, context)
context['subject'] = subject.strip()
email_body_html = loader.render_to_string(html_tmpl, context)
email_body_txt = loader.render_to_string(txt_tmpl, context)
return email_body_html, email_body_txt, context['subject']
def construct_and_send_email(
email_name: str, context: Dict[str, Any], recipient_list: List[str]
) -> int:
"""Construct an email message and send it.
:return: int
"""
email_body_html, email_body_txt, subject = construct_email(email_name, context)
connection = get_connection(fail_silently=False)
mail = EmailMultiAlternatives(
context['subject'],
email_body_txt,
from_email=None, # just use the configured default From-address.
to=recipient_list,
connection=connection,
reply_to=[settings.DEFAULT_REPLY_TO_EMAIL],
)
mail.attach_alternative(email_body_html, 'text/html')
return mail.send()