Wie sende ich mit python smtplib E-Mails an mehrere Empfänger?

196

Nach langem Suchen konnte ich nicht herausfinden, wie man mit smtplib.sendmail an mehrere Empfänger sendet. Das Problem war, dass jedes Mal, wenn die E-Mail gesendet wurde, die E-Mail-Header mehrere Adressen enthielten, aber tatsächlich nur der erste Empfänger die E-Mail erhielt.

Das Problem scheint zu sein, dass das email.MessageModul etwas anderes als die smtplib.sendmail()Funktion erwartet .

Kurz gesagt, um an mehrere Empfänger zu senden, sollten Sie den Header als eine Zeichenfolge von durch Kommas getrennten E-Mail-Adressen festlegen. Der sendmail()Parameter to_addrssollte jedoch eine Liste von E-Mail-Adressen sein.

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
quelle
1
Es scheint, dass OP seine eigene Frage beantwortet hat: sendmailbraucht eine Liste.
Cees Timmerman
Mit Python3 musste ich die Empfänger durchlaufen. for addr in recipients: msg['To'] = addrund dann hat es funktioniert. Bei mehreren Zuweisungen wird tatsächlich für jede ein neuer 'An'-Header angehängt. Dies ist eine sehr bizarre Oberfläche, ich kann nicht einmal erklären, wie ich dachte, es zu versuchen. Ich habe sogar darüber nachgedacht subprocess, das Unix- sendmailPaket aufzurufen , um meine geistige Gesundheit zu retten, bevor ich das herausgefunden habe.
Mehtunguh

Antworten:

309

Das funktioniert wirklich , ich habe viel Zeit damit verbracht, mehrere Varianten auszuprobieren.

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
quelle
3
Die Dokumentation hat das Beispiel:tolist =["[email protected]","[email protected]","[email protected]","[email protected]"]
chug2k
2
danke @sorin für dieses Skript. Ich hatte ein Problem beim Senden einer E-Mail von einem Python-Skript und mit diesem Code kann ich die E-Mail jetzt senden.
Angst_matrix
5
Dies wird nicht an mehrere Empfänger gesendet, wenn Sie Python 3 verwenden, das Sie send_messageanstelle von sendmailAntoines Kommentar unten und den Python-Dokumenten docs.python.org/3/library/email-examples.html
cardamom
Sie müssen für jede Durchquerung die Empfänger für sendmail verwenden, da sonst nur das erste Element die Mail empfängt.
Johnny
2
Korrektur der oben genannten URL: docs.python.org/3/library/email.examples.html
David
150

Das msg['To']muss eine Zeichenfolge sein:

msg['To'] = "[email protected], [email protected], [email protected]"

Während das recipientsin sendmail(sender, recipients, message)eine Liste sein muss:

sendmail("[email protected]", ["[email protected]", "[email protected]", "[email protected]"], "Howdy")
dvdhns
quelle
1
Dies ist eine seltsame Designentscheidung fürsmtplib.
Adam Matan
2
recipientsmuss keine Liste sein - wenn eine Zeichenfolge angegeben wird, wird sie als Liste mit einem Element behandelt. Die msg['To']Zeichenfolge kann einfach weggelassen werden.
Suzana
Ich verstehe nicht wirklich, wie '[email protected], [email protected]' analysiert wird, sodass nur die erste Adresse die E-Mail erhält. Aber danke! Dies ist die Antwort, musste dort Liste setzen.
Antonavy
hat für mich gearbeitet und stimmt mit der Dokumentation in docs.python.org/2/library/email-examples.html überein
Rodrigo Laguna
43

Sie müssen den Unterschied zwischen der sichtbaren Adresse einer E-Mail und der Zustellung verstehen .

msg["To"]ist im Wesentlichen das, was auf dem Brief gedruckt ist. Es hat eigentlich keine Wirkung. Abgesehen davon, dass Ihr E-Mail-Client genau wie der reguläre Postbeamte davon ausgeht, an wen Sie die E-Mail senden möchten.

Die tatsächliche Lieferung kann jedoch ganz anders funktionieren. So Sie können die E - Mail (oder eine Kopie) in den Briefkasten von jemand ganz anderes fallen.

Dafür gibt es verschiedene Gründe. Zum Beispiel Weiterleitung . Das To:Header-Feld ändert sich bei der Weiterleitung nicht, die E-Mail wird jedoch in einem anderen Postfach abgelegt.

Der smtp.sendmailBefehl kümmert sich nun um die eigentliche Lieferung. email.Messageist nur der Inhalt des Briefes, nicht die Lieferung.

In der unteren Ebene SMTPmüssen Sie die Empfänger einzeln angeben, weshalb eine Liste von Adressen (ohne Namen!) Die sinnvolle API ist.

Für den Header kann er beispielsweise auch den Namen enthalten, z To: First Last <[email protected]>, Other User <[email protected]>. Ihr Codebeispiel wird daher nicht empfohlen , da die Zustellung dieser E-Mail fehlschlägt, da Sie durch ,einfaches Aufteilen immer noch nicht über die gültigen Adressen verfügen!

Hat aufgehört - Anony-Mousse
quelle
2
RFC 2822 legt eine maximale Breite von 988 Zeichen für einen bestimmten Header und eine empfohlene Breite von 78 Zeichen fest. Sie müssen sicherstellen, dass Sie den Header "falten", wenn Sie zu viele Adressen haben.
Steve Hunt
Dies sollte die akzeptierte Antwort sein, da sie tatsächlich das Warum und das Wie erklärt.
Serrano
Gute Antwort. Was ist mit CC- und BCC-E-Mail-Feldern? Ich gehe davon aus, dass wir auch CC- und BCC-E-Mails in smtp.send aufnehmen müssen. Und nur CC-Liste (und nicht BCC-Liste) in den Nachrichtenfeldern?
Tagar
Ja, so funktioniert es. Mailserver werden wahrscheinlich das BCC-Feld löschen (um zu verhindern, dass dies sichtbar ist, und ich glaube nicht, dass dies alle tun), aber sie werden es nicht analysieren.
Hat aufgehört - Anony-Mousse
19

Für mich geht das.

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())
cooler Typ
quelle
Welche Python-Version verwenden Sie? Ich habe das gleiche Problem wie das Originalposter und verwende Python 2.7.9
Panofish
1
Warum nicht einfach, recipients = ['[email protected]','[email protected]']anstatt es zu einem String zu machen und es dann zu teilen, um eine Liste zu erstellen?
WoJ
an Woj, weil msg ['To'] eine Zeichenfolge sein sollte und s.sendmail eine Liste haben sollte: (Absender, >>> LISTE HIER <<<, msg.as_string ()). So ärgerlich es auch aussieht, Sie können nicht für beide Felder denselben Typ [Zeichenfolge oder Liste] verwenden
Pascal Louis-Marie
Funktioniert wie ein Zauber für mich. Python 3.7.3.
Anadyn
11

Ich habe das unten versucht und es hat wie ein Zauber funktioniert :)

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())
MasterMind
quelle
EJR ganz einfacher Code unten: 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

Das eigentliche Problem ist also, dass SMTP.sendmail und email.MIMEText zwei verschiedene Dinge benötigen.

email.MIMEText richtet den Header "An:" für den Text der E-Mail ein. Es wird NUR verwendet, um dem Menschen am anderen Ende ein Ergebnis anzuzeigen, und muss wie alle E-Mail-Header eine einzelne Zeichenfolge sein. (Beachten Sie, dass es eigentlich nichts mit den Personen zu tun haben muss, die die Nachricht tatsächlich erhalten.)

SMTP.sendmail hingegen richtet den "Umschlag" der Nachricht für das SMTP-Protokoll ein. Es benötigt eine Python-Liste von Zeichenfolgen, von denen jede eine einzelne Adresse hat.

Sie müssen also die beiden erhaltenen Antworten KOMBINIEREN. Setzen Sie msg ['To'] auf eine einzelne Zeichenfolge, übergeben Sie die Rohliste jedoch an sendmail:

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

Ich habe mir diese importierbare Modulfunktion ausgedacht. In diesem Beispiel wird der Google Mail-E-Mail-Server verwendet. Es ist in Header und Nachricht unterteilt, sodass Sie klar sehen können, was los ist:

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
quelle
7

Ich habe das vor ein paar Monaten herausgefunden und darüber gebloggt . Die Zusammenfassung lautet:

Wenn Sie smtplib verwenden möchten, um E-Mails an mehrere Empfänger zu senden email.Message.add_header('To', eachRecipientAsString), fügen Sie diese hinzu. Wenn Sie dann die sendmail-Methode aufrufen, use email.Message.get_all('To')senden Sie die Nachricht an alle. Das Gleiche gilt für Cc- und Bcc-Empfänger.

James McPherson
quelle
Python 3.7 löst eine Ausnahme mit Nachricht aus: Ausnahme ist aufgetreten: ValueError Es kann höchstens 1 To-Header in einer Nachricht geben
Wojciech Jakubas
6

Die folgende Lösung hat bei mir funktioniert. Es wird erfolgreich eine E-Mail an mehrere Empfänger gesendet, einschließlich "CC" und "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
quelle
1
Dies funktioniert teilweise. Um das BCC wirklich auszublenden, müssen Sie die BCC-Zeile bcc = ['mailid_5', 'mailid_6'] weglassen. Andernfalls wird dies in der Kopfzeile angezeigt, die den Zweck von bcc zunichte macht. Getestet mit Google Mail und anderen Mailservern.
Wil
@Wil wie würden Sie BCC in diesem Fall implementieren?
3pitt
4

Nun, die Methode in dieser Antwortmethode hat bei mir nicht funktioniert. Ich weiß nicht, vielleicht ist dies ein Python3- (ich verwende die 3.4-Version) oder ein Google Mail-Problem, aber nach einigen Versuchen war die Lösung, die für mich funktioniert hat, die Leitung

s.send_message(msg)

anstatt

s.sendmail(sender, recipients, msg.as_string())
Antoine
quelle
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]')

Es funktionierte nur bei mir mit der Funktion send_message und der Verwendung der Join-Funktion in der Liste mit Empfängern, Python 3.6.

Guilherme Henrique Mendes
quelle
0

Sie können dies versuchen, wenn Sie die Empfänger-E-Mails in eine Textdatei schreiben

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
quelle