Enviando email em HTML usando Python

260

Como posso enviar o conteúdo HTML em um email usando Python? Eu posso enviar texto simples.

Peter Mortensen
fonte
Apenas um aviso grande e gordo. Se você estiver enviando email não ASCII usando Python <3.0, considere usar o email no Django . Ele agrupa as seqüências UTF-8 corretamente e também é muito mais simples de usar. Você foi avisado :-)
Anders Rune Jensen
1
Se você quiser enviar uma HTML com unicode ver aqui: stackoverflow.com/questions/36397827/...
guettli

Respostas:

419

Da documentação do Python v2.7.14 - 18.1.11. email: Exemplos :

Aqui está um exemplo de como criar uma mensagem HTML com uma versão alternativa em texto sem formatação:

#! /usr/bin/python

import smtplib

from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText

# me == my email address
# you == recipient's email address
me = "[email protected]"
you = "[email protected]"

# Create message container - the correct MIME type is multipart/alternative.
msg = MIMEMultipart('alternative')
msg['Subject'] = "Link"
msg['From'] = me
msg['To'] = you

# Create the body of the message (a plain-text and an HTML version).
text = "Hi!\nHow are you?\nHere is the link you wanted:\nhttp://www.python.org"
html = """\
<html>
  <head></head>
  <body>
    <p>Hi!<br>
       How are you?<br>
       Here is the <a href="http://www.python.org">link</a> you wanted.
    </p>
  </body>
</html>
"""

# Record the MIME types of both parts - text/plain and text/html.
part1 = MIMEText(text, 'plain')
part2 = MIMEText(html, 'html')

# Attach parts into message container.
# According to RFC 2046, the last part of a multipart message, in this case
# the HTML message, is best and preferred.
msg.attach(part1)
msg.attach(part2)

# Send the message via local SMTP server.
s = smtplib.SMTP('localhost')
# sendmail function takes 3 arguments: sender's address, recipient's address
# and message to send - here it is sent as one string.
s.sendmail(me, you, msg.as_string())
s.quit()
Andrew Hare
fonte
1
É possível anexar uma terceira e uma quarta parte, que são anexos (um ASCII, um binário)? Como alguém faria isso? Obrigado.
Hamish Grubijan
1
Oi, notei que, no final, você quito sobjeto. E se eu quiser enviar várias mensagens? Devo sair sempre que enviar a mensagem ou todas (em um loop for) e sair de uma vez por todas?
Xpanta
Certifique-se de anexar o html por último, pois a parte preferida (mostrando) será a última anexada. # According to RFC 2046, the last part of a multipart message, in this case # the HTML message, is best and preferred. Gostaria de ler isso 2hrs ago
dwkd 4/15/15
1
Aviso: isso falhará se você tiver caracteres não-ascii no texto.
precisa
2
Hmm, eu recebo o erro para o objeto de lista msg.as_string (): não tem nenhum atributo codificado
JohnAndrews
61

Você pode tentar usar o meu módulo de mala direta .

from mailer import Mailer
from mailer import Message

message = Message(From="[email protected]",
                  To="[email protected]")
message.Subject = "An HTML Email"
message.Html = """<p>Hi!<br>
   How are you?<br>
   Here is the <a href="http://www.python.org">link</a> you wanted.</p>"""

sender = Mailer('smtp.example.com')
sender.send(message)
Ryan Ginstrom
fonte
O módulo Mailer é ótimo, no entanto, afirma trabalhar com o Gmail, mas não funciona e não há documentos.
MFB
1
@MFB - Você já tentou o repositório Bitbucket? bitbucket.org/ginstrom/mailer
Ryan Ginstrom
2
Para o gmail, deve-se fornecer use_tls=True, usr='email'e pwd='password'ao inicializar Mailere funcionará.
precisa saber é o seguinte
Eu recomendaria adicionar ao seu código a seguinte linha logo após a linha message.Html:message.Body = """Some text to show when the client cannot show HTML emails"""
IvanD 5/15
ótimo, mas como adicionar os valores das variáveis ​​ao link, quero dizer criar um link como este <a href=" python.org/somevalues"> link </ a > Para que eu possa acessar esses valores a partir das rotas para as quais ele vai. Obrigado
TaraGurung 4/16/16
49

Aqui está uma implementação do Gmail da resposta aceita:

import smtplib

from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText

# me == my email address
# you == recipient's email address
me = "[email protected]"
you = "[email protected]"

# Create message container - the correct MIME type is multipart/alternative.
msg = MIMEMultipart('alternative')
msg['Subject'] = "Link"
msg['From'] = me
msg['To'] = you

# Create the body of the message (a plain-text and an HTML version).
text = "Hi!\nHow are you?\nHere is the link you wanted:\nhttp://www.python.org"
html = """\
<html>
  <head></head>
  <body>
    <p>Hi!<br>
       How are you?<br>
       Here is the <a href="http://www.python.org">link</a> you wanted.
    </p>
  </body>
</html>
"""

# Record the MIME types of both parts - text/plain and text/html.
part1 = MIMEText(text, 'plain')
part2 = MIMEText(html, 'html')

# Attach parts into message container.
# According to RFC 2046, the last part of a multipart message, in this case
# the HTML message, is best and preferred.
msg.attach(part1)
msg.attach(part2)
# Send the message via local SMTP server.
mail = smtplib.SMTP('smtp.gmail.com', 587)

mail.ehlo()

mail.starttls()

mail.login('userName', 'password')
mail.sendmail(me, you, msg.as_string())
mail.quit()
DataTx
fonte
2
Grande código, ele funciona para mim, se eu ligado baixa segurança no google
Tovask
15
Eu uso uma senha específica do aplicativo google com python smtplib, fiz o truque sem ter que ir com baixa segurança.
yoyo
2
para quem lê os comentários acima: você só precisa de uma "Senha do aplicativo" se tiver ativado a verificação em duas etapas anteriormente na sua conta do Gmail.
Mugen
Existe uma maneira de acrescentar algo dinamicamente na parte HTML da mensagem?
magma
40

Aqui está uma maneira simples de enviar um email em HTML, apenas especificando o cabeçalho Content-Type como 'text / html':

import email.message
import smtplib

msg = email.message.Message()
msg['Subject'] = 'foo'
msg['From'] = '[email protected]'
msg['To'] = '[email protected]'
msg.add_header('Content-Type','text/html')
msg.set_payload('Body of <b>message</b>')

# Send the message via local SMTP server.
s = smtplib.SMTP('localhost')
s.starttls()
s.login(email_login,
        email_passwd)
s.sendmail(msg['From'], [msg['To']], msg.as_string())
s.quit()
3 rotações
fonte
2
Esta é uma resposta simples e agradável, útil para scripts rápidos e sujos, obrigado. BTW, pode-se consultar a resposta aceita para um smtplib.SMTP()exemplo simples , que não usa tls. Eu usei isso para um script interno no trabalho, onde usamos o ssmtp e um mailhub local. Além disso, este exemplo está ausente s.quit().
Mike S
1
"mailmerge_conf.smtp_server" não está definido ... pelo menos é o que o Python 3.6 diz ...
ZEE
Eu recebi um erro ao usar destinatários baseados em lista AttributeError: o objeto 'list' não tem nenhum atributo 'lstrip' alguma solução?
Navotera
10

Aqui está o código de exemplo. Isso é inspirado no código encontrado no site do Python Cookbook (não é possível encontrar o link exato)

def createhtmlmail (html, text, subject, fromEmail):
    """Create a mime-message that will render HTML in popular
    MUAs, text in better ones"""
    import MimeWriter
    import mimetools
    import cStringIO

    out = cStringIO.StringIO() # output buffer for our message 
    htmlin = cStringIO.StringIO(html)
    txtin = cStringIO.StringIO(text)

    writer = MimeWriter.MimeWriter(out)
    #
    # set up some basic headers... we put subject here
    # because smtplib.sendmail expects it to be in the
    # message body
    #
    writer.addheader("From", fromEmail)
    writer.addheader("Subject", subject)
    writer.addheader("MIME-Version", "1.0")
    #
    # start the multipart section of the message
    # multipart/alternative seems to work better
    # on some MUAs than multipart/mixed
    #
    writer.startmultipartbody("alternative")
    writer.flushheaders()
    #
    # the plain text section
    #
    subpart = writer.nextpart()
    subpart.addheader("Content-Transfer-Encoding", "quoted-printable")
    pout = subpart.startbody("text/plain", [("charset", 'us-ascii')])
    mimetools.encode(txtin, pout, 'quoted-printable')
    txtin.close()
    #
    # start the html subpart of the message
    #
    subpart = writer.nextpart()
    subpart.addheader("Content-Transfer-Encoding", "quoted-printable")
    #
    # returns us a file-ish object we can write to
    #
    pout = subpart.startbody("text/html", [("charset", 'us-ascii')])
    mimetools.encode(htmlin, pout, 'quoted-printable')
    htmlin.close()
    #
    # Now that we're done, close our writer and
    # return the message body
    #
    writer.lastpart()
    msg = out.getvalue()
    out.close()
    print msg
    return msg

if __name__=="__main__":
    import smtplib
    html = 'html version'
    text = 'TEST VERSION'
    subject = "BACKUP REPORT"
    message = createhtmlmail(html, text, subject, 'From Host <[email protected]>')
    server = smtplib.SMTP("smtp_server_address","smtp_port")
    server.login('username', 'password')
    server.sendmail('[email protected]', '[email protected]', message)
    server.quit()
Nathan
fonte
PARA SUA INFORMAÇÃO; este veio code.activestate.com/recipes/67083-send-html-mail-from-python/...
Dale E. Moore
5

para python3, melhore a resposta de @taltman :

  • use em email.message.EmailMessagevez de email.message.Messageconstruir email.
  • use email.set_contentfunc, atribua subtype='html'argumento. em vez da função de baixo nível set_payloade adicione o cabeçalho manualmente.
  • use SMTP.send_messagefunc em vez de SMTP.sendmailfunc para enviar email.
  • use o withbloco para fechar automaticamente a conexão.
from email.message import EmailMessage
from smtplib import SMTP

# construct email
email = EmailMessage()
email['Subject'] = 'foo'
email['From'] = '[email protected]'
email['To'] = '[email protected]'
email.set_content('<font color="red">red color text</font>', subtype='html')

# Send the message via local SMTP server.
with smtplib.SMTP('localhost') as s:
    s.login('foo_user', 'bar_password')
    s.send_message(email)
valleygtc
fonte
4

Na verdade, o yagmail adotou uma abordagem um pouco diferente.

Por padrão, ele envia HTML, com fallback automático para leitores de e-mail incapazes. Não é mais o século XVII.

Obviamente, ele pode ser substituído, mas aqui vai:

import yagmail
yag = yagmail.SMTP("[email protected]", "mypassword")

html_msg = """<p>Hi!<br>
              How are you?<br>
              Here is the <a href="http://www.python.org">link</a> you wanted.</p>"""

yag.send("[email protected]", "the subject", html_msg)

Para obter instruções de instalação e muitos outros recursos excelentes, dê uma olhada no github .

PascalVKooten
fonte
3

Aqui está um exemplo prático para enviar e-mails em texto sem formatação e HTML do Python usando smtplibjunto com as opções CC e BCC.

https://varunver.wordpress.com/2017/01/26/python-smtplib-send-plaintext-and-html-emails/

#!/usr/bin/env python
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText

def send_mail(params, type_):
      email_subject = params['email_subject']
      email_from = "[email protected]"
      email_to = params['email_to']
      email_cc = params.get('email_cc')
      email_bcc = params.get('email_bcc')
      email_body = params['email_body']

      msg = MIMEMultipart('alternative')
      msg['To'] = email_to
      msg['CC'] = email_cc
      msg['Subject'] = email_subject
      mt_html = MIMEText(email_body, type_)
      msg.attach(mt_html)

      server = smtplib.SMTP('YOUR_MAIL_SERVER.DOMAIN.COM')
      server.set_debuglevel(1)
      toaddrs = [email_to] + [email_cc] + [email_bcc]
      server.sendmail(email_from, toaddrs, msg.as_string())
      server.quit()

# Calling the mailer functions
params = {
    'email_to': '[email protected]',
    'email_cc': '[email protected]',
    'email_bcc': '[email protected]',
    'email_subject': 'Test message from python library',
    'email_body': '<h1>Hello World</h1>'
}
for t in ['plain', 'html']:
    send_mail(params, t)
Varun Verma
fonte
Pense que esta resposta cobre tudo. Grande ligação
stingMantis
1

Aqui está minha resposta para a AWS usando o boto3

    subject = "Hello"
    html = "<b>Hello Consumer</b>"

    client = boto3.client('ses', region_name='us-east-1', aws_access_key_id="your_key",
                      aws_secret_access_key="your_secret")

client.send_email(
    Source='ACME <[email protected]>',
    Destination={'ToAddresses': [email]},
    Message={
        'Subject': {'Data': subject},
        'Body': {
            'Html': {'Data': html}
        }
    }
Trent
fonte
0

Solução mais simples para enviar email da conta Organizacional no Office 365:

from O365 import Message

html_template =     """ 
            <html>
            <head>
                <title></title>
            </head>
            <body>
                    {}
            </body>
            </html>
        """

final_html_data = html_template.format(df.to_html(index=False))

o365_auth = ('sender_username@company_email.com','Password')
m = Message(auth=o365_auth)
m.setRecipients('receiver_username@company_email.com')
m.setSubject('Weekly report')
m.setBodyHTML(final_html_data)
m.sendMessage()

aqui df é um quadro de dados convertido em tabela html, que está sendo injetado em html_template

Gil Baggio
fonte
A pergunta não menciona nada sobre o uso do Office ou de uma conta organizacional. Boa contribuição, mas não muito útil para o autor da pergunta
Mwikala Kangwa