guida · smtp python
Come può un team di prodotto implementare SMTP con Python in modo sicuro?
Implementa SMTP in Python da un worker in background autorizzato, non direttamente da una richiesta web. Costruisci il messaggio con EmailMessage, usa SMTP_SSL per il TLS implicito oppure esegui un upgrade esplicito con STARTTLS quando l'attuale contratto del provider lo richiede, autenticati con un segreto lato server e chiama send_message con timeout limitati. Salva il job prima di connetterti, registra le prove di rifiuto per ogni destinatario, riconcilia le disconnessioni ambigue e distingui l'accettazione SMTP dalla consegna successiva e dall'arrivo in inbox.
Autorizza e salva l'invio prima di SMTP
Parti da un evento applicativo legittimo, come una ricevuta, un avviso di sicurezza, una verifica richiesta o una comunicazione sull'account. Autentica il chiamante e autorizza tenant, classe del messaggio, identità From visibile, destinatario e revisione del template. Scrivi un job di invio persistente con una chiave stabile dell'evento di business prima di aprire qualsiasi connessione SMTP. Questa chiave dovrebbe impedire che due worker creino in modo indipendente lo stesso messaggio logico. L'input del browser non deve poter scegliere host SMTP, porta, nome utente, mittente della busta, destinatari arbitrari, intestazioni o policy TLS. Mantieni questi valori in una configurazione server revisionata. Un worker della coda dovrebbe prendere in carico un job, ricontrollare soppressioni e autorizzazione al momento dell'invio, registrare ogni tentativo e rilasciare o finalizzare il job tramite stati espliciti. La libreria SMTP di Python trasporta il messaggio preparato; non fornisce autorizzazione dei tenant, consenso, idempotenza o policy di soppressione.
Costruisci il messaggio con EmailMessage
Usa email.message.EmailMessage invece di concatenare intestazioni e corpi grezzi. Imposta From, To, Subject, Date e un Message-ID generato secondo il modello approvato dall'applicazione, poi usa set_content per il testo e add_alternative per l'HTML quando serve. Valida gli oggetti indirizzo, limita il numero di destinatari e allegati, rifiuta l'iniezione di caratteri di nuova riga nei valori ed esegui l'escape dei dati del template per il contesto di output. Genera testo e HTML da un'unica revisione immutabile del template. Tieni segreti e dati personali non necessari fuori da oggetti, intestazioni personalizzate, nomi dei file, campi diagnostici e log. Separa in modo deliberato l'intestazione From visibile dal mittente della busta SMTP, perché autenticazione ed elaborazione dei bounce possono dipendere da identità diverse. Per l'audit, conserva una revisione del contenuto o un hash sicuro per la privacy invece di mantenere i corpi completi dei messaggi senza un'esigenza definita.
Scegli esplicitamente tra TLS implicito e STARTTLS
Python documenta SMTP_SSL per le connessioni cifrate fin dall'inizio e SMTP.starttls per eseguire l'upgrade di una connessione già stabilita. Segui l'hostname, la porta, il certificato e il contratto di submission attuali del provider invece di tirare a indovinare da un elenco generico di porte. Crea un contesto SSL predefinito verificato e non disattivare i controlli sul certificato o sull'hostname. Per STARTTLS, connettiti, invia EHLO se necessario, chiama starttls con il contesto e invia di nuovo EHLO, perché le estensioni annunciate possono cambiare dopo l'upgrade. Non inviare mai credenziali o contenuti dei messaggi dei clienti su una connessione in chiaro. L'RFC 8314 raccomanda la submission protetta da TLS e depreca l'accesso in chiaro. Tratta un errore di certificato, un hostname non corrispondente, l'assenza di uno STARTTLS richiesto o cambiamenti inattesi delle capacità come errori bloccanti da analizzare, invece di ripiegare silenziosamente.
Tieni le credenziali SMTP entro un confine ristretto per i segreti
Carica nome utente e password o token a runtime da un sistema di gestione dei segreti lato server. Non inserire credenziali in codice sorgente, bundle client, dump dell'ambiente, URL, stack trace delle eccezioni, analytics, notebook, screenshot, prompt o fixture committate. Limita ogni credenziale all'ambiente e al carico di lavoro più ristretti supportati dal provider, e separa lo sviluppo dalla produzione. Autenticati solo dopo aver stabilito lo stato TLS richiesto. Prova la rotazione con destinatari controllati: predisponi il sostituto tramite l'amministrazione approvata, aggiorna il worker, conferma l'autenticazione e un ciclo di vita completo degli eventi, poi revoca il vecchio valore. Errori di autenticazione ripetuti dovrebbero sospendere il percorso interessato invece di innescare un ciclo rapido di nuovi tentativi. Il metodo login di Python negozia tra i meccanismi annunciati dal server, ma il meccanismo effettivo del provider, la policy dell'account, i permessi dei token e il comportamento della rotazione richiedono prove aggiornate.
Usa una funzione di invio Python con limiti definiti
Mantieni piccolo l'adapter del provider e restituisci prove strutturate alla macchina a stati del job. Un flusso tipico crea un contesto SSL, apre SMTP_SSL(host, port, timeout=10) as smtp per il TLS implicito, chiama smtp.login(username, secret) e poi smtp.send_message(message, from_addr=envelope_from, to_addrs=recipients). Per un provider che richiede un upgrade esplicito, usa SMTP con un timeout, ehlo, starttls(context=context), ehlo e poi login. Non presentare hostname o porte di esempio come valori predefiniti universali. Passa un elenco di destinatari normalizzato invece di affidarti al parsing di intestazioni non attendibili. Registra la classe dell'eccezione, il codice di risposta SMTP e un testo diagnostico limitato quando disponibile, ma oscura indirizzi, credenziali e contenuto del messaggio. Misura separatamente le fasi di connessione, TLS, autenticazione, busta, dati e chiusura, così gli errori operativi restano diagnosticabili.
Interpreta con precisione i risultati per destinatario di send_message
Python documenta che sendmail e send_message terminano normalmente quando la posta viene accettata per almeno un destinatario e restituiscono un dizionario dei destinatari rifiutati; un dizionario vuoto significa che in quella fase nessun destinatario è stato rifiutato. Conserva questo risultato per destinatario invece di segnare l'intero job come consegnato. Se tutti i destinatari vengono rifiutati, la libreria solleva un'eccezione SMTPRecipientsRefused. Altre eccezioni distinguono rifiuto del mittente, rifiuto di DATA, errori di autenticazione, connessione, protocollo e simili. Associa le prove esatte agli stati dell'applicazione: accettato dal server di submission, rifiutato in modo permanente, rifiutato in modo transitorio o sconosciuto. Un ritorno normale dimostra solo l'esito della submission SMTP in quel perimetro. Non stabilisce l'accettazione da parte del server di destinazione, la collocazione finale nella casella, la lettura o l'engagement. Notifiche di stato della consegna successive o eventi del provider vanno correlati separatamente.
Ritenta solo quando il rischio di duplicati è sotto controllo
Classifica gli errori prima di pianificare un altro tentativo. Errori permanenti di indirizzo, mittente, autenticazione, policy o contenuto richiedono in genere una correzione o una soppressione, non una ripetizione automatica. Le risposte transitorie 4xx possono essere ritentate con backoff esponenziale, jitter, un tetto ai tentativi, una scadenza e un budget per destinazione. Un reset della connessione o un timeout dopo l'invio dei dati del messaggio può essere ambiguo: il server potrebbe aver accettato il messaggio mentre il client non ha ricevuto la risposta finale. Mantieni quel tentativo come sconosciuto, esamina l'attività del provider o gli eventi successivi tramite una correlazione sicura per la privacy ed evita un nuovo invio immediato alla cieca. SMTP non ha una chiave di idempotenza applicativa universale. La chiave persistente dell'evento di business impedisce tentativi concorrenti dell'applicazione, ma non può costringere un server SMTP remoto a deduplicare due submission accettate. Esegui l'escalation degli esiti ambigui ripetuti e conserva le prove esatte usate per la decisione.
Gestisci gli esiti parziali dei destinatari e le soppressioni
Quando un messaggio ha più destinatari, SMTP può accettarne alcuni e rifiutarne altri. Salva la risposta per ogni destinatario e fai avanzare allo stato successivo solo il sottoinsieme accettato. Non inviare di nuovo l'intero elenco originale solo perché un indirizzo ha ricevuto un rifiuto transitorio. Applica soppressioni per bounce permanenti, segnalazioni di spam, disiscrizioni, motivi legali, tenant e amministratori prima di ogni tentativo, compresi i nuovi tentativi. Separa le classi di messaggi solo tramite una policy esplicita e documentata; etichettare un messaggio come transazionale non annulla la sicurezza dei destinatari né le restrizioni del provider. Preferisci job con un solo destinatario per i flussi sensibili, quando privacy e stato individuale ne giustificano il costo. Evita di esporre gli elenchi di destinatari tramite To o Cc e non usare mai il comportamento di Bcc come sostituto dell'autorizzazione. Limita e oscura il testo diagnostico, perché le risposte SMTP possono contenere indirizzi dei destinatari o dettagli specifici del ricevente.
Testa i percorsi di errore con sistemi controllati
Testa costruzione del messaggio, Unicode, alternative testo e HTML, allegati, rifiuto delle intestazioni, normalizzazione dei destinatari, verifica TLS, STARTTLS mancante, credenziali non valide, rifiuto del mittente, rifiuto di uno o di tutti i destinatari, rifiuto di DATA, timeout prima e dopo una possibile accettazione, disconnessioni, risposte di limitazione della frequenza, scadenza dei nuovi tentativi, worker duplicati, modifiche alle soppressioni e rotazione dei segreti. Usa un servizio SMTP di test controllato o un finto server locale per test unitari e di integrazione deterministici; non instradare mai traffico accidentale degli ambienti non di produzione verso indirizzi dei clienti. Nei canary di produzione, usa destinatari autorizzati ed esamina le intestazioni grezze per From visibile, percorso della busta, Message-ID, DKIM, SPF, allineamento DMARC e prove del provider. Conferma che log e metriche non contengano credenziali né corpi dei messaggi. Blocca il lancio se il worker può aggirare l'autorizzazione dei tenant, degradare TLS, ritentare senza limiti o ignorare i rifiuti parziali, oppure se non è possibile sospendere il percorso di invio.
Come si inserisce SendHQ
SendHQ è un'API email con ambito limitato al workspace per comunicazioni di prodotto previste. La documentazione copre l'invio, i domini verificati, gli eventi di consegna e le soppressioni. Usa l'API HTTP documentata per integrare SendHQ con Python.
Domande frequenti
In Python conviene usare SMTP_SSL o STARTTLS?
Usa la modalità richiesta dall'attuale contratto di submission del provider. SMTP_SSL cifra fin dall'inizio della connessione; STARTTLS esegue un upgrade esplicito e richiede un TLS verificato più un nuovo EHLO.
Un ritorno normale di send_message dimostra la consegna?
No. Significa che almeno un destinatario è stato accettato in quella fase della submission SMTP. L'accettazione presso la destinazione, la collocazione nella casella e l'engagement richiedono prove successive e circoscritte.
Cosa significa il dizionario restituito da send_message?
Associa i destinatari rifiutati dal server SMTP alle relative risposte. Un dizionario vuoto significa che nessuno è stato rifiutato in quella fase, non che ogni messaggio sia arrivato in inbox.
Un timeout può essere ritentato subito?
Non in modo sicuro, se si è verificato dopo una possibile submission. Conserva il tentativo come ambiguo, riconcilia le prove del provider o degli eventi successivi e invia di nuovo solo secondo una policy che limiti il rischio di duplicati.
Dove va archiviata la password SMTP?
In un sistema di gestione dei segreti lato server, con accesso ristretto per carico di lavoro e ambiente, recupero sottoposto ad audit, rotazione testata e nessuna esposizione a client, log, prompt o fixture.
In produzione si può mai disattivare la verifica del certificato?
No. Un errore di certificato o di hostname è la prova di una configurazione non sicura o errata. Sospendi il percorso e diagnostica il problema invece di indebolire silenziosamente la verifica TLS.
Come va gestito il rifiuto parziale dei destinatari?
Salva il risultato di ogni destinatario, fai avanzare il sottoinsieme accettato e ritenta solo i rifiuti transitori idonei. Non inviare di nuovo ai destinatari già accettati insieme all'intero elenco originale.
Questa pagina dimostra che SendHQ supporta SMTP?
No. Questa guida copre Python SMTP in generale; usa la documentazione corrente di SendHQ per la sua API email.
Fonti
- smtplib: client per il protocollo SMTP — Python Software Foundation
- email.message: rappresentare un messaggio email — Python Software Foundation
- Esempi di email in Python — Python Software Foundation
- RFC 5321: Simple Mail Transfer Protocol (SMTP) — RFC Editor
- RFC 4954: SMTP Service Extension for Authentication — RFC Editor
- RFC 8314: Il testo in chiaro è considerato obsoleto: uso di Transport Layer Security (TLS) per submission e accesso email — RFC Editor