Comment envoyer un e-mail à plusieurs destinataires en utilisant python smtplib?


196

Après de nombreuses recherches, je n'ai pas pu trouver comment utiliser smtplib.sendmail pour envoyer à plusieurs destinataires. Le problème était qu'à chaque fois que le courrier était envoyé, les en-têtes du courrier semblaient contenir plusieurs adresses, mais en fait, seul le premier destinataire recevrait le courrier électronique.

Le problème semble être que le email.Messagemodule attend quelque chose de différent de la smtplib.sendmail()fonction.

En bref, pour envoyer à plusieurs destinataires, vous devez définir l'en-tête comme une chaîne d'adresses électroniques séparées par des virgules. Le sendmail()paramètre to_addrsdoit cependant être une liste d'adresses 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
Il semble qu'OP ait répondu à sa propre question: a sendmailbesoin d'une liste.
Cees Timmerman


En utilisant Python3, j'ai dû parcourir les destinataires; for addr in recipients: msg['To'] = addret puis ça a marché. Plusieurs affectations ajoutent en fait un nouvel en-tête «À» pour chacune. C'est une interface très bizarre, je ne peux même pas expliquer comment j'ai pensé l'essayer. J'envisageais même d'utiliser subprocessle sendmailpaquet Unix pour sauver ma raison avant de comprendre cela.
mehtunguh

Réponses:


311

Cela fonctionne vraiment , j'ai passé beaucoup de temps à essayer plusieurs variantes.

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 documentation a l'exemple:tolist =["one@one.org","two@two.org","three@three.org","four@four.org"]
chug2k

2
merci @sorin pour ce script. J'avais un problème pour envoyer un e-mail à partir d'un script python et avec ce morceau de code, je peux maintenant envoyer l'e-mail.
fear_matrix

5
Cela ne sera pas envoyé à plusieurs destinataires si vous utilisez Python 3 dont vous avez besoin send_messageau lieu de sendmailselon le commentaire d'Antoine ci-dessous et les documents Python docs.python.org/3/library/email-examples.html
cardamom

Vous devez utiliser pour chaque cheminement les destinataires de sendmail, sinon seul le premier élément recevra le courrier.
Johnny

2
correction de l'url mentionnée ci-dessus: docs.python.org/3/library/email.examples.html
David

150

Le msg['To']doit être une chaîne:

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

Alors que le recipientsin sendmail(sender, recipients, message)doit être une liste:

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

1
Ceci est une décision de conception étrange poursmtplib.
Adam Matan

2
recipientsne doit pas être une liste - si une chaîne est donnée, elle est traitée comme une liste avec un élément. La msg['To']chaîne peut simplement être omise.
Suzana

Je ne comprends pas vraiment comment «a@a.com, b@b.com» est analysé, donc seule la première adresse reçoit l'e-mail. Mais merci! Telle est la réponse, a dû mettre la liste là-dedans.
antonavy

a fonctionné pour moi, et il est cohérent avec la documentation dans docs.python.org/2/library/email-examples.html
Rodrigo Laguna

43

Vous devez comprendre la différence entre l' adresse visible d'un e-mail et la livraison .

msg["To"]est essentiellement ce qui est imprimé sur la lettre. Cela n'a en fait aucun effet. Sauf que votre client de messagerie, tout comme l'agent de poste ordinaire, supposera que c'est à qui vous souhaitez envoyer l'e-mail.

La livraison réelle peut cependant fonctionner très différemment. Vous pouvez donc déposer l'e-mail (ou une copie) dans la boîte aux lettres de quelqu'un de complètement différent.

Il y a plusieurs raisons à cela. Par exemple, le transfert . Le To:champ d'en-tête ne change pas lors du transfert, mais l'e-mail est déposé dans une autre boîte aux lettres.

La smtp.sendmailcommande s'occupe maintenant de la livraison réelle . email.Messageest le contenu de la lettre uniquement, pas la livraison.

En bas niveau SMTP, vous devez donner les destinataires un par un, c'est pourquoi une liste d'adresses (sans inclure les noms!) Est l'API sensée.

Pour l'en-tête, il peut également contenir par exemple le nom, par exemple To: First Last <email@addr.tld>, Other User <other@mail.tld>. Votre exemple de code n'est donc pas recommandé , car il ne parviendra pas à livrer ce courrier, car juste en le divisant sur ,vous n'avez toujours pas les adresses valides!


2
La RFC 2822 impose une largeur maximale de 988 caractères pour un en-tête donné et une largeur recommandée de 78 caractères. Vous devrez vous assurer de "plier" l'en-tête si vous avez trop d'adresses.
Steve Hunt

Cela devrait être la réponse acceptée, car elle explique en fait le pourquoi et le comment.
Serrano

Très bonne réponse. Qu'en est-il des champs de messagerie CC et BCC? Je suppose que nous devons également inclure les e-mails CC et BCC dans smtp.send. Et seulement la liste CC (et non la liste BCC) dans les champs msg?
Tagar

Oui, c'est comme ça que ça marche. Les serveurs de messagerie supprimeront probablement le champ BCC (pour éviter que cela ne soit visible, et je ne pense pas qu'ils le fassent tous), mais ils ne le analyseront pas.
A QUIT - Anony-Mousse

19

Ça marche pour moi.

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())

quelle version de python utilisez-vous? J'ai le même problème que l'affiche originale et j'utilise python 2.7.9
panofish

1
Pourquoi ne pas simplement en recipients = ['john.doe@example.com','john.smith@example.co.uk']faire une chaîne, puis la diviser pour en faire une liste?
WoJ

à Woj, car msg ['To'] doit être une chaîne et s.sendmail doit avoir une liste: (expéditeur, >>> LISTE ICI <<<, msg.as_string ()). Cela signifie, aussi ennuyeux que cela puisse paraître, que vous ne pouvez pas utiliser un même type [chaîne ou liste] pour les deux champs
Pascal Louis-Marie

Fonctionne comme un charme pour moi. Python 3.7.3.
Anadyn

11

J'ai essayé ci-dessous et cela a fonctionné comme un charme :)

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 code simple entier ci-dessous: 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

Donc, en réalité, le problème est que SMTP.sendmail et email.MIMEText ont besoin de deux choses différentes.

email.MIMEText configure l'en-tête "To:" pour le corps de l'e-mail. Il est UNIQUEMENT utilisé pour afficher un résultat à l'être humain à l'autre extrémité, et comme tous les en-têtes de courrier électronique, il doit être une seule chaîne. (Notez que cela n'a rien à voir avec les personnes qui reçoivent réellement le message.)

SMTP.sendmail, d'autre part, définit "l'enveloppe" du message pour le protocole SMTP. Il a besoin d'une liste Python de chaînes, chacune ayant une seule adresse.

Donc, ce que vous devez faire, c'est COMBINER les deux réponses que vous avez reçues. Définissez msg ['To'] sur une seule chaîne, mais passez la liste brute à sendmail:

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

7

Je suis venu avec cette fonction de module importable. Il utilise le serveur de messagerie gmail dans cet exemple. Il est divisé en en-tête et message afin que vous puissiez voir clairement ce qui se passe:

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

J'ai compris cela il y a quelques mois et j'ai blogué à ce sujet . Le résumé est:

Si vous souhaitez utiliser smtplib pour envoyer des e-mails à plusieurs destinataires, utilisez email.Message.add_header('To', eachRecipientAsString)pour les ajouter, puis lorsque vous appelez la méthode sendmail, use email.Message.get_all('To')envoyez le message à chacun d'eux. Idem pour les destinataires Cc et Cci.


Python 3.7 lève une exception avec un message: Une exception s'est produite: ValueError Il peut y avoir au plus 1 En-têtes dans un message
Wojciech Jakubas

6

La solution ci-dessous a fonctionné pour moi. Il envoie avec succès un e-mail à plusieurs destinataires, y compris «CC» et «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
Cela fonctionne en partie, pour masquer vraiment le BCC, vous devez omettre la ligne BCC bcc = ['mailid_5', 'mailid_6'] sinon cela apparaîtra dans l'en-tête en défaisant le but de bcc. Testé avec gmail et autre serveur de messagerie.
Wil

@ Comment allez-vous implémenter BCC dans ce cas?
3pitt

4

Eh bien, la méthode de cette méthode de réponse n'a pas fonctionné pour moi. Je ne sais pas, c'est peut-être un problème lié à Python3 (j'utilise la version 3.4) ou à gmail, mais après quelques essais, la solution qui a fonctionné pour moi, était la ligne

s.send_message(msg)

au lieu de

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

4

J'utilise python 3.6 et le code suivant fonctionne pour moi

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')

Cela ne fonctionnait que pour moi avec la fonction send_message et en utilisant la fonction join dans la liste avec les destinataires, python 3.6.


0

vous pouvez essayer cela lorsque vous écrivez les e-mails appropriés sur un fichier texte

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')
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.