Enviando email em HTML usando Python


260

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


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 = "my@email.com"
you = "your@email.com"

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

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="me@example.com",
                  To="you@example.com")
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)

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 = "my@email.com"
you = "your@email.com"

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

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'] = 'sender@test.com'
msg['To'] = 'recipient@test.com'
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()

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 <sender@host.com>')
    server = smtplib.SMTP("smtp_server_address","smtp_port")
    server.login('username', 'password')
    server.sendmail('sender@host.com', 'target@otherhost.com', message)
    server.quit()


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'] = 'sender@test.com'
email['To'] = 'recipient@test.com'
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)

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("me@example.com", "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("to@example.com", "the subject", html_msg)

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


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 = "from_email@domain.com"
      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': 'to_email@domain.com',
    'email_cc': 'cc_email@domain.com',
    'email_bcc': 'bcc_email@domain.com',
    'email_subject': 'Test message from python library',
    'email_body': '<h1>Hello World</h1>'
}
for t in ['plain', 'html']:
    send_mail(params, t)

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 <do-not-reply@acme.com>',
    Destination={'ToAddresses': [email]},
    Message={
        'Subject': {'Data': subject},
        'Body': {
            'Html': {'Data': html}
        }
    }

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


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
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.