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