Bagaimana cara mengirim email ke banyak penerima menggunakan python smtplib?


196

Setelah banyak pencarian, saya tidak dapat menemukan cara menggunakan smtplib.sendmail untuk mengirim ke banyak penerima. Masalahnya adalah setiap kali surat dikirimkan, tajuk surat tampaknya berisi banyak alamat, tetapi kenyataannya hanya penerima pertama yang akan menerima email.

Masalahnya tampaknya bahwa email.Messagemodul mengharapkan sesuatu yang berbeda dari smtplib.sendmail()fungsinya.

Singkatnya, untuk mengirim ke banyak penerima, Anda harus mengatur tajuk menjadi serangkaian alamat email yang dibatasi koma. The sendmail()parameter to_addrsnamun harus daftar alamat email.

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
Tampaknya OP menjawab pertanyaannya sendiri: sendmailperlu daftar.
Cees Timmerman


Menggunakan Python3 saya harus mengulangi penerima; for addr in recipients: msg['To'] = addrdan kemudian berhasil. Banyak tugas sebenarnya menambahkan header 'To' baru untuk masing-masing. Ini adalah antarmuka yang sangat aneh, saya bahkan tidak bisa menjelaskan bagaimana saya berpikir untuk mencobanya. Saya bahkan mempertimbangkan subprocessuntuk menggunakan memanggil sendmailpaket unix untuk menyelamatkan kewarasan saya sebelum saya menemukan ini.
mehtunguh

Jawaban:


311

Ini benar-benar berfungsi , saya menghabiskan banyak waktu untuk mencoba berbagai varian.

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
dokumentasi memang memiliki contoh:tolist =["one@one.org","two@two.org","three@three.org","four@four.org"]
chug2k

2
terima kasih @sorin untuk skrip ini. Saya mengalami masalah untuk mengirim email dari skrip python dan dengan potongan kode ini, saya sekarang dapat mengirim email.
fear_matrix

5
Ini tidak akan dikirim ke beberapa penerima jika Anda menggunakan Python 3 yang Anda butuhkan send_messagealih-alih sendmailsesuai komentar Antoine di bawah ini dan dokumen Python docs.python.org/3/library/email-examples.html
cardamom

Anda harus menggunakan untuk setiap lintasan yang penerima untuk sendmail, jika tidak hanya elemen pertama yang akan menerima email.
Johnny

2
koreksi ke url yang disebutkan di atas: docs.python.org/3/library/email.examples.html
David

150

The msg['To']perlu string:

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

Sementara recipientsin sendmail(sender, recipients, message)perlu daftar:

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

1
Ini adalah satu keputusan desain yang aneh untuksmtplib.
Adam Matan

2
recipientstidak harus menjadi daftar - jika string diberikan, itu diperlakukan sebagai daftar dengan satu elemen. The msg['To']String hanya dapat dihilangkan.
Suzana

Saya tidak begitu mengerti, bagaimana 'a@a.com, b@b.com' diurai sehingga hanya alamat pertama yang mendapat email. Tapi terima kasih! Ini jawabannya, harus letakkan daftarnya di sana.
antonavy

bekerja untuk saya, dan ini konsisten dengan dokumentasi di docs.python.org/2/library/email-examples.html
Rodrigo Laguna

43

Anda perlu memahami perbedaan antara yang terlihat alamat email, dan pengiriman .

msg["To"]pada dasarnya adalah apa yang dicetak pada surat itu. Sebenarnya tidak memiliki efek apa pun. Kecuali bahwa klien surel Anda, sama seperti petugas pos biasa, akan menganggap bahwa ini yang ingin Anda kirimi surel.

Namun pengiriman yang sebenarnya dapat bekerja sangat berbeda. Jadi, Anda dapat memasukkan email (atau salinan) ke kotak pos seseorang yang sama sekali berbeda.

Ada berbagai alasan untuk ini. Misalnya penerusan . Bidang To:tajuk tidak berubah saat penerusan, namun surel dijatuhkan ke kotak surat lain.

The smtp.sendmailperintah sekarang mengurus sebenarnya pengiriman. email.Messageadalah isi surat saja, bukan pengiriman.

Pada level rendah SMTP, Anda perlu memberikan penerima satu-per-satu, itulah sebabnya daftar alamat (tidak termasuk nama!) Adalah API yang masuk akal.

Untuk tajuk, dapat juga berisi misalnya nama, misalnya To: First Last <email@addr.tld>, Other User <other@mail.tld>. Karena itu contoh kode Anda tidak disarankan , karena akan gagal mengirimkan email ini, karena hanya dengan membaginya pada ,Anda masih belum memiliki alamat yang valid!


2
RFC 2822 memaksakan lebar maksimum 988 karakter untuk header yang diberikan dan lebar yang disarankan 78 karakter. Anda perlu memastikan Anda "melipat" header jika Anda memiliki terlalu banyak alamat.
Steve Hunt

Ini harus menjadi jawaban yang diterima, karena ini menjelaskan mengapa dan bagaimana.
Serrano

Jawaban yang bagus Bagaimana dengan bidang email CC dan BCC? Saya berasumsi kita juga harus memasukkan email CC dan BCC di smtp.send. Dan hanya daftar CC (dan bukan daftar BCC) di kolom msg?
Tagar

Ya, begitulah cara kerjanya. Server e-mail kemungkinan akan menjatuhkan bidang BCC (untuk mencegah agar tidak terlihat, dan saya pikir mereka tidak melakukannya), tetapi mereka tidak akan menguraikannya.
Memiliki QUIT - Anony-Mousse

19

Ini bekerja untuk saya.

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

versi python apa yang Anda gunakan? Saya mendapatkan masalah yang sama dengan poster aslinya dan saya menggunakan python 2.7.9
panofish

1
Mengapa tidak sekadar recipients = ['john.doe@example.com','john.smith@example.co.uk']membuatnya menjadi string, lalu membaginya menjadi daftar?
WoJ

ke Woj, karena msg ['To'] harus berupa string dan s.sendmail harus memiliki daftar: (pengirim, >>> DAFTAR DI SINI <<<, msg.as_string ()). Itu artinya, sama menjengkelkannya dengan yang terlihat, bahwa Anda tidak dapat menggunakan satu tipe [string atau daftar] yang sama untuk kedua bidang
Pascal Louis-Marie

Bekerja seperti pesona bagi saya. Python 3.7.3.
Anadyn

11

Saya mencoba di bawah ini dan bekerja seperti pesona :)

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 seluruh kode sederhana di bawah ini: 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

Jadi sebenarnya masalahnya adalah SMTP.sendmail dan email. SIMET membutuhkan dua hal yang berbeda.

email.MIMEText mengatur tajuk "Ke:" untuk isi email. Ini HANYA digunakan untuk menampilkan hasil kepada manusia di ujung lainnya, dan seperti semua header email, harus berupa string tunggal. (Perhatikan bahwa itu sebenarnya tidak ada hubungannya dengan orang yang benar-benar menerima pesan.)

SMTP.sendmail, di sisi lain, mengatur "amplop" pesan untuk protokol SMTP. Perlu daftar string Python, yang masing-masing memiliki satu alamat.

Jadi, yang perlu Anda lakukan adalah menggabungkan dua balasan yang Anda terima. Atur msg ['Ke'] menjadi satu string, tetapi berikan daftar mentah ke sendmail:

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

7

Saya datang dengan fungsi modul yang dapat diimpor ini. Ini menggunakan server email gmail dalam contoh ini. Ini dibagi menjadi header dan pesan sehingga Anda dapat dengan jelas melihat apa yang terjadi:

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

Saya menemukan ini beberapa bulan yang lalu dan membuat blog tentang hal itu . Ringkasannya adalah:

Jika Anda ingin menggunakan smtplib untuk mengirim email ke banyak penerima, gunakan email.Message.add_header('To', eachRecipientAsString)untuk menambahkannya, dan kemudian ketika Anda memanggil metode sendmail, use email.Message.get_all('To')kirim pesan ke semuanya. Ditto untuk penerima Cc dan Bcc.


Python 3.7 melempar pengecualian dengan pesan: Pengecualian telah terjadi: ValueError Mungkin ada paling banyak 1 Untuk tajuk pesan
Wojciech Jakubas

6

Solusi di bawah ini berhasil untuk saya. Itu berhasil mengirim email ke beberapa penerima, termasuk "CC" dan "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
Ini berfungsi sebagian, untuk benar-benar menyembunyikan BCC Anda harus menghilangkan baris BCC bcc = ['mailid_5', 'mailid_6'] jika tidak, ini akan ditampilkan di header mengalahkan tujuan bcc. Diuji dengan gmail dan server surat lainnya.
Wil

@Apakah Anda akan menerapkan BCC dalam kasus itu?
3pitt

4

Nah, metode dalam metode asnwer ini tidak berhasil untuk saya. Saya tidak tahu, mungkin ini adalah Python3 (saya menggunakan versi 3.4) atau masalah terkait gmail, tetapi setelah beberapa kali mencoba, solusi yang bekerja untuk saya, adalah garis

s.send_message(msg)

dari pada

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

4

Saya menggunakan python 3.6 dan kode berikut ini berfungsi untuk saya

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

Ini hanya bekerja untuk saya dengan fungsi send_message dan menggunakan fungsi gabung dalam daftar dengan penerima, python 3.6.


0

Anda dapat mencoba ini ketika Anda menulis email penerima pada file teks

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')
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.