วิธีการส่งอีเมลไปยังผู้รับหลายคนโดยใช้ python smtplib?


198

หลังจากค้นหามากฉันไม่สามารถหาวิธีใช้ smtplib.sendmail เพื่อส่งไปยังผู้รับหลายคน ปัญหาคือทุกครั้งที่มีการส่งจดหมายส่วนหัวจดหมายจะมีที่อยู่หลายแห่ง แต่ในความเป็นจริงผู้รับเพียงรายแรกเท่านั้นที่จะได้รับอีเมล

ปัญหาน่าจะเป็นที่email.Messageโมดูลคาดว่าสิ่งที่แตกต่างจากsmtplib.sendmail()ฟังก์ชั่น

ในระยะสั้นหากต้องการส่งไปยังผู้รับหลายคนคุณควรตั้งส่วนหัวให้เป็นสตริงของที่อยู่อีเมลคั่นด้วยเครื่องหมายจุลภาค sendmail()พารามิเตอร์to_addrsแต่ควรจะเป็นรายชื่อที่อยู่อีเมล

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
ดูเหมือนว่า OP จะตอบคำถามของเขาเอง: sendmailต้องการรายการ
Cees Timmerman


การใช้ Python3 ฉันต้องวนซ้ำผู้รับ for addr in recipients: msg['To'] = addrแล้วมันก็ใช้งานได้ การมอบหมายหลายรายการจะเพิ่มส่วนหัว 'ถึง' ใหม่สำหรับแต่ละรายการ นี่เป็นอินเทอร์เฟซที่แปลกประหลาดมากฉันไม่สามารถอธิบายได้ว่าฉันจะลองทำยังไง ฉันยังคิดsubprocessจะใช้โทรหายูนิกซ์sendmailแพ็คเกจเพื่อรักษาสติก่อนที่จะคิดออก
mehtunguh

คำตอบ:


313

มันใช้งานได้จริงฉันใช้เวลาหลายครั้งในการลองหลายรูปแบบ

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
เอกสารประกอบมีตัวอย่าง:tolist =["one@one.org","two@two.org","three@three.org","four@four.org"]
chug2k

2
ขอบคุณ @sorin สำหรับสคริปต์นี้ ฉันมีปัญหาในการส่งอีเมลจากสคริปต์ไพ ธ อนและด้วยรหัสชิ้นนี้ฉันสามารถส่งอีเมลได้ตอนนี้
fear_matrix

5
นี้จะไม่ส่งไปยังผู้รับหลายถ้าคุณกำลังใช้งูหลาม 3 คุณต้องsend_messageแทนการsendmailตามความคิดเห็นของแอนทอนด้านล่างและเอกสารหลามdocs.python.org/3/library/email-examples.html
กระวาน

คุณต้องใช้สำหรับการสำรวจแต่ละครั้งที่ผู้รับสำหรับ sendmail มิฉะนั้นเฉพาะองค์ประกอบแรกเท่านั้นที่จะได้รับอีเมล
จอห์นนี่

2
การแก้ไข URL ที่กล่าวถึงข้างต้น: docs.python.org/3/library/email.examples.html
David

151

msg['To']ความต้องการที่จะเป็นสตริง:

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

ในขณะที่recipientsในsendmail(sender, recipients, message)จะต้องมีรายการ:

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

1
นี่เป็นการตัดสินใจออกแบบที่แปลกอย่างหนึ่งสำหรับsmtplib.
Adam Matan

2
recipientsไม่จำเป็นต้องเป็นรายการ - หากมีการกำหนดสตริงจะถือว่าเป็นรายการที่มีองค์ประกอบเดียว msg['To']สตริงก็สามารถจะมองข้าม
Suzana

ฉันไม่เข้าใจจริงๆว่า 'a@a.com, b@b.com' มีการแยกวิเคราะห์อย่างไรเพื่อให้ที่อยู่แรกเท่านั้นที่ได้รับอีเมล แต่ขอบคุณ! นี่คือคำตอบต้องใส่รายการในนั้น
antonavy

ทำงานสำหรับฉันและสอดคล้องกับเอกสารในdocs.python.org/2/library/email-examples.html
Rodrigo Laguna

44

คุณจำเป็นต้องเข้าใจความแตกต่างระหว่างที่มองเห็นอยู่ของอีเมลและการส่งมอบ

msg["To"]เป็นหลักสิ่งที่พิมพ์บนตัวอักษร มันไม่มีผลอะไรเลย ยกเว้นไคลเอนต์อีเมลของคุณเช่นเดียวกับเจ้าหน้าที่โพสต์ทั่วไปจะถือว่านี่คือคนที่คุณต้องการส่งอีเมลถึง

การส่งมอบจริง แต่สามารถทำงานได้ค่อนข้างแตกต่างกัน ดังนั้นคุณสามารถวางอีเมล (หรือสำเนา) ลงในกล่องโพสต์ของใครบางคนที่แตกต่างกันโดยสิ้นเชิง

มีเหตุผลหลายประการสำหรับเรื่องนี้ ยกตัวอย่างเช่นการส่งต่อ To:ข้อมูลส่วนหัวไม่เปลี่ยนแปลงในการส่งต่อ แต่อีเมลที่ถูกลดลงในกล่องจดหมายที่แตกต่างกัน

smtp.sendmailคำสั่งตอนนี้ใช้เวลาในการดูแลของจริงจัดส่ง email.Messageเป็นเนื้อหาของตัวอักษรเท่านั้นไม่ใช่การส่งมอบ

ในระดับต่ำSMTPคุณจะต้องให้ผู้รับแบบหนึ่งต่อหนึ่งซึ่งเป็นสาเหตุที่รายการของที่อยู่ (ไม่รวมถึงชื่อ!) คือ API ที่สมเหตุสมผล

To: First Last <email@addr.tld>, Other User <other@mail.tld>สำหรับส่วนหัวก็ยังสามารถมีตัวอย่างเช่นชื่อเช่น ดังนั้นจึงไม่แนะนำให้ใช้ตัวอย่างรหัสของคุณเนื่องจากจะทำให้การส่งเมลนี้ล้มเหลวเนื่องจากเพียงแยกโดยที่,คุณยังคงไม่มีที่อยู่ที่ถูกต้อง!


2
RFC 2822 กำหนดความกว้างสูงสุด 988 อักขระสำหรับส่วนหัวที่กำหนดและความกว้างที่แนะนำคือ 78 อักขระ คุณจะต้องให้แน่ใจว่าคุณ "พับ" ส่วนหัวหากคุณมีที่อยู่มากเกินไป
Steve Hunt

นี่ควรเป็นคำตอบที่ได้รับการยอมรับเนื่องจากอธิบายถึงสาเหตุและวิธีการได้อย่างแท้จริง
Serrano

คำตอบที่ดี แล้วฟิลด์อีเมล CC และ BCC ล่ะ ฉันคิดว่าเราต้องรวมอีเมล CC และ BCC ใน smtp.send และมีเพียงรายการ CC (และไม่ใช่รายการ BCC) ในฟิลด์ข้อความหรือไม่
Tagar

ใช่นั่นคือวิธีการทำงาน เซิร์ฟเวอร์อีเมลมีแนวโน้มที่จะลดลงในช่อง BCC (เพื่อป้องกันไม่ให้มองเห็นได้และฉันไม่คิดว่าพวกเขาทำ) แต่พวกเขาจะไม่แยกมัน
เลิกเล่น - Anony-Mousse

19

มันใช้งานได้สำหรับฉัน

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

คุณใช้ไพ ธ อนรุ่นใด ฉันได้รับปัญหาเช่นเดียวกับโปสเตอร์ดั้งเดิมและฉันใช้ python 2.7.9
panofish

1
ทำไมไม่เพียงrecipients = ['john.doe@example.com','john.smith@example.co.uk']สร้างสตริงแล้วแยกเป็นรายการ?
WoJ

ถึง Woj เนื่องจาก msg ['ถึง'] ควรเป็นสตริงและ s.sendmail ควรมีรายการ: (ผู้ส่ง >>> รายการที่นี่ <<<, msg.as_string () นั่นหมายความว่าน่ารำคาญอย่างที่คุณไม่สามารถใช้ [สตริงหรือรายการ] ประเภทเดียวกันสำหรับทั้งสองฟิลด์
Pascal Louis-Marie

ทำงานเหมือนจับใจสำหรับฉัน Python 3.7.3
Anadyn

11

ฉันลองด้านล่างและใช้งานได้อย่างมีเสน่ห์ :)

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 ด้านล่าง: 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

ดังนั้นจริงๆแล้วปัญหาคือว่า SMTP.sendmail และ email.MIMEText ต้องการสองสิ่งที่แตกต่างกัน

email.MIMEText ตั้งค่าส่วนหัว "ถึง:" สำหรับเนื้อความของอีเมล มันจะใช้สำหรับการแสดงผลให้กับมนุษย์ที่ปลายอีกด้านและเช่นเดียวกับส่วนหัวของอีเมลทั้งหมดจะต้องเป็นสตริงเดียว (โปรดทราบว่าไม่จำเป็นต้องทำอะไรกับคนที่ได้รับข้อความจริงๆ)

SMTP.sendmail ตั้งค่า "ซองจดหมาย" ของข้อความสำหรับโปรโตคอล SMTP มันต้องการรายการสตริงของหลามซึ่งแต่ละอันมีที่อยู่เดียว

ดังนั้นสิ่งที่คุณต้องทำคือรวมคำตอบทั้งสองที่คุณได้รับ ตั้งค่า msg ['ถึง'] เป็นสตริงเดี่ยว แต่ส่งรายการ raw ไปที่ sendmail:

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

7

ฉันมากับฟังก์ชั่นโมดูลที่นำเข้าได้ มันใช้เซิร์ฟเวอร์อีเมล gmail ในตัวอย่างนี้ มันแบ่งออกเป็นส่วนหัวและข้อความเพื่อให้คุณสามารถเห็นสิ่งที่เกิดขึ้นอย่างชัดเจน:

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

ฉันคิดออกไม่กี่เดือนหลังและblogged เกี่ยวกับเรื่องนี้ สรุปคือ:

หากคุณต้องการใช้ smtplib เพื่อส่งอีเมลไปยังผู้รับหลายคนให้ใช้email.Message.add_header('To', eachRecipientAsString)เพื่อเพิ่มพวกเขาและจากนั้นเมื่อคุณเรียกใช้เมธอด sendmail use email.Message.get_all('To')ส่งข้อความถึงพวกเขาทั้งหมด เช่นเดียวกันสำหรับผู้รับสำเนาถึงและสำเนาลับถึง


Python 3.7 ส่งข้อยกเว้นพร้อมข้อความ: เกิดข้อยกเว้น: ValueError อาจมีอย่างน้อย 1 ส่วนหัวในข้อความ
Wojciech Jakubas

6

วิธีแก้ปัญหาด้านล่างใช้ได้สำหรับฉัน สามารถส่งอีเมลไปยังผู้รับหลายคนได้สำเร็จรวมถึง "CC" และ "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
ส่วนนี้ใช้งานได้หากต้องการซ่อน BCC จริงๆคุณจะต้องไม่ใช้ BCC line bcc = ['mailid_5', 'mailid_6'] มิฉะนั้นจะแสดงในส่วนหัวเพื่อเอาชนะจุดประสงค์ของ bcc ทดสอบกับ gmail และเมลเซิร์ฟเวอร์อื่น
วิลล์

@ คุณจะใช้ BCC อย่างไรในกรณีนั้น
3

4

ดีวิธีการในวิธีasnwer นี้ใช้ไม่ได้สำหรับฉัน ฉันไม่รู้บางทีนี่อาจเป็น Python3 (ฉันใช้รุ่น 3.4) หรือปัญหาที่เกี่ยวข้องกับ gmail แต่หลังจากที่ลองมาแล้วบางวิธีการแก้ปัญหาที่ใช้งานได้สำหรับฉันก็คือสาย

s.send_message(msg)

แทน

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

4

ฉันใช้ python 3.6 และรหัสต่อไปนี้ใช้ได้กับฉัน

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

มันใช้งานได้กับฉันด้วยฟังก์ชั่น send_message เท่านั้นและใช้ฟังก์ชั่นเข้าร่วมในรายการที่มีผู้รับ python 3.6


0

คุณสามารถลองวิธีนี้เมื่อคุณเขียนอีเมลผู้รับในไฟล์ข้อความ

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')
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.