Como enviar email para vários destinatários usando python smtplib?


196

Depois de muita pesquisa, não consegui descobrir como usar o smtplib.sendmail para enviar para vários destinatários. O problema era que, sempre que o email era enviado, os cabeçalhos pareciam conter vários endereços, mas na verdade apenas o primeiro destinatário recebia o email.

O problema parece ser que o email.Messagemódulo espera algo diferente da smtplib.sendmail()função.

Em resumo, para enviar para vários destinatários, você deve definir o cabeçalho como uma sequência de endereços de email delimitados por vírgula. O sendmail()parâmetro, to_addrsno entanto, deve ser uma lista de endereços de 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
Parece que OP respondeu à sua própria pergunta: sendmailprecisa de uma lista.
Cees Timmerman


Usando o Python3, tive que percorrer os destinatários; for addr in recipients: msg['To'] = addre então funcionou. Na verdade, várias atribuições acrescentam um novo cabeçalho 'Para' a cada uma. Essa é uma interface muito bizarra, eu nem consigo explicar como pensei em experimentar. Eu estava pensando em usar subprocesso sendmailpacote unix para salvar minha sanidade antes de descobrir isso.
mehtunguh

Respostas:


311

Isso realmente funciona , passei muito tempo tentando várias variantes.

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
a documentação tem o exemplo:tolist =["one@one.org","two@two.org","three@three.org","four@four.org"]
chug2k

2
obrigado @sorin por este script. Eu estava com problemas para enviar um email de um script python e, com esse pedaço de código, agora posso enviar o email.
Fear_matrix 14/07/2015

5
Isso não será enviado a vários destinatários se você estiver usando o Python 3, em send_messagevez de usar sendmailo comentário de Antoine abaixo e os documentos do Python docs.python.org/3/library/email-examples.html
cardamom

Você deve usar para cada passagem que os destinatários do sendmail, caso contrário, apenas o primeiro elemento receberá o email.
Johnny

2
correção para o URL mencionado acima: docs.python.org/3/library/email.examples.html
David

150

A msg['To']precisa ser uma string:

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

Enquanto o recipientsin sendmail(sender, recipients, message)precisa ser uma lista:

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

1
Esta é uma decisão de design estranha parasmtplib.
Adam Matan

2
recipientsnão precisa ser uma lista - se uma string for fornecida, ela será tratada como uma lista com um elemento. A msg['To']string pode ser simplesmente omitida.
Suzana

Realmente não entendo como 'a@a.com, b@b.com' é analisado para que apenas o primeiro endereço receba o email. Mas obrigado! Esta é a resposta, teve que colocar a lista lá.
antonavy

trabalhou para mim, e é consistente com a documentação em docs.python.org/2/library/email-examples.html
Rodrigo Laguna

43

Você precisa entender a diferença entre o endereço visível de um email e a entrega .

msg["To"]é essencialmente o que está impresso na carta. Na verdade, não tem nenhum efeito. Exceto que o seu cliente de email, assim como o oficial de correios, presumirá que é para quem você deseja enviar o email.

A entrega real, no entanto, pode funcionar bem diferente. Então você pode soltar o email (ou uma cópia) na caixa postal de alguém completamente diferente.

Há várias razões para isto. Por exemplo encaminhamento . oTo: campo do cabeçalho não muda no encaminhamento, no entanto, o email é descartado em uma caixa de correio diferente.

O smtp.sendmailcomando agora cuida da entrega real .email.Messageé apenas o conteúdo da carta, não a entrega.

Em nível baixo SMTP, você precisa fornecer aos destinatários um por um, e é por isso que uma lista de endereços (sem incluir nomes!) É a API sensata.

Para o cabeçalho, ele também pode conter, por exemplo, o nome, por exemplo To: First Last <email@addr.tld>, Other User <other@mail.tld>. Portanto, seu exemplo de código não é recomendado , pois ele falhará ao entregar este email, pois, ao dividi-lo, ,você ainda não possui os endereços válidos!


2
O RFC 2822 impõe uma largura máxima de 988 caracteres para um determinado cabeçalho e uma largura recomendada de 78 caracteres. Você precisará garantir que "dobre" o cabeçalho se você tiver muitos endereços.
Steve caça

Essa deve ser a resposta aceita, pois na verdade explica o porquê e como.
Serrano

Ótima resposta. E os campos de email CC e BCC? Suponho que também tenhamos que incluir os emails CC e BCC no smtp.send. E apenas a lista CC (e não a lista BCC) nos campos msg?
Tagar

Sim, é assim que funciona. Os servidores de email provavelmente eliminarão o campo Cco (para impedir que isso fique visível, e acho que não), mas eles não serão analisados.
Saiu - Anony-Mousse

19

Funciona para mim.

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

qual versão do python você está usando? Recebo o mesmo problema que o poster original e estou usando python 2.7.9
panofish

1
Por que não simplesmente em recipients = ['john.doe@example.com','john.smith@example.co.uk']vez de torná-lo uma string e depois dividi-lo para fazer uma lista?
WoJ 16/04/19

para o Woj, porque msg ['To'] deve ser uma string e s.sendmail deve ter uma lista: (remetente, >>> LIST AQUI <<<, msg.as_string ()). Isso significa que, por mais irritante que pareça, você não pode usar um mesmo tipo [string ou lista] para os dois campos
Pascal Louis-Marie

Funciona como um encanto para mim. Python 3.7.3.
Anadyn

11

Eu tentei o abaixo e funcionou como um encanto :)

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 todo código simples abaixo: 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

Na verdade, o problema é que SMTP.sendmail e email.MIMEText precisam de duas coisas diferentes.

email.MIMEText configura o cabeçalho "Para:" para o corpo do email. É usado SOMENTE para exibir um resultado ao ser humano na outra extremidade e, como todos os cabeçalhos de email, deve ser uma única sequência. (Observe que ele realmente não tem nada a ver com as pessoas que realmente recebem a mensagem.)

SMTP.sendmail, por outro lado, configura o "envelope" da mensagem para o protocolo SMTP. Ele precisa de uma lista de strings Python, cada uma com um único endereço.

Então, o que você precisa fazer é COMBINAR as duas respostas que você recebeu. Defina msg ['To'] como uma única string, mas passe a lista bruta para sendmail:

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

7

Eu vim com esta função de módulo importável. Ele usa o servidor de email do gmail neste exemplo. É dividido em cabeçalho e mensagem para que você possa ver claramente o que está acontecendo:

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

Eu descobri isso alguns meses atrás e escrevi sobre isso . O resumo é:

Se você deseja usar o smtplib para enviar email para vários destinatários, use-os email.Message.add_header('To', eachRecipientAsString)para adicioná-los e, quando você chamar o método sendmail, use email.Message.get_all('To')envie a mensagem para todos eles. O mesmo vale para os destinatários Cc e Cco.


Python 3.7 lança uma exceção com a mensagem: Ocorreu uma exceção : ValueError Pode haver no máximo 1 Para cabeçalhos em uma mensagem
Wojciech Jakubas

6

A solução abaixo funcionou para mim. Ele envia com êxito um email para vários destinatários, incluindo "CC" e "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
Isso funciona parcialmente, para ocultar realmente o Cco, você deve omitir a linha Cco bcc = ['mailid_5', 'mailid_6']; caso contrário, isso será exibido no cabeçalho, derrotando o objetivo do cco. Testado com o Gmail e outro servidor de email.
10249 Wil as

@ Como você implementaria o BCC nesse caso?
3pitt 18/09/19

4

Bem, o método neste método asnwer não funcionou para mim. Não sei, talvez esse seja um problema relacionado ao Python3 (estou usando a versão 3.4) ou ao gmail, mas depois de algumas tentativas, a solução que funcionou para mim foi a linha

s.send_message(msg)

ao invés de

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

4

Eu uso o python 3.6 e o ​​código a seguir funciona para mim

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

Ele só funcionou para mim com a função send_message e usando a função join na lista de destinatários, python 3.6.


0

você pode tentar isso ao escrever os e-mails dos destinatários em um arquivo de texto

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')
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.