SMTP für Python — die Post Ihres Skripts oder Ihrer Django-App, die ankommt
Python bringt SMTP mit: Mit smtplib senden Sie eine Nachricht in wenigen Zeilen, und Django fasst das in einer eigenen Mail-Schicht mit EMAIL-Einstellungen zusammen. Was keines von beiden liefert, ist die Zustellbarkeit — die hängt vom Server ab, über den Sie senden.
Ob Sie ein eigenständiges Skript, eine Flask-App oder ein Django-Projekt haben: Die Einstellungen sind dieselben fünf Daten. Sie richten sie auf Ihr Relay, und der Code, der die Nachrichten baut, bleibt unverändert.
Warum es ohne Relay schiefgeht
Python-Post kommt oft aus dem Hintergrund: ein nächtlicher Bericht, ein Cron-Job, der Rechnungen versendet, ein Skript, das alarmiert, wenn ein Messwert aus dem Toleranzbereich fällt. Niemand schaut zu — und deshalb merkt niemand, dass der empfangende Server sie still abweist. Bei Django kommt die klassische Go-live-Überraschung hinzu: In der Entwicklung geht alles an die Konsole, in der Produktion an echte Anbieter, die Reputation sehr wohl prüfen.
SMTP in Python einrichten
Zugangsdaten abrufen
Melden Sie sich in Ihrem 2mail-Konto an und rufen Sie dort Ihren SMTP-Server, Benutzernamen und Ihr Passwort ab.
In Python eintragen
In einem Django-Projekt legen Sie die EMAIL-Einstellungen in den Settings fest: das SMTP-Backend als E-Mail-Backend, den Host des Relays, Port 587, die STARTTLS-Option aktiviert, Benutzername und Passwort sowie eine Standard-Absenderadresse auf Ihrer eigenen Domain. Wenn Sie direkt mit smtplib arbeiten, verbinden Sie sich mit dem Host auf Port 587, rufen starttls auf, melden sich mit Benutzername und Passwort an und senden dann die Nachricht. In beiden Fällen lesen Sie die Daten aus Umgebungsvariablen, nicht aus dem Code.
Domain authentifizieren
Sorgen Sie dafür, dass SPF, DKIM und DMARC für Ihre Domain korrekt gesetzt sind, damit Empfänger verifizieren können, dass die Mail von Ihnen stammt.
Testen
Senden Sie von Ihrer Plattform aus eine Testnachricht an eine Adresse bei einem großen Provider und prüfen Sie, ob sie im Posteingang ankommt und nicht im Spam-Ordner.
Die Felder, die Python abfragt
Jede Plattform nennt sie etwas anders, aber es geht immer um dieselben fünf. Die konkreten Werte sind kontogebunden und finden Sie in Ihrem 2mail-Konto — rufen Sie sie dort ab, damit Sie sicher die richtigen verwenden.
| Feld | Was Sie eintragen |
|---|---|
| SMTP-Server (Host) | Der Servername aus Ihrem 2mail-Konto. |
| Port | Der Port, der zu Ihrer gewählten Verschlüsselung gehört; Ihr Konto zeigt, welcher. |
| Verschlüsselung | TLS. Senden Sie nie unverschlüsselt — sonst gehen Ihre Zugangsdaten lesbar über die Leitung. |
| Benutzername | Der SMTP-Login Ihres 2mail-Kontos. |
| Passwort | Das zugehörige Passwort. Verwenden Sie nie das Passwort eines Mitarbeiterpostfachs. |
SMTP-Konfiguration für Python im Code
Funktionierende Beispiele für Port 587 mit STARTTLS, direkt zum Übernehmen. Ersetzen Sie die Absenderadresse durch eine Adresse auf Ihrer eigenen Domain und prüfen Sie Servername und Login in Ihrem 2mail-Konto. Das Passwort gehört in eine Umgebungsvariable — nie in den Code und nie in die Versionsverwaltung.
smtplib: Verbindung auf 587 mit starttls()
Die Standardbibliothek genügt. Die Reihenfolge zählt: zuerst starttls(), erst dann login() — sonst geht Ihr Passwort unverschlüsselt über die Leitung, oder das Relay lehnt die Anmeldung ab. Verwenden Sie smtplib.SMTP und nicht SMTP_SSL: Letzteres gehört zu Port 465. Benutzername und Passwort kommen aus Umgebungsvariablen.
import os
import smtplib
import ssl
from email.message import EmailMessage
msg = EmailMessage()
msg["From"] = "Example <noreply@example.com>"
msg["To"] = "you@example.org"
msg["Subject"] = "SMTP test"
msg.set_content("Sent through the 2mail SMTP relay.")
context = ssl.create_default_context()
with smtplib.SMTP("relay.2mail.eu", 587, timeout=10) as server:
server.starttls(context=context) # upgrade to TLS first, log in afterwards
server.login(os.environ["SMTP_USERNAME"], os.environ["SMTP_PASSWORD"])
server.send_message(msg) # call again for the next message, same connection Django: die EMAIL_*-Settings
Django braucht kein zusätzliches Paket. Legen Sie das SMTP-Backend ausdrücklich fest: In der Entwicklung steht es oft auf dem Konsolen-Backend, und dann versendet die Produktion nichts, während alles zu funktionieren scheint. sendtestemail ist ein eingebauter Management-Befehl, mit dem Sie die Einstellungen prüfen, ohne eine View oder einen Task aufrufen zu müssen.
# settings.py
import os
EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend"
EMAIL_HOST = "relay.2mail.eu"
EMAIL_PORT = 587
EMAIL_USE_TLS = True # STARTTLS - never together with EMAIL_USE_SSL
EMAIL_HOST_USER = os.environ["SMTP_USERNAME"]
EMAIL_HOST_PASSWORD = os.environ["SMTP_PASSWORD"]
EMAIL_TIMEOUT = 10
DEFAULT_FROM_EMAIL = "Example <noreply@example.com>"
SERVER_EMAIL = "noreply@example.com" # sender of error reports to ADMINS
# Test from the shell:
# python manage.py sendtestemail you@example.org Flask-Mail: dieselben fünf Daten
Wenn Sie mit Flask arbeiten, fragt Flask-Mail dieselben Daten unter anderen Namen ab. Auch hier gilt: MAIL_USE_TLS für Port 587, und MAIL_USE_SSL bleibt aus.
import os
from flask import Flask
from flask_mail import Mail
app = Flask(__name__)
app.config.update(
MAIL_SERVER="relay.2mail.eu",
MAIL_PORT=587,
MAIL_USE_TLS=True, # STARTTLS
MAIL_USE_SSL=False,
MAIL_USERNAME=os.environ["SMTP_USERNAME"],
MAIL_PASSWORD=os.environ["SMTP_PASSWORD"],
MAIL_DEFAULT_SENDER="noreply@example.com",
)
mail = Mail(app) Welche Mails Python sendet
Sobald das Relay eingerichtet ist, laufen diese alle über 2mail — Sie müssen sie nicht einzeln konfigurieren.
Stolperfallen bei Python
TLS-Option und Port müssen zusammenpassen
Django kennt zwei getrennte TLS-Einstellungen: eine für STARTTLS und eine für TLS von Anfang an. Aktivieren Sie nur die für STARTTLS, die zu Port 587 passt. Beide zugleich führen zu einem Konfigurationsfehler; keine von beiden sendet Ihre Zugangsdaten im Klartext, was ein Relay zu Recht ablehnt.
Eine Verbindung pro Serie, nicht pro Nachricht
Ein Skript, das für jede von tausend Nachrichten eine neue SMTP-Verbindung öffnet, verhält sich wie ein Angreifer. Öffnen Sie eine Verbindung, senden Sie die Serie, schließen Sie. Django hat dafür eine Funktion, die mehrere Nachrichten über eine einzige Verbindung sendet.
Stille Fehler in Hintergrundaufgaben
Eine Exception in einem Cron-Job verschwindet in einer Logdatei, die niemand liest. Fangen Sie Versandfehler ab und melden Sie sie dort, wo sie gesehen werden — und binden Sie die Webhooks von 2mail für Zustellung und Bounces an, damit Sie auch sehen, was nach der Übergabe scheitert.
Häufige Fehlermeldungen bei Python
Die Meldungen, die Sie sehen, wenn Host, Port, Verschlüsselung oder Login nicht stimmen — im Wortlaut, damit Sie sie in Ihrem Log wiedererkennen, mit Ursache und Lösung daneben.
| Meldung | Ursache | Lösung |
|---|---|---|
smtplib.SMTPAuthenticationError: (535, b'5.7.8 Error: authentication failed: …') | Das Relay lehnt die Anmeldung ab: ein falscher Benutzername oder ein falsches Passwort, oder eine Umgebungsvariable, die im Cron- oder Service-Kontext einen anderen Wert hat als in Ihrer Shell. | Geben Sie aus, was der Prozess tatsächlich liest (den Benutzernamen, nie das Passwort), und verwenden Sie den SMTP-Login aus Ihrem 2mail-Konto — nicht das Passwort eines Postfachs. |
smtplib.SMTPNotSupportedError: SMTP AUTH extension not supported by server. | login() wird vor starttls() aufgerufen. Ein Relay bietet die Anmeldung erst an, sobald die Verbindung verschlüsselt ist; auf der noch unverschlüsselten Verbindung gibt es AUTH also nicht. | Rufen Sie zuerst server.starttls(context=context) auf und erst dann server.login(…). In Django: Setzen Sie EMAIL_USE_TLS = True. |
ssl.SSLError: [SSL: WRONG_VERSION_NUMBER] wrong version number (_ssl.c:…) | Der Code verwendet smtplib.SMTP_SSL (oder in Django EMAIL_USE_SSL) auf Port 587. Python beginnt dann sofort mit einem TLS-Handshake, während das Relay auf diesem Port zuerst gewöhnliches SMTP erwartet und erst nach STARTTLS umschaltet. Die klassische Verwechslung von 465 und 587. | Verwenden Sie smtplib.SMTP(…, 587) gefolgt von starttls(), oder in Django EMAIL_USE_TLS = True mit Port 587. |
smtplib.SMTPServerDisconnected: Connection unexpectedly closed | Die Verbindung ist vor oder während des Dialogs abgebrochen. Meist ein Skript, das eine Verbindung offen hält und sie nach einer langen Pause wiederverwendet, während der Server sie inzwischen wegen Inaktivität geschlossen hat — oder eine gewöhnliche SMTP-Verbindung zu einem Port, der TLS ab dem ersten Byte erwartet. | Öffnen Sie eine Verbindung pro Serie von Nachrichten und schließen Sie sie danach; fangen Sie die Exception ab und verbinden Sie sich neu. Prüfen Sie, dass Sie Port 587 mit starttls() verwenden. |
ValueError: EMAIL_USE_TLS/EMAIL_USE_SSL are mutually exclusive, so only set one of those settings to True. | In den Django-Settings sind beide TLS-Optionen aktiviert — oft, weil eine davon aus einer gemeinsamen Basisdatei stammt und die andere aus den Produktions-Settings. | Lassen Sie nur EMAIL_USE_TLS = True stehen und setzen Sie EMAIL_USE_SSL = False. |
Andere Plattform?
SMTP ist ein Standardprotokoll: Jedes System, das SMTP spricht — ein CRM, ein ERP, eine eigene Anwendung oder ein Server —, kann über 2mail mit denselben fünf Feldern senden.