Enviar correo electrónico HTML usando Python


260

¿Cómo puedo enviar el contenido HTML en un correo electrónico usando Python? Puedo enviar un mensaje de texto simple.


Solo una gran advertencia. Si está enviando correos electrónicos que no son ASCII usando Python <3.0, considere usar el correo electrónico en Django . Envuelve las cadenas UTF-8 correctamente y también es mucho más simple de usar. Usted ha sido advertido :-)
Anders Rune Jensen

1
Si desea enviar un HTML con Unicode, consulte aquí: stackoverflow.com/questions/36397827/…
guettli

Respuestas:


419

De la documentación de Python v2.7.14 - 18.1.11. correo electrónico: Ejemplos :

Aquí hay un ejemplo de cómo crear un mensaje HTML con una versión alternativa de texto sin formato:

#! /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
¿Es posible adjuntar una tercera y una cuarta parte, ambas adjuntas (una ASCII, una binaria)? ¿Cómo haría uno eso? Gracias.
Hamish Grubijan

1
Hola, me di cuenta de que al final eres quitel sobjeto. ¿Qué pasa si quiero enviar múltiples mensajes? ¿Debo renunciar cada vez que envío el mensaje o enviarlos a todos (en un bucle for) y luego dejarlo de una vez por todas?
xpanta

Asegúrese de adjuntar html al final, ya que la parte preferida (que se muestra) será la que se adjuntará al final. # According to RFC 2046, the last part of a multipart message, in this case # the HTML message, is best and preferred. Desearía leer esto hace 2
horas

1
Advertencia: esto falla si tiene caracteres no ascii en el texto.
guettli

2
Hmm, obtengo el error para msg.as_string (): el objeto de lista no tiene codificación de atributo
JohnAndrews

61

Puede intentar usar mi módulo de correo .

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)

El módulo Mailer es excelente, sin embargo, afirma que funciona con Gmail, pero no lo hace y no hay documentos.
MFB

1
@MFB - ¿Has probado el repositorio de Bitbucket? bitbucket.org/ginstrom/mailer
Ryan Ginstrom

2
Para gmail se debe proporcionar use_tls=True, usr='email'y pwd='password'al inicializar Mailer, funcionará.
ToonAlfrink

Recomendaría agregar a su código la siguiente línea justo después del mensaje. Línea message.Body = """Some text to show when the client cannot show HTML emails"""
HTML

genial, pero cómo agregar los valores de las variables al enlace me refiero a crear un enlace como este <a href=" python.org/somevalues"> link </ a > Para que pueda acceder a esos valores desde las rutas a las que va. Gracias
TaraGurung

49

Aquí hay una implementación de Gmail de la respuesta aceptada:

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
Gran código, funciona para mí, si
activé la

15
Utilizo una contraseña específica de la aplicación de Google con python smtplib, hice el truco sin tener que ir con poca seguridad.
yoyo

2
para cualquiera que lea los comentarios anteriores: Solo necesita una "Contraseña de aplicación" si ha habilitado previamente la verificación en dos pasos en su cuenta de Gmail.
Mugen

¿Hay alguna manera de agregar algo dinámicamente en la parte HTML del mensaje?
magma

40

Aquí hay una manera simple de enviar un correo electrónico HTML, simplemente especificando el encabezado 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 es una buena respuesta simple, útil para scripts rápidos y sucios, gracias. Por cierto, uno puede referirse a la respuesta aceptada para un smtplib.SMTP()ejemplo simple , que no utiliza tls. Usé esto para un script interno en el trabajo donde usamos ssmtp y un mailhub local. Además, este ejemplo falta s.quit().
Mike S

1
"mailmerge_conf.smtp_server" no está definido ... al menos es lo que dice Python 3.6 ...
ZEE

recibí un error al usar receptores basados ​​en listas AttributeError: ¿el objeto 'list' no tiene el atributo 'lstrip' alguna solución?
navotera

10

Aquí hay un código de muestra. Esto está inspirado en el código que se encuentra en el sitio de Python Cookbook (no puedo encontrar el enlace exacto)

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, mejore la respuesta de @taltman :

  • utilizar en email.message.EmailMessagelugar de email.message.Messageconstruir correo electrónico.
  • use email.set_contentfunc, asigne subtype='html'argumento. en lugar de func de bajo nivel set_payloady agregue encabezado manualmente.
  • use SMTP.send_messagefunc en lugar de SMTP.sendmailfunc para enviar correos electrónicos.
  • use el withbloque para cerrar automáticamente la conexión.
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

En realidad, yagmail tomó un enfoque un poco diferente.

Por defecto enviará HTML, con respaldo automático para lectores de correo electrónico incapaces. Ya no es el siglo XVII.

Por supuesto, se puede anular, pero aquí va:

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 obtener instrucciones de instalación y muchas más funciones excelentes, eche un vistazo a github .


3

Aquí hay un ejemplo de trabajo para enviar mensajes de texto sin formato y correos electrónicos HTML desde Python usando smtplibjunto con las opciones CC y 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)

Piensa que esta respuesta cubre todo. Gran enlace
stingMantis

1

Aquí está mi respuesta para AWS usando 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

La solución más simple para enviar correos electrónicos desde la cuenta de la organización en 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()

aquí df es un marco de datos convertido a tabla html, que se inyecta a html_template


La pregunta no menciona nada sobre el uso de Office o una cuenta organizacional. Buena contribución pero no muy útil para el autor de la pregunta
Mwikala Kangwa
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.