2mail — relay SMTP z belgijskiej infrastruktury

SMTP dla Pythona — poczta ze skryptu albo aplikacji Django, która dociera

Python ma SMTP wbudowane: dzięki smtplib wyślą Państwo wiadomość w kilku linijkach, a Django pakuje to we własną warstwę pocztową z ustawieniami EMAIL. Czego nie dostarcza żadne z nich, to dostarczalność — ta zależy od serwera, przez który Państwo wysyłają.

Czy mają Państwo luźny skrypt, aplikację Flask czy projekt Django: ustawienia to te same pięć danych. Kierują je Państwo na swój relay, a kod budujący wiadomości zostaje bez zmian.

Dlaczego bez relaya coś idzie nie tak

Poczta z Pythona pochodzi często z tła: nocnego raportu, zadania cron wysyłającego faktury, skryptu ostrzegającego, gdy pomiar wypada poza normę. Nikt na to nie patrzy — a więc nikt nie zauważa, że serwer odbiorcy po cichu je odrzuca. Przy Django dochodzi klasyczna niespodzianka przy uruchomieniu: w rozwoju wszystko idzie na konsolę, a w produkcji do prawdziwych dostawców, którzy <em>faktycznie</em> sprawdzają reputację.

Konfiguracja SMTP w Python

1

Pobranie danych

Zaloguj się na swoje konto 2mail i pobierz stamtąd serwer SMTP, nazwę użytkownika oraz hasło.

2

Wpisanie w Python

W projekcie Django prosimy ustawić w settings dane EMAIL: backend SMTP jako backend pocztowy, host relaya, port 587, włączoną opcję STARTTLS, nazwę użytkownika i hasło oraz domyślny adres nadawcy we własnej domenie. Jeśli pracują Państwo bezpośrednio ze smtplib, prosimy połączyć się z hostem na porcie 587, wywołać starttls, zalogować się nazwą użytkownika i hasłem, a potem wysłać wiadomość. W obu przypadkach prosimy odczytywać dane ze zmiennych środowiskowych, a nie z kodu.

3

Uwierzytelnienie domeny

Zadbaj o poprawne ustawienie SPF, DKIM i DMARC dla swojej domeny, aby odbiorcy mogli zweryfikować, że wiadomość pochodzi od Ciebie.

4

Test

Wyślij ze swojej platformy wiadomość testową na adres u dużego dostawcy i sprawdź, czy trafia do skrzynki odbiorczej, a nie do spamu.

Pola, o które prosi Python

Każda platforma nazywa je nieco inaczej, ale zawsze chodzi o te same pięć. Konkretne wartości są powiązane z kontem i znajdą je Państwo na swoim koncie 2mail — prosimy je stamtąd przepisać, aby mieć pewność, że są właściwe.

Pole Co wpisać
Serwer SMTP (host)Nazwa serwera z Państwa konta 2mail.
PortPort odpowiadający wybranemu szyfrowaniu; Państwa konto pokazuje, który to.
SzyfrowanieTLS. Nigdy nie wysyłają Państwo bez szyfrowania — inaczej dane logowania idą przez sieć otwartym tekstem.
Nazwa użytkownikaLogin SMTP Państwa konta 2mail.
HasłoOdpowiadające mu hasło. Nigdy nie należy używać hasła do skrzynki pracownika.

Konfiguracja SMTP dla Python w kodzie

Działające przykłady dla portu 587 ze STARTTLS, gotowe do skopiowania. Prosimy zastąpić adres nadawcy adresem we własnej domenie oraz sprawdzić nazwę serwera i login na swoim koncie 2mail. Miejsce hasła jest w zmiennej środowiskowej — nigdy w kodzie i nigdy w systemie kontroli wersji.

smtplib: połączenie na porcie 587 ze starttls()

Biblioteka standardowa wystarczy. Kolejność ma znaczenie: najpierw starttls(), dopiero potem login() — inaczej Państwa hasło idzie przez sieć bez szyfrowania albo relay odrzuca logowanie. Prosimy używać smtplib.SMTP, a nie SMTP_SSL: ta druga klasa pasuje do portu 465. Login i hasło pochodzą ze zmiennych środowiskowych.

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: ustawienia EMAIL_*

Django nie potrzebuje dodatkowego pakietu. Prosimy jawnie ustawić backend SMTP: w środowisku deweloperskim często ustawiony jest backend konsolowy, a wtedy produkcja niczego nie wysyła, choć wszystko wydaje się działać. sendtestemail to wbudowane polecenie administracyjne, którym sprawdzą Państwo ustawienia bez wywoływania widoku albo zadania.

# 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: te same pięć danych

Jeśli pracują Państwo z Flaskiem, Flask-Mail pyta o te same dane pod innymi nazwami. Tu także obowiązuje zasada: MAIL_USE_TLS dla portu 587, a MAIL_USE_SSL pozostaje wyłączone.

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)

Jakie wiadomości wysyła Python

Gdy relay jest już skonfigurowany, wszystkie idą przez 2mail — nie trzeba ich konfigurować pojedynczo.

Reset hasła i weryfikacja adresu e-mail z Django
Zaplanowane raporty i eksporty z zadań cron
Ostrzeżenia ze skryptów monitoringu i przetwarzania danych
Faktury i potwierdzenia z aplikacji webowej
Raporty o błędach do administratorów

Pułapki przy Python

Opcja TLS i port muszą się zgadzać

Django zna dwa osobne ustawienia TLS: jedno dla STARTTLS i jedno dla TLS od samego początku. Prosimy włączyć wyłącznie ustawienie STARTTLS; ono pasuje do portu 587. Oba naraz dają błąd konfiguracji; żadne z nich wysyła Państwa login bez szyfrowania, a to relay słusznie odrzuca.

Jedno połączenie na serię, nie na wiadomość

Skrypt, który dla każdej z tysiąca wiadomości otwiera nowe połączenie SMTP, zachowuje się jak napastnik. Prosimy otworzyć jedno połączenie, wysłać serię i zamknąć. Django ma do tego funkcję wysyłania wielu wiadomości przez jedno połączenie.

Ciche błędy w zadaniach w tle

Wyjątek w zadaniu cron znika w pliku logu, którego nikt nie czyta. Prosimy przechwytywać błędy przy wysyłce i zgłaszać je tam, gdzie rzucają się w oczy — oraz podłączyć webhooki 2mail dla dostarczenia i odbicia, aby widzieć też, co psuje się <em>po</em> przekazaniu.

Częste komunikaty o błędach przy Python

Komunikaty, które zobaczą Państwo, gdy host, port, szyfrowanie albo login się nie zgadzają — przytoczone dosłownie, aby dało się je rozpoznać w logu, wraz z przyczyną i rozwiązaniem obok.

Komunikat Przyczyna Rozwiązanie
smtplib.SMTPAuthenticationError: (535, b'5.7.8 Error: authentication failed: …') Relay odrzuca login: błędna nazwa użytkownika albo błędne hasło, albo zmienna środowiskowa, która w kontekście crona lub usługi ma inną wartość niż w Państwa powłoce. Prosimy wypisać to, co proces faktycznie odczytuje (nazwę użytkownika, nigdy hasło), i użyć loginu SMTP z Państwa konta 2mail — a nie hasła do skrzynki pocztowej.
smtplib.SMTPNotSupportedError: SMTP AUTH extension not supported by server. login() jest wywoływane przed starttls(). Relay oferuje uwierzytelnianie dopiero wtedy, gdy połączenie jest szyfrowane; na jeszcze nieszyfrowanym połączeniu AUTH po prostu nie istnieje. Prosimy najpierw wywołać server.starttls(context=context), a dopiero potem server.login(…). W Django: prosimy ustawić EMAIL_USE_TLS = True.
ssl.SSLError: [SSL: WRONG_VERSION_NUMBER] wrong version number (_ssl.c:…) Kod używa smtplib.SMTP_SSL (albo, w Django, EMAIL_USE_SSL) na porcie 587. Python zaczyna wtedy od razu od uzgadniania TLS, podczas gdy relay na tym porcie oczekuje najpierw zwykłego SMTP i przełącza się dopiero po STARTTLS. Klasyczne pomylenie portów 465 i 587. Prosimy użyć smtplib.SMTP(…, 587), a następnie starttls(), albo w Django EMAIL_USE_TLS = True z portem 587.
smtplib.SMTPServerDisconnected: Connection unexpectedly closed Połączenie zostało zerwane przed rozmową albo w jej trakcie. Zwykle to skrypt, który utrzymuje otwarte połączenie i po długiej przerwie używa go ponownie, podczas gdy serwer zdążył je zamknąć z powodu braku aktywności — albo zwykłe połączenie SMTP z portem, który oczekuje TLS od pierwszego bajtu. Prosimy otwierać jedno połączenie na serię wiadomości i zamykać je po wysyłce; wyjątek prosimy przechwycić i połączyć się ponownie. Prosimy sprawdzić, czy używają Państwo portu 587 ze starttls().
ValueError: EMAIL_USE_TLS/EMAIL_USE_SSL are mutually exclusive, so only set one of those settings to True. W ustawieniach Django włączone są obie opcje TLS — często dlatego, że jedna pochodzi ze wspólnego pliku bazowego, a druga z ustawień produkcyjnych. Prosimy zostawić wyłącznie EMAIL_USE_TLS = True i ustawić EMAIL_USE_SSL = False.
SPF, DKIM i DMARC wyjaśnione O dostarczalności

Inna platforma?

SMTP to protokół standardowy: każdy system, który mówi po SMTP — CRM, ERP, własna aplikacja albo serwer — może wysyłać przez 2mail z użyciem tych samych pięciu pól.

Najczęściej zadawane pytania o SMTP dla Python

smtplib i Django wysyłają, ale nie dostarczają dostarczalności: ta zależy od serwera, przez który Państwo wysyłają. Lokalna funkcja pocztowa albo świeży serwer nie ma uwierzytelniania ani reputacji. Relay SMTP z poprawnymi rekordami SPF, DKIM i DMARC to rozwiązuje.
Backend SMTP jako backend poczty, host relaya, port 587, włączoną opcję STARTTLS, swoją nazwę użytkownika i hasło oraz domyślny adres nadawcy we własnej domenie. Login prosimy przechowywać w zmiennych środowiskowych, a nie w samych ustawieniach.
Prosimy nawiązać połączenie z hostem na porcie 587, wywołać starttls, zalogować się nazwą użytkownika i hasłem i wysłać wiadomość. Przy kilku wiadomościach prosimy używać tego samego połączenia zamiast otwierać nowe dla każdej z nich.
Na swoim koncie 2mail, dla każdego zastosowania osobno. Są przypisane do konta, więc nie publikujemy ich na stronie. Dla każdego skryptu albo aplikacji prosimy najlepiej utworzyć własny login, aby móc go osobno odwołać i osobno śledzić ruch.
Trust Guard Security Scanned
Zadzwoń teraz
Wyślij e-mail