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"] = "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
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 = '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
Die Dokumentation hat das Beispiel:tolist =["one@one.org","two@two.org","three@three.org","four@four.org"]
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'] = "a@b.com, b@b.com, c@b.com"

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

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

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 'a@a.com, b@b.com' 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@addr.tld>, Other User <other@mail.tld>. 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!


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

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 = ['john.doe@example.com','john.smith@example.co.uk']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 =  ['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())

EJR ganz einfacher Code unten: 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

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

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

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.


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)

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

4

Ich benutze Python 3.6 und der folgende Code funktioniert für mich

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

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.


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 = "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')
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.