Senden von HTML-E-Mails mit Python

260

Wie kann ich den HTML-Inhalt mit Python in einer E-Mail senden? Ich kann einfachen Text senden.

Peter Mortensen
quelle
Nur eine große fette Warnung. Wenn Sie Nicht- ASCII- E-Mails mit Python <3.0 senden , sollten Sie die E-Mail in Django verwenden . Es umschließt UTF-8- Zeichenfolgen korrekt und ist außerdem viel einfacher zu verwenden. Sie wurden gewarnt :-)
Anders Rune Jensen
1
Wenn Sie einen HTML- Code
guettli

Antworten:

419

Aus der Python v2.7.14-Dokumentation - 18.1.11. E-Mail: Beispiele :

Hier ist ein Beispiel für das Erstellen einer HTML-Nachricht mit einer alternativen Nur-Text-Version:

#! /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
quelle
1
Ist es möglich, einen dritten und einen vierten Teil anzuhängen, die beide Anhänge sind (ein ASCII, ein Binär)? Wie würde man das machen? Vielen Dank.
Hamish Grubijan
1
Hallo, mir ist aufgefallen, dass du quitam Ende das sObjekt hast . Was ist, wenn ich mehrere Nachrichten senden möchte? Sollte ich jedes Mal beenden, wenn ich die Nachricht sende, oder sie alle senden (in einer for-Schleife) und dann ein für alle Mal beenden?
xpanta
Stellen Sie sicher, dass Sie HTML zuletzt anhängen, da der bevorzugte (anzeigende) Teil der zuletzt angehängte ist. # According to RFC 2046, the last part of a multipart message, in this case # the HTML message, is best and preferred. Ich wünschte, ich hätte dies vor 2 Stunden gelesen
dwkd
1
Warnung: Dies schlägt fehl, wenn der Text Nicht-ASCII-Zeichen enthält.
Guettli
2
Hmm, ich bekomme den Fehler für msg.as_string (): Listenobjekt hat keine Attributcodierung
JohnAndrews
61

Sie könnten versuchen, meine zu verwenden Mailer- Modul zu verwenden.

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
quelle
Das Mailer-Modul ist großartig, behauptet jedoch, mit Google Mail zu arbeiten, tut dies jedoch nicht und es gibt keine Dokumente.
MFB
1
@MFB - Hast du das Bitbucket Repo ausprobiert? bitbucket.org/ginstrom/mailer
Ryan Ginstrom
2
Für Google Mail sollte man bereitstellen use_tls=True, usr='email'und pwd='password'bei der Initialisierung Mailerwird es funktionieren.
ToonAlfrink
Ich würde empfehlen, die folgende Zeile direkt nach der Nachricht in Ihren Code einzufügen. HTML-Zeile:message.Body = """Some text to show when the client cannot show HTML emails"""
IvanD
Großartig, aber wie man die Variablenwerte zum Link hinzufügt Ich meine, einen Link wie diesen <a href=" python.org/somevalues"> Link </ a > zu erstellen , damit ich über die Routen, zu denen er führt, auf diese Werte zugreifen kann. Vielen Dank
TaraGurung
49

Hier ist eine Google Mail- Implementierung der akzeptierten Antwort:

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
quelle
2
Toller Code, es funktioniert für mich, wenn ich niedrige Sicherheit in Google
aktiviert habe
15
Ich benutze ein Google- Anwendungs-spezifisches Passwort mit Python SMTplib, habe den Trick gemacht, ohne auf niedrige Sicherheit gehen zu müssen.
Jojo
2
Für alle, die die obigen Kommentare lesen: Sie benötigen nur ein "App-Passwort", wenn Sie zuvor die Bestätigung in zwei Schritten in Ihrem Google Mail-Konto aktiviert haben.
Mugen
Gibt es eine Möglichkeit, etwas dynamisch an den HTML-Teil der Nachricht anzuhängen?
Magma
40

Hier ist eine einfache Möglichkeit, eine HTML-E-Mail zu senden, indem Sie den Content-Type-Header als 'text / html' angeben:

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()
Taltman
quelle
2
Dies ist eine schöne einfache Antwort, praktisch für schnelle und schmutzige Skripte, danke. Übrigens kann man sich auf die akzeptierte Antwort für ein einfaches smtplib.SMTP()Beispiel beziehen , das keine tls verwendet. Ich habe dies für ein internes Skript bei der Arbeit verwendet, bei dem wir ssmtp und einen lokalen Mailhub verwenden. Auch dieses Beispiel fehlt s.quit().
Mike S
1
"mailmerge_conf.smtp_server" ist nicht definiert ... zumindest sagt Python 3.6 ...
ZEE
Ich habe einen Fehler bei der Verwendung von listenbasierten Empfängern erhalten. AttributeError: Das Objekt 'list' hat kein Attribut 'lstrip'. Gibt es eine Lösung?
Navotera
10

Hier ist Beispielcode. Dies ist inspiriert von Code auf der Python Cookbook- Website (der genaue Link kann nicht gefunden werden).

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
quelle
Zu Ihrer Information; Dies kam von code.activestate.com/recipes/67083-send-html-mail-from-python/…
Dale E. Moore
5

Verbessern Sie für Python3 die Antwort von @taltman :

  • Verwenden Sie email.message.EmailMessageanstelle von email.message.Message, um E-Mails zu erstellen.
  • benutze email.set_contentfunc, weise subtype='html'argument zu. anstelle von Low-Level-Funktion set_payloadund Header manuell hinzufügen.
  • Verwenden Sie SMTP.send_messagefunc anstelle von SMTP.sendmailfunc, um E-Mails zu senden.
  • Verwenden Sie den withBlock, um die Verbindung automatisch zu schließen.
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)
talgtc
quelle
4

Eigentlich hat yagmail einen etwas anderen Ansatz gewählt.

Es wird standardmäßig senden HTML, mit automatischem Rückfall für unfähig E - Mail-Leser. Es ist nicht mehr das 17. Jahrhundert.

Natürlich kann es überschrieben werden, aber hier geht's:

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)

Installationsanweisungen und viele weitere großartige Funktionen finden Sie im Github .

PascalVKooten
quelle
3

Hier ist ein funktionierendes Beispiel zum Senden von Nur-Text- und HTML-E-Mails von Python mit smtplib zusammen mit den CC- und BCC-Optionen.

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
quelle
Ich denke, diese Antwort deckt alles ab. Toller Link
stingMantis
1

Hier ist meine Antwort für AWS mit 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
quelle
0

Einfachste Lösung zum Senden von E-Mails von einem Organisationskonto 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()

hier df ein Datenrahmen, der in eine HTML-Tabelle konvertiert wurde und in html_template eingefügt wird

Gil Baggio
quelle
In der Frage wird nichts über die Verwendung von Office oder eines Organisationskontos erwähnt. Guter Beitrag, aber nicht sehr hilfreich für den Fragesteller
Mwikala Kangwa