Invio di e-mail HTML tramite Python


260

Come posso inviare il contenuto HTML in un'e-mail usando Python? Posso inviare un semplice testo.


Solo un grosso avvertimento grasso. Se stai inviando e- mail non ASCII usando Python <3.0, considera di usare l'e-mail in Django . Avvolge correttamente le stringhe UTF-8 ed è anche molto più semplice da usare. Sei stato avvisato :-)
Anders Rune Jensen,

1
Se si desidera inviare un HTML con unicode vedere qui: stackoverflow.com/questions/36397827/...
guettli

Risposte:


419

Dalla documentazione di Python v2.7.14 - 18.1.11. email: esempi :

Ecco un esempio di come creare un messaggio HTML con una versione di testo normale alternativa:

#! /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
È possibile allegare una terza e una quarta parte, entrambe le quali sono allegati (una ASCII, una binaria)? Come si farebbe? Grazie.
Hamish Grubijan,

1
Ciao, ho notato che alla fine sei quitl' soggetto. Cosa succede se desidero inviare più messaggi? Devo uscire ogni volta che invio il messaggio o inviarli tutti (in un ciclo for) e quindi uscire una volta per tutte?
xpanta,

Assicurati di collegare html per ultimo, poiché la parte preferita (mostrando) sarà quella allegata per ultima. # According to RFC 2046, the last part of a multipart message, in this case # the HTML message, is best and preferred. Vorrei leggere questo 2 ore fa
dwkd

1
Avviso: questo non riesce se nel testo sono presenti caratteri non ASCII.
Guettli,

2
Hmm, ricevo l'errore per msg.as_string (): l'oggetto list non ha codifica di attributo
JohnAndrews

61

Potresti provare a usare my modulo mailer .

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)

Il modulo Mailer è eccezionale, tuttavia afferma di funzionare con Gmail, ma non lo è e non ci sono documenti.
MFB

1
@MFB - Hai provato il repository Bitbucket? bitbucket.org/ginstrom/mailer
Ryan Ginstrom il

2
Per gmail si dovrebbe fornire use_tls=True, usr='email'e pwd='password'quando l'inizializzazione Mailere funzionerà.
ToonAlfrink,

Ti consiglio di aggiungere al tuo codice la seguente riga subito dopo il messaggio. message.Body = """Some text to show when the client cannot show HTML emails"""
Riga HTML

fantastico, ma come aggiungere i valori delle variabili al collegamento, intendo creare un collegamento come questo <a href=" python.org/somevalues"> collegamento </ a > In modo che io possa accedere a tali valori dalle rotte verso cui va. Grazie
TaraGurung il

49

Ecco un'implementazione di Gmail della risposta accettata:

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
Ottimo codice, funziona per me, se ho attivato la bassa sicurezza in Google
Tovask il

15
Uso una password specifica per l'applicazione google con python smtplib, ho fatto il trucco senza dover passare alla bassa sicurezza.
yoyo

2
per chiunque legga i commenti precedenti: è necessaria una "Password app" solo se in precedenza è stata abilitata la verifica in due passaggi nel proprio account Gmail.
Mugen,

C'è un modo per aggiungere qualcosa in modo dinamico nella parte HTML del messaggio?
magma

40

Ecco un modo semplice per inviare un'e-mail HTML, semplicemente specificando l'intestazione Content-Type come '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
Questa è una bella risposta semplice, utile per script veloci e sporchi, grazie. A proposito si può fare riferimento alla risposta accettata per un semplice smtplib.SMTP()esempio, che non utilizza tls. L'ho usato per uno script interno al lavoro in cui utilizziamo ssmtp e un mailhub locale. Inoltre, questo esempio è mancante s.quit().
Mike S,

1
"mailmerge_conf.smtp_server" non è definito ... almeno è quello che dice Python 3.6 ...
ZEE

ho riscontrato un errore durante l'utilizzo dei destinatari basati su elenco AttributeError: l'oggetto 'list' non ha alcun attributo 'lstrip' qualsiasi soluzione?
Navotera,

10

Ecco un codice di esempio. Questo si ispira al codice trovato sul sito Cookbook di Python (non riesco a trovare il link esatto)

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

per python3, migliora la risposta di @taltman :

  • utilizzare email.message.EmailMessageinvece di email.message.Messagecostruire e-mail.
  • usa email.set_contentfunc, assegna subtype='html'argomento. invece di funzioni di basso livello set_payloade aggiungi l'intestazione manualmente.
  • usa SMTP.send_messagefunc invece di SMTP.sendmailfunc per inviare e-mail.
  • usa il withblocco per chiudere automaticamente la connessione.
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

In realtà, yagmail ha adottato un approccio leggermente diverso.

Per impostazione predefinita, invierà HTML, con fallback automatico per i lettori di e-mail incapaci. Non è più il 17 ° secolo.

Certo, può essere ignorato, ma qui 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)

Per le istruzioni di installazione e molte altre fantastiche funzionalità, dai un'occhiata al github .


3

Ecco un esempio funzionante per inviare e-mail in testo semplice e HTML da Python utilizzando smtplibinsieme alle opzioni 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)

Pensa che questa risposta copra tutto. Ottimo collegamento
stingMantis,

1

Ecco la mia risposta per 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

Soluzione più semplice per l'invio di e-mail dall'account organizzativo in 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()

qui df è un frame di dati convertito in tabella html, che viene iniettato in html_template


La domanda non menziona nulla sull'uso di Office o di un account organizzativo. Buon contributo ma non molto utile per chi
chiede
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.