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.


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 = "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
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="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)

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 = "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
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'] = '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
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 <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

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'] = '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

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

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


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 = "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)

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

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


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
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.