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"] = "[email protected]"
msg["To"] = "[email protected],[email protected],[email protected]"
msg["Cc"] = "[email protected],[email protected]"
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()
user1148320
la source
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 = '[email protected]'
recipients = ['[email protected]', '[email protected]']
msg['Subject'] = "subject line"
msg['From'] = sender
msg['To'] = ", ".join(recipients)
s.sendmail(sender, recipients, msg.as_string())
Sorin
la source
3
la documentation a l'exemple:tolist =["[email protected]","[email protected]","[email protected]","[email protected]"]
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'] = "[email protected], [email protected], [email protected]"

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

sendmail("[email protected]", ["[email protected]", "[email protected]", "[email protected]"], "Howdy")
dvdhns
la source
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 «[email protected], [email protected]» 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 protected]>, Other User <[email protected]>. 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!

A QUIT - Anony-Mousse
la source
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 = '[email protected]'
recipients = '[email protected],[email protected]'
msg['Subject'] = "subject line"
msg['From'] = sender
msg['To'] = recipients
s.sendmail(sender, recipients.split(','), msg.as_string())
Un gars sympa
la source
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 = ['[email protected]','[email protected]']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 =  ['[email protected]', '[email protected]']
rec =  ', '.join(rec_list)

msg['To'] = rec

send_out = smtplib.SMTP('localhost')
send_out.sendmail(me, rec_list, msg.as_string())
Cerveau
la source
FYR code simple entier ci-dessous: import smtplib from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText sender = '[email protected]' rec_list = ['[email protected]', '[email protected]'] 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())
SaiSandeep Golla
la source
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 protected]', 'email2@another_email.com', '[email protected]']
    gmail_user = '[email protected]'
    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()
radtek
la source
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.

James McPherson
la source
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)
Omkar
la source
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())
Antoine
la source
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'] = '[email protected]'
    msg['To'] = (', ').join(recipients.split(','))

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

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

if __name__ == '__main__':
    sender('[email protected],[email protected]')

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.

Guilherme Henrique Mendes
la source
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 = "[email protected]"
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')
Skiller Dz
la source