11import re
22import smtplib
3- from collections .abc import Sequence
43from email .headerregistry import Address
54from email .message import EmailMessage , MIMEPart
65from email .utils import make_msgid
1312from couchers .models import Email
1413from couchers .proto .internal import jobs_pb2
1514
16- template_base = Path (Path (__file__ ).parent / ".." / ".." / ".." / "templates" / "v2" )
17-
1815# Base directory for relative EmailPart.data_file_path
1916email_related_part_data_path_base = Path (couchers .__file__ ).parents [3 ] # /app/backend
2017
@@ -51,7 +48,7 @@ def process_relative_src_match(match: re.Match[str]) -> str:
5148 return html , related_parts
5249
5350
54- def email_proto_to_message (payload : jobs_pb2 .SendEmailPayload , couchers_id : str ) -> tuple [ EmailMessage , str | None ] :
51+ def email_proto_to_message (payload : jobs_pb2 .SendEmailPayload , couchers_id : str ) -> EmailMessage :
5552 msg = EmailMessage ()
5653 msg ["Subject" ] = payload .subject
5754 msg ["From" ] = Address (payload .sender_name , addr_spec = payload .sender_email )
@@ -67,29 +64,19 @@ def email_proto_to_message(payload: jobs_pb2.SendEmailPayload, couchers_id: str)
6764
6865 msg .set_content (payload .plain )
6966
70- html_body : str | None = payload .html
71- if html_body :
72- related_parts : Sequence [jobs_pb2 .EmailPart ] = payload .html_related_parts
73- if not related_parts :
74- # Backcompat (2026-06): Embedding relative images used to be this function's responsibility,
75- # and was moved to the payload builder. Keep this fallback in case we have queued payloads
76- # that didn't do their own embedding.
77- content_id_domain = Address (addr_spec = payload .sender_email ).domain
78- html_body , related_parts = embed_html_relative_images (
79- html_body , base_dir = template_base , content_id_domain = content_id_domain
80- )
81-
82- msg .add_alternative (html_body , subtype = "html" )
67+ if payload .html :
68+ msg .add_alternative (payload .html , subtype = "html" )
8369 html_part = cast (list [MIMEPart ], msg .get_payload ())[- 1 ]
8470
85- for related_part in related_parts :
86- _add_email_part (html_part , related_part , related = True )
71+ if payload .html_related_parts :
72+ for related_part in payload .html_related_parts :
73+ _add_email_part (html_part , related_part , related = True )
8774
8875 if payload .attachments :
8976 for attachment in payload .attachments :
9077 _add_email_part (msg , attachment , related = False )
9178
92- return msg , html_body
79+ return msg
9380
9481
9582def _add_email_part (msg : MIMEPart , part : jobs_pb2 .EmailPart , * , related : bool ) -> MIMEPart :
@@ -125,7 +112,7 @@ def send_smtp_email(payload: jobs_pb2.SendEmailPayload) -> Email:
125112 Returns a models.Email object that can be straight away added to the database.
126113 """
127114 message_id = random_hex ()
128- msg , updated_html = email_proto_to_message (payload , message_id )
115+ msg = email_proto_to_message (payload , message_id )
129116
130117 with smtplib .SMTP (config .SMTP_HOST , config .SMTP_PORT ) as server :
131118 server .ehlo ()
@@ -143,7 +130,7 @@ def send_smtp_email(payload: jobs_pb2.SendEmailPayload) -> Email:
143130 recipient = payload .recipient ,
144131 subject = payload .subject ,
145132 plain = payload .plain ,
146- html = updated_html or "" ,
133+ html = payload . html ,
147134 list_unsubscribe_header = payload .list_unsubscribe_header ,
148135 source_data = payload .source_data ,
149136 )
0 commit comments