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"] = "[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()
pengguna1148320
sumber
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 = '[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
sumber
3
dokumentasi memang memiliki contoh:tolist =["[email protected]","[email protected]","[email protected]","[email protected]"]
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'] = "[email protected], [email protected], [email protected]"

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

sendmail("[email protected]", ["[email protected]", "[email protected]", "[email protected]"], "Howdy")
dvdhns
sumber
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 '[email protected], [email protected]' 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 protected]>, Other User <[email protected]>. 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!

Memiliki QUIT - Anony-Mousse
sumber
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 = '[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())
pria keren
sumber
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 = ['[email protected]','[email protected]']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 =  ['[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())
Dalang
sumber
FYR seluruh kode sederhana di bawah ini: 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

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())
SaiSandeep Golla
sumber
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 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
sumber
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.

James McPherson
sumber
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)
Omkar
sumber
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())
Antoine
sumber
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]')

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

Guilherme Henrique Mendes
sumber
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 = "[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
sumber