Come inviare e-mail a più destinatari utilizzando python smtplib?


196

Dopo molte ricerche non sono riuscito a scoprire come utilizzare smtplib.sendmail per inviare a più destinatari. Il problema era ogni volta che la posta veniva inviata, le intestazioni della posta sembravano contenere più indirizzi, ma in realtà solo il primo destinatario riceveva la posta.

Il problema sembra essere che il email.Messagemodulo si aspetta qualcosa di diverso dalla smtplib.sendmail()funzione.

In breve, per inviare a più destinatari è necessario impostare l'intestazione su una stringa di indirizzi e-mail delimitati da virgole. Il sendmail()parametro to_addrstuttavia dovrebbe essere un elenco di indirizzi e-mail.

from email.MIMEMultipart import MIMEMultipart
from email.MIMEText import MIMEText
import smtplib

msg = MIMEMultipart()
msg["Subject"] = "Example"
msg["From"] = "me@example.com"
msg["To"] = "malcom@example.com,reynolds@example.com,firefly@example.com"
msg["Cc"] = "serenity@example.com,inara@example.com"
body = MIMEText("example email body")
msg.attach(body)
smtp = smtplib.SMTP("mailhost.example.com", 25)
smtp.sendmail(msg["From"], msg["To"].split(",") + msg["Cc"].split(","), msg.as_string())
smtp.quit()

1
Sembra che OP abbia risposto alla sua stessa domanda: ha sendmailbisogno di un elenco.
Cees Timmerman,


Usando Python3 ho dovuto passare in rassegna i destinatari; for addr in recipients: msg['To'] = addre poi ha funzionato. Le assegnazioni multiple aggiungono effettivamente una nuova intestazione "A" per ognuna. Questa è un'interfaccia molto bizzarra, non riesco nemmeno a spiegare come ho pensato di provarlo. Stavo anche pensando di usare subprocessper chiamare il sendmailpacchetto unix per salvare la mia sanità mentale prima di capire questo.
mehtunguh

Risposte:


311

Questo funziona davvero , ho speso un sacco di tempo a cercare molteplici varianti.

import smtplib
from email.mime.text import MIMEText

s = smtplib.SMTP('smtp.uk.xensource.com')
s.set_debuglevel(1)
msg = MIMEText("""body""")
sender = 'me@example.com'
recipients = ['john.doe@example.com', 'john.smith@example.co.uk']
msg['Subject'] = "subject line"
msg['From'] = sender
msg['To'] = ", ".join(recipients)
s.sendmail(sender, recipients, msg.as_string())

3
la documentazione ha l'esempio:tolist =["one@one.org","two@two.org","three@three.org","four@four.org"]
chug2k,

2
grazie @sorin per questo script. Avevo un problema con l'invio di un'e-mail da uno script Python e con questo pezzo di codice, ora posso inviare l'e-mail.
fear_matrix,

5
Questo non verrà inviato a più destinatari se stai usando Python 3 di cui hai bisogno send_messageinvece sendmailche secondo il commento di Antoine di seguito e i documenti di Python docs.python.org/3/library/email-examples.html
cardamomo

Devi usare per ogni traversata che i destinatari per sendmail, altrimenti solo il primo elemento riceverà la posta.
Johnny,

2
correzione dell'URL di
David

150

La msg['To']deve essere una stringa:

msg['To'] = "a@b.com, b@b.com, c@b.com"

Mentre recipientsin sendmail(sender, recipients, message)deve essere un elenco:

sendmail("a@a.com", ["a@b.com", "b@b.com", "c@b.com"], "Howdy")

1
Questa è una strana decisione progettuale persmtplib.
Adam Matan,

2
recipientsnon deve essere un elenco: se viene fornita una stringa, viene trattata come un elenco con un elemento. La msg['To']stringa può essere semplicemente omessa.
Suzana,

Non capisco davvero come viene analizzato "a@a.com, b@b.com", quindi solo il primo indirizzo riceve l'e-mail. Ma grazie! Questa è la risposta, ho dovuto mettere la lista lì dentro.
antonavy,

ha funzionato per me ed è coerente con la documentazione in docs.python.org/2/library/email-examples.html
Rodrigo Laguna

43

Devi capire la differenza tra l' indirizzo visibile di un'e-mail e la consegna .

msg["To"]è essenzialmente ciò che è stampato sulla lettera. In realtà non ha alcun effetto. Tranne il fatto che il tuo client di posta elettronica, proprio come il normale funzionario delle poste, supporrà che è a questo che vuoi inviare l'e-mail.

La consegna effettiva tuttavia può funzionare in modo molto diverso. Quindi puoi rilasciare l'email (o una copia) nella casella postale di qualcuno completamente diverso.

Ci sono diverse ragioni per questo. Ad esempio l' inoltro . Il To:campo di intestazione non cambia durante l'inoltro, tuttavia l'e-mail viene rilasciata in un'altra cassetta postale.

Il smtp.sendmailcomando ora si occupa della consegna effettiva .email.Messageè solo il contenuto della lettera, non la consegna.

A basso livello SMTP, è necessario fornire i destinatari uno per uno, motivo per cui un elenco di indirizzi (esclusi i nomi!) È l'API sensibile.

Per l'intestazione, può anche contenere ad esempio il nome, ad es To: First Last <email@addr.tld>, Other User <other@mail.tld>. Il tuo esempio di codice quindi non è raccomandato , in quanto non riuscirà a consegnare questa posta, dal momento che semplicemente dividendola su di ,te non hai ancora gli indirizzi validi!


2
RFC 2822 impone una larghezza massima di 988 caratteri per una data intestazione e una larghezza consigliata di 78 caratteri. Dovrai assicurarti di "piegare" l'intestazione se hai troppi indirizzi.
Steve Hunt,

Questa dovrebbe essere la risposta accettata, poiché in realtà spiega il perché e il come.
Serrano,

Bella risposta. Che dire dei campi email CC e BCC? Presumo che dobbiamo anche includere e-mail CC e BCC in smtp.send. E solo l'elenco CC (e non l'elenco BCC) nei campi msg?
Tagar,

Sì, funziona così. I server di posta probabilmente abbandoneranno il campo Ccn (per evitare che ciò sia visibile e non penso che lo facciano tutti), ma non lo analizzeranno.
Ha QUIT - Anony-Mousse

19

Per me funziona.

import smtplib
from email.mime.text import MIMEText

s = smtplib.SMTP('smtp.uk.xensource.com')
s.set_debuglevel(1)
msg = MIMEText("""body""")
sender = 'me@example.com'
recipients = 'john.doe@example.com,john.smith@example.co.uk'
msg['Subject'] = "subject line"
msg['From'] = sender
msg['To'] = recipients
s.sendmail(sender, recipients.split(','), msg.as_string())

quale versione di Python stai usando? Ottengo lo stesso problema del poster originale e sto usando Python 2.7.9
Panofish

1
Perché non semplicemente recipients = ['john.doe@example.com','john.smith@example.co.uk']invece di renderlo una stringa e quindi dividerlo per creare un elenco?
WoJ,

a Woj, perché msg ['To'] dovrebbe essere una stringa e s.sendmail dovrebbe avere un elenco: (mittente, >>> ELENCO QUI <<<, msg.as_string ()). Ciò significa che, per quanto fastidioso, non puoi usare lo stesso tipo [stringa o elenco] per entrambi i campi
Pascal Louis-Marie,

Funziona come un incanto per me. Python 3.7.3.
Anadyn,

11

Ho provato il seguito e ha funzionato come un fascino :)

rec_list =  ['first@example.com', 'second@example.com']
rec =  ', '.join(rec_list)

msg['To'] = rec

send_out = smtplib.SMTP('localhost')
send_out.sendmail(me, rec_list, msg.as_string())

FYR codice intero semplice qui sotto: import smtplib from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText sender = 'myEmailAddress@example.com' rec_list = ['first@example.com', 'second@example.com'] rec = ', '.join(rec_list) msg = MIMEMultipart('alternative') msg['Subject'] = 'The required subject' msg['From'] = sender msg['To'] = rec html = ('whatever html code') htm_part = MIMEText(html, 'html') msg.attach(htm_part) send_out = smtplib.SMTP('localhost') send_out.sendmail(sender, rec_list, msg.as_string()) send_out.quit()
MasterMind

10

Quindi in realtà il problema è che SMTP.sendmail e email.MIMEText hanno bisogno di due cose diverse.

email.MIMEText imposta l'intestazione "A:" per il corpo dell'e-mail. Viene utilizzato SOLO per visualizzare un risultato all'essere umano all'altro capo e, come tutte le intestazioni di posta elettronica, deve essere una singola stringa. (Nota che in realtà non ha nulla a che fare con le persone che effettivamente ricevono il messaggio.)

SMTP.sendmail, d'altra parte, imposta la "busta" del messaggio per il protocollo SMTP. Ha bisogno di un elenco di stringhe Python, ognuna delle quali ha un singolo indirizzo.

Quindi, ciò che devi fare è COMBINARE le due risposte che hai ricevuto. Imposta msg ['To'] su una singola stringa, ma passa l'elenco non elaborato a sendmail:

emails = ['a.com','b.com', 'c.com']
msg['To'] = ', '.join( emails ) 
....
s.sendmail( msg['From'], emails, msg.as_string())

7

Mi è venuta in mente questa funzione modulo imponente. In questo esempio utilizza il server di posta elettronica Gmail. È suddiviso in intestazione e messaggio in modo da poter vedere chiaramente cosa sta succedendo:

import smtplib

def send_alert(subject=""):

    to = ['email@one.com', 'email2@another_email.com', 'a3rd@email.com']
    gmail_user = 'me@gmail.com'
    gmail_pwd = 'my_pass'
    smtpserver = smtplib.SMTP("smtp.gmail.com", 587)
    smtpserver.ehlo()
    smtpserver.starttls()
    smtpserver.ehlo
    smtpserver.login(gmail_user, gmail_pwd)
    header = 'To:' + ", ".join(to) + '\n' + 'From: ' + gmail_user + '\n' + 'Subject: ' + subject + '\n'
    msg = header + '\n' + subject + '\n\n'
    smtpserver.sendmail(gmail_user, to, msg)
    smtpserver.close()

7

L'ho capito qualche mese fa e ne ho parlato sul blog . Il riassunto è:

Se si desidera utilizzare smtplib per inviare e-mail a più destinatari, utilizzare email.Message.add_header('To', eachRecipientAsString)per aggiungerli, quindi quando si richiama il metodo sendmail, use email.Message.get_all('To')inviare il messaggio a tutti loro. Idem per i destinatari Cc e Ccn.


Python 3.7 genera un'eccezione con un messaggio: si è verificata un'eccezione : ValueError Potrebbero esserci al massimo 1 intestazioni in un messaggio
Wojciech Jakubas,

6

La soluzione di seguito ha funzionato per me. Invia correttamente un'e-mail a più destinatari, inclusi "CC" e "BCC".

toaddr = ['mailid_1','mailid_2']
cc = ['mailid_3','mailid_4']
bcc = ['mailid_5','mailid_6']
subject = 'Email from Python Code'
fromaddr = 'sender_mailid'
message = "\n  !! Hello... !!"

msg['From'] = fromaddr
msg['To'] = ', '.join(toaddr)
msg['Cc'] = ', '.join(cc)
msg['Bcc'] = ', '.join(bcc)
msg['Subject'] = subject

s.sendmail(fromaddr, (toaddr+cc+bcc) , message)

1
Questo funziona in parte, per nascondere davvero il BCC devi omettere la riga BCC bcc = ['mailid_5', 'mailid_6'] altrimenti questo mostrerà nell'intestazione che sconfigge lo scopo di bcc. Testato con Gmail e altri server di posta.
Wil

@Wil come implementeresti BCC in quel caso?
3pitt

4

Bene, il metodo in questo metodo di risposta non ha funzionato per me. Non lo so, forse questo è un problema di Python3 (sto usando la versione 3.4) o di Gmail, ma dopo alcuni tentativi, la soluzione che ha funzionato per me è stata la linea

s.send_message(msg)

invece di

s.sendmail(sender, recipients, msg.as_string())

4

Uso python 3.6 e il seguente codice funziona per me

email_send = 'xxxxx@xxx.xxx,xxxx@xxx.xxx'
server.sendmail(email_user,email_send.split(','),text)    

3
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText

def sender(recipients): 

    body = 'Your email content here'
    msg = MIMEMultipart()

    msg['Subject'] = 'Email Subject'
    msg['From'] = 'your.email@gmail.com'
    msg['To'] = (', ').join(recipients.split(','))

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

    server = smtplib.SMTP('smtp.gmail.com', 587)
    server.starttls()
    server.login('your.email@gmail.com', 'yourpassword')
    server.send_message(msg)
    server.quit()

if __name__ == '__main__':
    sender('email_1@domain.com,email_2@domain.com')

Ha funzionato solo per me con la funzione send_message e usando la funzione join nell'elenco con i destinatari, python 3.6.


0

puoi provare questo quando scrivi le e-mail del destinatario su un file di testo

from email.mime.text import MIMEText
from email.header import Header
import smtplib

f =  open('emails.txt', 'r').readlines()
for n in f:
     emails = n.rstrip()
server = smtplib.SMTP('smtp.uk.xensource.com')
server.ehlo()
server.starttls()
body = "Test Email"
subject = "Test"
from = "me@example.com"
to = emails
msg = MIMEText(body,'plain','utf-8')
msg['Subject'] = Header(subject, 'utf-8')
msg['From'] =  Header(from, 'utf-8')
msg['To'] = Header(to, 'utf-8')
text = msg.as_string()
try:
   server.send(from, emails, text)
   print('Message Sent Succesfully')
except:
   print('There Was An Error While Sending The Message')
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.