Python smtplib kullanarak birden çok alıcıya e-posta nasıl gönderilir?


198

Çok fazla arama yaptıktan sonra birden fazla alıcıya göndermek için smtplib.sendmail'in nasıl kullanılacağını bulamadım. Sorun postanın her gönderilmesinde posta başlıklarının birden fazla adres içerdiği görülüyordu, ancak aslında sadece ilk alıcı e-postayı alacaktı.

Sorun, email.Messagemodülün smtplib.sendmail()işlevden farklı bir şey beklemesi gibi görünüyor .

Kısacası, birden çok alıcıya göndermek için üstbilgiyi virgülle ayrılmış e-posta adresleri dizesi olarak ayarlamanız gerekir. Ancak sendmail()parametre to_addrsbir e-posta adresi listesi olmalıdır.

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
Görünüşe göre OP kendi sorusunu yanıtladı: sendmailbir listeye ihtiyacı var.
Cees Timmerman


Python3 kullanarak alıcılar arasında döngü vardı; for addr in recipients: msg['To'] = addrve sonra işe yaradı. Birden çok atama aslında her biri için yeni bir 'Kime' başlığı ekler. Bu çok tuhaf bir arayüz, nasıl denemeyi düşündüğümü bile açıklayamıyorum. Bunu çözmeden önce akıl sağlığımı kurtarmak subprocessiçin unix sendmailpaketini çağırmayı bile düşünüyordum .
mehtunguh

Yanıtlar:


313

Bu gerçekten işe yarıyor , birden fazla varyantı denemek için çok zaman harcadım.

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
belgelerde örnek var:tolist =["one@one.org","two@two.org","three@three.org","four@four.org"]
chug2k 23:13

2
bu senaryo için teşekkür ederim. Ben bir python script e-posta göndermek için bir sorun vardı ve bu kod parçası ile, şimdi e-posta gönderebilirsiniz.
fear_matrix

5
Python 3 kullanıyorsanız bu size gereken birden çok alıcıya göndermek olmaz send_messageyerine sendmailAntoine'nin aşağıda yorum ve Python docs göre docs.python.org/3/library/email-examples.html
kakule

Sendmail için alıcıların her geçişi için kullanmanız gerekir, aksi takdirde yalnızca ilk öğe postayı alır.
Johnny

2
yukarıda belirtilen url'ye düzeltme: docs.python.org/3/library/email.examples.html
David

151

msg['To']Bir dize olması gerekir:

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

İken recipientsde sendmail(sender, recipients, message)ihtiyaçları listesi gibi:

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

1
Bu garip bir tasarım kararısmtplib.
Adam Matan

2
recipientsbir liste olmak zorunda değildir - bir dize verilirse, bir öğe içeren bir liste olarak kabul edilir. msg['To']Dize basitçe atlanabilir.
Suzana

Gerçekten 'a@a.com, b@b.com' un nasıl ayrıştırıldığını anlamıyorum, bu yüzden sadece ilk adres e-postayı alır. Ama teşekkürler! Bu cevap, oraya liste koymak zorunda kaldı.
antonavy


44

Bir e-postanın görünür adresi ile teslimat arasındaki farkı anlamalısınız .

msg["To"]aslında mektubun üzerinde yazılı olan şeydir. Aslında bir etkisi yok. E-posta istemciniz, normal posta memuru gibi, bunun e-postayı göndermek istediğiniz kişi olduğunu varsayacaktır.

Ancak gerçek teslimat oldukça farklı olabilir. Yani yapabilirsiniz bambaşka birinin sonrası kutuya e-posta (veya bir kopyasını) bırakın.

Bunun için birden çok neden var. Örneğin yönlendirme . To:Başlık alanı yönlendirme üzerinde değişmez ancak farklı bir e posta kutusuna dökülür.

smtp.sendmailKomutu artık ilgilenir fiili teslim. email.Messageyalnızca mektubun içeriğidir, teslim değil.

Düşük düzeyde SMTP, alıcılara birer birer vermeniz gerekir, bu nedenle adreslerin bir listesi (adlar dahil değil!) Mantıklı API'dir.

Üstbilgi için, örneğin adı da içerebilir To: First Last <email@addr.tld>, Other User <other@mail.tld>. Bu nedenle kod örneğiniz tavsiye edilmez , çünkü bu postayı teslim etmede başarısız olur, çünkü sadece bölerek ,geçerli adreslere sahip değilsiniz!


2
RFC 2822, belirli bir üstbilgi için maksimum 988 karakter ve önerilen 78 karakter genişliğini uygular. Çok fazla adresiniz varsa başlığı "katladığınızdan" emin olmanız gerekir.
Steve Hunt

Neden ve nasıl olduğunu açıkladığı için bu kabul edilen cevap olmalıdır.
Serrano

Mükemmel cevap. CC ve BCC e-posta alanları ne olacak? Ayrıca smtp.send'e CC ve BCC e-postalarını eklememiz gerektiğini varsayıyorum. Ve msg alanlarında sadece CC listesi (BCC listesi değil)?
Tagar

Evet, işte böyle çalışır. Posta sunucuları büyük olasılıkla BCC alanını bırakacaktır (bunun görünür olmasını önlemek için ve hepsinin yaptığını sanmıyorum), ancak ayrıştırmazlar.
ÇIKIŞ - Anony-Mousse

19

Benim için çalışıyor.

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

hangi python sürümünü kullanıyorsunuz? Orijinal poster ile aynı sorunu alıyorum ve python 2.7.9 kullanıyorum
panofish

1
Neden sadece recipients = ['john.doe@example.com','john.smith@example.co.uk']bir dize yapmak yerine bir liste yapmak için onu bölmek yerine?
WoJ

Woj'a, çünkü msg ['To'] bir dize olmalı ve s.sendmail'in bir listesi olmalıdır: (gönderen, >>> BURAYA LİSTE <<<, msg.as_string ()). Bu, göründüğü kadar sinir bozucu, her iki alan için aynı tür [dize veya liste] kullanamayacağınız anlamına gelir
Pascal Louis-Marie

Benim için bir cazibe gibi çalışıyor. Python 3.7.3.
Anadyn

11

Aşağıdaki denedim ve bir cazibe gibi çalıştı :)

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

Aşağıda tüm basit kod: 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

Yani aslında sorun şu ki SMTP.sendmail ve email.MIMEText iki farklı şeye ihtiyaç duyuyor.

E-postanın gövdesi için "Kime:" üstbilgisini ayarlar. SADECE insanın diğer ucundaki bir sonucu görüntülemek için kullanılır ve tüm e-posta başlıkları gibi, tek bir dize olmalıdır. (Aslında mesajı alan kişilerle hiçbir ilgisi olmadığını unutmayın.)

SMTP.sendmail, SMTP protokolü için iletinin "zarfını" ayarlar. Her birinin tek bir adresi olan bir Python dizesi listesine ihtiyacı vardır.

Yani, yapmanız gereken iki yanıtı BİRLEŞTİRMEK. Msg ['To'] öğesini tek bir dizeye ayarlayın, ancak sendmail'e ham listeyi iletin:

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

7

Bu ithal modül fonksiyonu ile geldim. Bu örnekte gmail e-posta sunucusunu kullanır. Neler olup bittiğini açıkça görebilmeniz için başlık ve iletiye ayrılmıştır:

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

Bunu birkaç ay önce anladım ve blog yazdım . Özet:

Birden fazla alıcıya e-posta göndermek için smtplib kullanmak istiyorsanız, email.Message.add_header('To', eachRecipientAsString)bunları eklemek için kullanın ve sonra sendmail yöntemini çağırdığınızda use email.Message.get_all('To'), iletiyi hepsine gönderin. Bilgi ve Gizli alıcılar için Ditto.


Python 3.7, ileti ile bir istisna atar: İstisna oluştu: ValueError Mesajda en fazla 1 başlık olabilir
Wojciech Jakubas

6

Aşağıdaki çözüm benim için çalıştı. "CC" ve "BCC" dahil olmak üzere birden çok alıcıya başarıyla bir e-posta gönderir.

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
Bu kısmen çalışır, BCC'yi gerçekten gizlemek için BCC satırını atlamalısınız bcc = ['mailid_5', 'mailid_6'] aksi takdirde bcc amacını yenen başlıkta gösterilir. Gmail ve diğer posta sunucusu ile test edildi.
Wil

@Bu durumda BCC'yi nasıl uygularsınız?
3pitt

4

Eh, yöntem bu asnwer yöntemine benim için çalışmadı. Bilmiyorum, belki bu bir Python3 (3.4 sürümünü kullanıyorum) veya gmail ile ilgili bir sorun, ancak bazı denemelerden sonra benim için çalışan çözüm, satırdı

s.send_message(msg)

onun yerine

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

4

Python 3.6 kullanıyorum ve aşağıdaki kod benim için çalışıyor

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

Sadece send_message fonksiyonu ve alıcılar python 3.6 ile listedeki join işlevini kullanarak benim için çalıştı.


0

recpient e-postaları bir metin dosyasına yazarken bunu deneyebilirsiniz

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')
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.