26:def build_mime_message( 27- from_email: str, 28- to_email: str, 29- subject: str, 30- html_body: str = "", 31- text_body: str = "", 32- attachments: Optional[list] = None, # list of {filename, content(bytes), mime_type} 33- unsubscribe_url: str = "", 34- unsubscribe_mailto: str = "", 35-) -> MIMEMultipart: 36- """Build a real MIME multipart message. From header always equals the authenticated account.""" 37- attachments = attachments or [] 38- # RFC 2046 structure: when attachments exist, build 39- # multipart/mixed[ alternative/plain+html, attachment... ]; attachments are 40- # NEVER siblings of the body alternatives (multipart/alternative only holds 41- # the same content in different formats). 42- body = MIMEMultipart("alternative") if (html_body and text_body) else None 43- msg = MIMEMultipart("mixed") if attachments else ( 44- MIMEMultipart("alternative") if (html_body and text_body) else MIMEMultipart("mixed")) 45- msg["From"] = from_email # MUST be the authenticated Gmail account (never spoofed) 46- msg["To"] = to_email 47- msg["Subject"] = subject 48- msg["Date"] = formatdate(localtime=True) 49- msg["Message-ID"] = make_msgid() 50- msg["X-Mailer"] = "BulkGmailMailer (permission-based sending)" 51- 52- # List-Unsubscribe headers for compliance 53- if unsubscribe_url: 54- parts = [f"<{unsubscribe_url}>"] 55- if unsubscribe_mailto: 56- parts.append(f"") 57- msg["List-Unsubscribe"] = ", ".join(parts) 58- msg["List-Unsubscribe-Post"] = "List-Unsubscribe=One-Click" 59- 60- # Text part first, then HTML (preferred last in alternative) 61- if text_body: 62- (body or msg).attach(MIMEText(text_body, "plain", "utf-8")) 63- if html_body: 64- (body or msg).attach(MIMEText(html_body, "html", "utf-8")) 65- if body is not None: 66- msg.attach(body) 67- 68- # Attachments 69- for att in attachments: 70- data = att["content"] 71- ctype = att.get("mime_type") or "application/octet-stream"