authentik.stages.email.utils
email utils
1"""email utils""" 2 3from email.mime.image import MIMEImage 4from functools import lru_cache 5from pathlib import Path 6 7from django.conf import settings 8from django.core.mail import EmailMultiAlternatives 9from django.core.mail.message import sanitize_address 10from django.template.exceptions import TemplateDoesNotExist 11from django.template.loader import render_to_string 12from django.utils import translation 13 14 15@lru_cache 16def logo_data() -> MIMEImage: 17 """Get logo as MIME Image for emails""" 18 path = Path("web/dist/assets/icons/icon_left_brand.png") 19 # When running tests, assets might not exist, so fallback to a different icon 20 if settings.TEST: 21 path = Path("web/authentik/sources/saml.png") 22 with open(path, "rb") as _logo_file: 23 logo = MIMEImage(_logo_file.read()) 24 logo.add_header("Content-ID", "<logo>") 25 logo.add_header("Content-Disposition", "inline", filename="logo.png") 26 return logo 27 28 29def _sanitize_recipients(recipients: list[tuple[str, str]]) -> list[str]: 30 """Sanitize a list of (name, email) tuples into valid email addresses.""" 31 sanitized = [] 32 for recipient_name, recipient_email in recipients: 33 # Remove any newline characters from name and email before sanitizing 34 clean_name = recipient_name.replace("\n", " ").replace("\r", " ") if recipient_name else "" 35 clean_email = recipient_email.replace("\n", "").replace("\r", "") if recipient_email else "" 36 sanitized.append(sanitize_address((clean_name, clean_email), "utf-8")) 37 return sanitized 38 39 40class TemplateEmailMessage(EmailMultiAlternatives): 41 """Wrapper around EmailMultiAlternatives with integrated template rendering""" 42 43 def __init__( 44 self, 45 to: list[tuple[str, str]], 46 cc: list[tuple[str, str]] | None = None, 47 bcc: list[tuple[str, str]] | None = None, 48 template_name=None, 49 template_context=None, 50 language="", 51 **kwargs, 52 ): 53 sanitized_to = _sanitize_recipients(to) 54 sanitized_cc = _sanitize_recipients(cc) if cc else None 55 sanitized_bcc = _sanitize_recipients(bcc) if bcc else None 56 super().__init__(to=sanitized_to, cc=sanitized_cc, bcc=sanitized_bcc, **kwargs) 57 if not template_name: 58 return 59 with translation.override(language): 60 html_content = render_to_string(template_name, template_context) 61 try: 62 text_content = render_to_string( 63 template_name.replace("html", "txt"), template_context 64 ) 65 self.body = text_content 66 except TemplateDoesNotExist: 67 pass 68 self.mixed_subtype = "related" 69 self.attach_alternative(html_content, "text/html")
@lru_cache
def
logo_data() -> email.mime.image.MIMEImage:
16@lru_cache 17def logo_data() -> MIMEImage: 18 """Get logo as MIME Image for emails""" 19 path = Path("web/dist/assets/icons/icon_left_brand.png") 20 # When running tests, assets might not exist, so fallback to a different icon 21 if settings.TEST: 22 path = Path("web/authentik/sources/saml.png") 23 with open(path, "rb") as _logo_file: 24 logo = MIMEImage(_logo_file.read()) 25 logo.add_header("Content-ID", "<logo>") 26 logo.add_header("Content-Disposition", "inline", filename="logo.png") 27 return logo
Get logo as MIME Image for emails
class
TemplateEmailMessage(django.core.mail.message.EmailMultiAlternatives):
41class TemplateEmailMessage(EmailMultiAlternatives): 42 """Wrapper around EmailMultiAlternatives with integrated template rendering""" 43 44 def __init__( 45 self, 46 to: list[tuple[str, str]], 47 cc: list[tuple[str, str]] | None = None, 48 bcc: list[tuple[str, str]] | None = None, 49 template_name=None, 50 template_context=None, 51 language="", 52 **kwargs, 53 ): 54 sanitized_to = _sanitize_recipients(to) 55 sanitized_cc = _sanitize_recipients(cc) if cc else None 56 sanitized_bcc = _sanitize_recipients(bcc) if bcc else None 57 super().__init__(to=sanitized_to, cc=sanitized_cc, bcc=sanitized_bcc, **kwargs) 58 if not template_name: 59 return 60 with translation.override(language): 61 html_content = render_to_string(template_name, template_context) 62 try: 63 text_content = render_to_string( 64 template_name.replace("html", "txt"), template_context 65 ) 66 self.body = text_content 67 except TemplateDoesNotExist: 68 pass 69 self.mixed_subtype = "related" 70 self.attach_alternative(html_content, "text/html")
Wrapper around EmailMultiAlternatives with integrated template rendering
TemplateEmailMessage( to: list[tuple[str, str]], cc: list[tuple[str, str]] | None = None, bcc: list[tuple[str, str]] | None = None, template_name=None, template_context=None, language='', **kwargs)
44 def __init__( 45 self, 46 to: list[tuple[str, str]], 47 cc: list[tuple[str, str]] | None = None, 48 bcc: list[tuple[str, str]] | None = None, 49 template_name=None, 50 template_context=None, 51 language="", 52 **kwargs, 53 ): 54 sanitized_to = _sanitize_recipients(to) 55 sanitized_cc = _sanitize_recipients(cc) if cc else None 56 sanitized_bcc = _sanitize_recipients(bcc) if bcc else None 57 super().__init__(to=sanitized_to, cc=sanitized_cc, bcc=sanitized_bcc, **kwargs) 58 if not template_name: 59 return 60 with translation.override(language): 61 html_content = render_to_string(template_name, template_context) 62 try: 63 text_content = render_to_string( 64 template_name.replace("html", "txt"), template_context 65 ) 66 self.body = text_content 67 except TemplateDoesNotExist: 68 pass 69 self.mixed_subtype = "related" 70 self.attach_alternative(html_content, "text/html")
Initialize a single email message (which can be sent to multiple recipients).