Leitfaden · SMTP mit Python

Wie sollte ein Produktteam SMTP mit Python sicher implementieren?

Implementieren Sie SMTP in Python aus einem autorisierten Hintergrund-Worker und nicht direkt aus einer Webanfrage. Erstellen Sie die Nachricht mit EmailMessage, nutzen Sie SMTP_SSL für implizites TLS oder wechseln Sie ausdrücklich per STARTTLS zu TLS, wenn der aktuelle Vertrag des Providers es verlangt, authentifizieren Sie sich mit einem serverseitigen Geheimnis und rufen Sie send_message mit begrenzten Timeouts auf. Speichern Sie den Job, bevor Sie sich verbinden, erfassen Sie Ablehnungsnachweise pro Empfänger, gleichen Sie mehrdeutige Verbindungsabbrüche ab und unterscheiden Sie die SMTP-Annahme von späterer Zustellung und Platzierung im Posteingang.

Den Versand vor SMTP autorisieren und speichern

Beginnen Sie mit einem legitimen Anwendungsereignis wie Beleg, Sicherheitswarnung, angeforderter Verifizierung oder Kontohinweis. Authentifizieren Sie den Aufrufer und autorisieren Sie Mandant, Nachrichtenklasse, sichtbare From-Identität, Empfänger und Template-Revision. Schreiben Sie einen dauerhaften Ausgangs-Job mit stabilem Geschäftsereignis-Schlüssel, bevor Sie eine SMTP-Verbindung öffnen. Dieser Schlüssel sollte verhindern, dass zwei Worker dieselbe logische Nachricht unabhängig voneinander erzeugen. Browser-Eingaben dürfen weder SMTP-Host, Port, Benutzernamen, Envelope-Absender, beliebige Empfänger, Header noch die TLS-Richtlinie bestimmen. Halten Sie diese Werte in geprüfter Serverkonfiguration. Ein Queue-Worker sollte einen Job übernehmen, Sperrlisten und Autorisierung zur Sendezeit erneut prüfen, jeden Versuch protokollieren und den Job über explizite Zustände freigeben oder abschließen. Die SMTP-Bibliothek von Python transportiert die vorbereitete Nachricht. Sie liefert weder Mandantenautorisierung noch Einwilligung, Idempotenz oder Sperrlistenrichtlinie.

Die Nachricht mit EmailMessage erstellen

Verwenden Sie email.message.EmailMessage, statt rohe Header und Bodys zu verketten. Setzen Sie From, To, Subject, Date und eine generierte Message-ID gemäß dem freigegebenen Modell der Anwendung und nutzen Sie dann set_content für Text und bei Bedarf add_alternative für HTML. Validieren Sie Adressobjekte, begrenzen Sie Empfänger- und Anhangzahlen, weisen Sie Newline-Injection in Werten ab und maskieren Sie Template-Daten für den Ausgabekontext. Erzeugen Sie Text und HTML aus einer unveränderlichen Template-Revision. Halten Sie Geheimnisse und unnötige personenbezogene Daten aus Betreffzeilen, benutzerdefinierten Headern, Dateinamen, Diagnosefeldern und Logs heraus. Trennen Sie den sichtbaren From-Header bewusst vom SMTP-Envelope-Absender, denn Authentifizierung und Bounce-Verarbeitung können von unterschiedlichen Identitäten abhängen. Speichern Sie für das Audit eine Inhaltsrevision oder einen datenschutzsicheren Hash, statt vollständige Nachrichtentexte ohne definierten Bedarf aufzubewahren.

Implizites TLS oder STARTTLS ausdrücklich wählen

Python dokumentiert SMTP_SSL für von Beginn an verschlüsselte Verbindungen und SMTP.starttls für den Wechsel einer bestehenden Verbindung zu TLS. Folgen Sie dem aktuellen Vertrag des Providers zu Hostname, Port, Zertifikat und Einlieferung, statt aus einer generischen Portliste zu raten. Erstellen Sie einen verifizierten Standard-SSL-Kontext und deaktivieren Sie keine Zertifikats- oder Hostnamenprüfungen. Verbinden Sie sich bei STARTTLS, senden Sie bei Bedarf EHLO, rufen Sie starttls mit dem Kontext auf und senden Sie EHLO erneut, denn angebotene Erweiterungen können sich nach dem Wechsel ändern. Senden Sie Zugangsdaten oder Kundennachrichten niemals über eine Klartextverbindung. RFC 8314 empfiehlt TLS-geschützte Einlieferung und stuft Klartextzugriff als veraltet ein. Behandeln Sie Zertifikatsfehler, Hostnamen-Abweichung, fehlendes erforderliches STARTTLS oder unerwartete Änderungen der Fähigkeiten als harte Fehler, die untersucht werden müssen, statt stillschweigend zurückzufallen.

SMTP-Zugangsdaten in einer engen Secret-Grenze halten

Laden Sie Benutzernamen und Passwort oder Token zur Laufzeit aus einer verwalteten serverseitigen Secret-Infrastruktur. Legen Sie Zugangsdaten nicht in Quellcode, Client-Bundles, Umgebungs-Dumps, URLs, Exception-Traces, Analytics, Notebooks, Screenshots, Prompts oder eingecheckten Fixtures ab. Beschränken Sie jede Zugangsberechtigung auf die kleinste vom Provider unterstützte Umgebung und Workload und trennen Sie Entwicklung von Produktion. Authentifizieren Sie sich erst, wenn der erforderliche TLS-Zustand hergestellt ist. Proben Sie die Rotation mit kontrollierten Empfängern: Stellen Sie den Ersatz über die freigegebene Administration bereit, aktualisieren Sie den Worker, bestätigen Sie Authentifizierung und einen vollständigen Event-Lebenszyklus und widerrufen Sie dann den alten Wert. Wiederholte Authentifizierungsfehler sollten die betroffene Route pausieren, statt eine schnelle Wiederholungsschleife auszulösen. Die Methode login von Python handelt zwischen den vom Server angebotenen Mechanismen aus, aber der tatsächliche Mechanismus des Providers, Kontorichtlinien, Token-Berechtigungen und das Rotationsverhalten erfordern aktuelle Nachweise.

Eine begrenzte Python-Sendefunktion verwenden

Halten Sie den Provider-Adapter klein und geben Sie strukturierte Nachweise an die Job-Zustandsmaschine zurück. Ein typischer Ablauf erstellt einen SSL-Kontext, öffnet für implizites TLS SMTP_SSL(host, port, timeout=10) als smtp, ruft smtp.login(username, secret) auf und dann smtp.send_message(message, from_addr=envelope_from, to_addrs=recipients). Für einen Provider mit ausdrücklichem TLS-Wechsel verwenden Sie SMTP mit Timeout, ehlo, starttls(context=context), ehlo und danach login. Stellen Sie Beispiel-Hostnamen oder -Ports nicht als allgemeine Standardwerte dar. Übergeben Sie eine normalisierte Empfängerliste, statt sich auf das Parsen nicht vertrauenswürdiger Header zu verlassen. Erfassen Sie Exception-Klasse, SMTP-Antwortcode und begrenzten Diagnosetext, sofern verfügbar, schwärzen Sie aber Adressen, Zugangsdaten und Nachrichteninhalt. Messen Sie die Phasen Verbindung, TLS, Authentifizierung, Envelope, Data und Quit getrennt, damit sich Betriebsfehler weiter diagnostizieren lassen.

Empfängerergebnisse von send_message präzise interpretieren

Python dokumentiert, dass sendmail und send_message normal zurückkehren, wenn die Nachricht für mindestens einen Empfänger angenommen wurde, und ein Dictionary für abgelehnte Empfänger zurückgeben. Ein leeres Dictionary bedeutet, dass in dieser Phase kein Empfänger abgelehnt wurde. Bewahren Sie dieses Ergebnis pro Empfänger auf, statt den gesamten Job als zugestellt zu markieren. Werden alle Empfänger abgelehnt, löst die Bibliothek eine Exception SMTPRecipientsRefused aus. Andere Exceptions unterscheiden Ablehnung des Absenders, Ablehnung von DATA, Authentifizierung, Verbindung, Protokoll und verwandte Fehler. Bilden Sie exakte Nachweise auf Anwendungszustände ab: vom Einlieferungsserver angenommen, permanent abgelehnt, vorübergehend abgelehnt oder unbekannt. Eine normale Rückkehr belegt nur das SMTP-Einlieferungsergebnis in diesem Umfang. Sie belegt weder die Annahme durch den Zielserver noch die endgültige Postfachplatzierung, das Lesen oder Engagement. Spätere Zustellstatus-Benachrichtigungen oder Provider-Events müssen separat korreliert werden.

Nur wiederholen, wenn das Duplikatrisiko kontrolliert ist

Klassifizieren Sie Fehler, bevor Sie einen weiteren Versuch planen. Permanente Fehler bei Adresse, Absender, Authentifizierung, Richtlinie oder Inhalt erfordern in der Regel Korrektur oder Sperre statt automatischer Wiederholung. Vorübergehende 4xx-Antworten können mit exponentiellem Backoff, Jitter, Versuchsobergrenze, Ablauf und Budget pro Ziel wiederholt werden. Ein Verbindungsabbruch oder Timeout nach den Nachrichtendaten kann mehrdeutig sein: Der Server könnte die Nachricht angenommen haben, während der Client die endgültige Antwort verpasst hat. Belassen Sie diesen Versuch als unbekannt, prüfen Sie Provider-Aktivität oder spätere Events über datenschutzsichere Korrelation und vermeiden Sie ein sofortiges blindes erneutes Senden. SMTP kennt keinen universellen Idempotenzschlüssel für Anwendungen. Der dauerhafte Geschäftsereignis-Schlüssel verhindert gleichzeitige Anwendungsversuche, kann einen entfernten SMTP-Server aber nicht zwingen, zwei angenommene Einlieferungen zu deduplizieren. Eskalieren Sie wiederholte mehrdeutige Ergebnisse und bewahren Sie die für die Entscheidung genutzten Nachweise exakt auf.

Teilweise akzeptierte Empfänger und Sperrlisten behandeln

Hat eine Nachricht mehrere Empfänger, kann SMTP einige annehmen und andere ablehnen. Speichern Sie die Antwort jedes Empfängers und überführen Sie nur die akzeptierte Teilmenge in den nächsten Zustand. Senden Sie nicht die gesamte ursprüngliche Liste erneut, nur weil eine Adresse eine vorübergehende Ablehnung erhielt. Wenden Sie Sperren wegen permanenter Bounces, Beschwerden, Abmeldungen, Recht, Mandant und Administrator vor jedem Versuch an, auch bei Wiederholungen. Trennen Sie Nachrichtenklassen nur über eine ausdrücklich dokumentierte Richtlinie. Die Bezeichnung „transaktional“ hebt weder Empfängerschutz noch Provider-Beschränkungen auf. Bevorzugen Sie Jobs mit einem Empfänger für sensible Workflows, wenn Datenschutz und individueller Zustand den Aufwand rechtfertigen. Vermeiden Sie es, Empfängerlisten über To oder Cc offenzulegen, und nutzen Sie Bcc-Verhalten niemals als Ersatz für Autorisierung. Begrenzen und schwärzen Sie Diagnosetext, denn SMTP-Antworten können Empfängeradressen oder empfängerspezifische Details enthalten.

Fehlerpfade mit kontrollierten Systemen testen

Testen Sie Nachrichtenaufbau, Unicode, Text- und HTML-Alternativen, Anhänge, Header-Ablehnung, Empfängernormalisierung, TLS-Verifizierung, fehlendes STARTTLS, ungültige Zugangsdaten, Ablehnung des Absenders, Ablehnung eines und aller Empfänger, Ablehnung von DATA, Timeouts vor und nach möglicher Annahme, Verbindungsabbrüche, Rate-Antworten, Ablauf von Wiederholungen, doppelte Worker, Sperrlistenänderungen und Rotation von Geheimnissen. Verwenden Sie einen kontrollierten Test-SMTP-Service oder einen lokalen Fake für deterministische Unit- und Integrationstests und leiten Sie versehentlichen Traffic niedrigerer Umgebungen nie an Kundenadressen. Verwenden Sie in produktiven Canary-Tests autorisierte Empfänger und prüfen Sie die rohen Header auf sichtbares From, Envelope-Pfad, Message-ID, DKIM, SPF, DMARC-Alignment und Provider-Nachweise. Bestätigen Sie, dass Logs und Metriken keine Zugangsdaten oder Nachrichtentexte preisgeben. Lassen Sie den Launch scheitern, wenn der Worker die Mandantenautorisierung umgehen, TLS herabstufen, unbegrenzt wiederholen, teilweise Ablehnung ignorieren oder die Sendeleitung nicht pausieren kann.

So passt SendHQ

SendHQ ist eine auf den Workspace beschränkte E-Mail-API für erwartete Produktkommunikation. Die Dokumentation behandelt Versand, verifizierte Domains, Zustell-Events und Sperrlisten. Verwenden Sie die dokumentierte HTTP-API, wenn Sie SendHQ mit Python integrieren.

Häufig gestellte Fragen

Sollte Python SMTP_SSL oder STARTTLS verwenden?

Verwenden Sie den Modus, den der aktuelle Einlieferungsvertrag des Providers verlangt. SMTP_SSL verschlüsselt ab Verbindungsbeginn. STARTTLS wechselt ausdrücklich zu TLS und erfordert verifiziertes TLS sowie ein erneutes EHLO.

Beweist eine normale Rückkehr von send_message die Zustellung?

Nein. Sie bedeutet, dass in dieser SMTP-Einlieferungsphase mindestens ein Empfänger angenommen wurde. Annahme durch das Ziel, Postfachplatzierung und Engagement brauchen spätere Nachweise im jeweiligen Umfang.

Was bedeutet das von send_message zurückgegebene Dictionary?

Es ordnet vom SMTP-Server abgelehnte Empfänger den Antwortnachweisen zu. Ein leeres Dictionary bedeutet, dass in dieser Phase keine abgelehnt wurden, nicht dass jede Nachricht einen Posteingang erreicht hat.

Kann ein Timeout sofort wiederholt werden?

Nicht sicher, wenn es nach einer möglichen Einlieferung auftrat. Behalten Sie den Versuch als mehrdeutig bei, gleichen Sie Provider- oder spätere Event-Nachweise ab und senden Sie nur unter einer begrenzten Duplikatrisiko-Richtlinie erneut.

Wo sollte das SMTP-Passwort gespeichert werden?

Nutzen Sie eine verwaltete serverseitige Secret-Infrastruktur mit engem Zugriff nach Workload und Umgebung, protokolliertem Abruf, getesteter Rotation und ohne Offenlegung gegenüber Clients, Logs, Prompts oder Fixtures.

Sollte die Zertifikatsprüfung im Produktivbetrieb jemals deaktiviert werden?

Nein. Ein Zertifikats- oder Hostnamenfehler ist ein Hinweis auf unsichere oder falsche Konfiguration. Stoppen Sie die Route und diagnostizieren Sie sie, statt die TLS-Verifizierung stillschweigend abzuschwächen.

Wie sollte mit teilweiser Ablehnung von Empfängern umgegangen werden?

Speichern Sie jedes Empfängerergebnis, überführen Sie die akzeptierte Teilmenge weiter und wiederholen Sie nur infrage kommende vorübergehende Ablehnungen. Senden Sie bereits akzeptierte Empfänger nicht mit der gesamten ursprünglichen Liste erneut.

Belegt diese Seite, dass SendHQ SMTP unterstützt?

Nein. Dieser Leitfaden behandelt Python SMTP allgemein; verwenden Sie für die E-Mail-API die aktuelle SendHQ-Dokumentation.

Quellen