Reputationspflege 7: Schlangenmail

Unter den Augen des gestrengen Rspamd muss ich einige Python-Skripte mit E-Mail-Funktion umarbeiten: Grundlose MIME multipart messages

msg = MIMEMultipart() msg.attach(MIMEText(body, 'plain'))

– werden mit dem Symbol CTYPE_MIXED_BOGUS (1) markiert, während –

msg = MIMEText(body, 'plain')

– ein wohlwollendes MIME_GOOD (-0.1) nach sich zieht. Außerdem lerne ich, dass Postfix seit Version 2.6 mit Rücksicht auf fragile DKIM-Signaturen fehlende Header nicht mehr automatisch ergänzt – mit gravierenden Folgen (MISSING_MID (2.5), MISSING_DATE (1)) für meine skriptbasierten E-Mails. Zwar könnte ich Postfix nun anweisen, wieder für vollständige Header zu sorgen (always_add_missing_headers = yes). Dadurch entstünden allerdings Message-IDs der Form 20220219215732.2CE497F8AA@mail.eden.one, die einen falschen Eindruck vom Geburtsort der Nachrichten vermitteln.

Manuell in mutt komponierte E-Mails tragen nämlich IDs der Form YhHNelJ2KZ2Lni7x@client.eden.one, basierend auf dem internen ID-Algorithmus mutt_gen_msgid() und der Einstellung set hostname="client.eden.one" in .muttrc. Die Python-Funktion email.utils.make_msgid() erzeugt mit dem Parameterwert domain='client.eden.one' entsprechende Herkunftsnachweise, wenn auch mit einer anderen ID-Struktur. Der gleichnamige msmtp-Parameter domain sorgt in Verbindung mit dem Hostnamen client.eden.one übrigens für Konsistenz zwischen Message-ID und Received-Header, während der vergleichbare Parameter der Python-Funktion smtplib.SMTP() local_hostname heißt. Etwas verwirrend, aber funktional gleichwertig:

# mutt und msmtp Received: from client.eden.one (cable-XX-XX-XXX-X.nc.de [XX.XX.XXX.X]) Message-ID: <YhHNelJ2KZ2Lni7x@client.eden.one> # Python Received: from client.eden.one (cable-XX-XX-XXX-X.nc.de [XX.XX.XXX.X]) Message-ID: <164535102753.2523.10851843159073092003@client.eden.one>

Schließlich löse ich auch noch das Rätsel des MIME_BASE64_TEXT (0.1): Jede automatisch generierte E-Mail, die sich nicht auf den ASCII-Zeichensatz beschränkt, wird seitens des Python-Moduls email.mime base64-kodiert. Rspamd hält quoted-printable für angemessener und vergibt das obige Symbol. Bis vor einigen Jahren hätte eine entsprechende Änderung eine manuelle Anpassung der MIME-Header erfordert, mit der set_content()-Funktion der EmailMessage-Klasse (seit Python 3.6) und ihrem Parameter cte ist es sehr viel einfacher. Die verschiedenen Anpassungen nehme ich zum Anlass, den E-Mail-Versand aller Skripte an das Modul scriptmail zu delegieren:

#!/usr/bin/env python3 import os import datetime import __main__ as main import smtplib from email.message import EmailMessage from email.headerregistry import Address from email.utils import make_msgid import keyring smtp_server = 'mail.eden.one' smtp_user = 'user@eden.one' port = 587 recipient = Address("Script Master", "user", "eden.one") sender = Address("Script Status", "noreply", "eden.one") localhost = 'client.eden.one' def send_message(subject, body): now = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') subject = f'{os.path.basename(main.__file__)}: {subject}' body = f'{body}\n\n{now}' msg = EmailMessage() msg['From'] = sender msg['To'] = recipient msg['Subject'] = subject msg['Message-ID'] = make_msgid(domain=localhost) msg.set_content(body, cte='quoted-printable') smtp_password = keyring.get_password(smtp_server, smtp_user) s = smtplib.SMTP(host=smtp_server, local_hostname=localhost, port=port) s.starttls() s.login(smtp_user, smtp_password) s.send_message(msg) del msg

Die Funktion send_message() ergänzt vor dem Versand den Subject-Header um den Namen des aufrufenden Skripts und den Body um einen Zeitstempel. Das SMTP-Passwort wird aus dem macOS-Schlüsselbund entnommen.