Wysyłanie wiadomości e-mail w formacie HTML przy użyciu języka Python


260

Jak mogę wysłać treść HTML w wiadomości e-mail za pomocą Pythona? Mogę wysłać prosty tekst.


Wielkie ostrzeżenie o tłuszczu. Jeśli wysyłasz wiadomości e-mail inne niż ASCII przy użyciu języka Python <3.0, rozważ użycie wiadomości e-mail w Django . Prawidłowo otacza łańcuchy UTF-8 , a także jest znacznie prostszy w użyciu. Zostałeś ostrzeżony :-)
Anders Rune Jensen

1
Jeśli chcesz wysłać HTML z Unicode, zobacz tutaj: stackoverflow.com/questions/36397827/...
guettli

Odpowiedzi:


419

Z dokumentacji Python v2.7.14 - 18.1.11. email: Przykłady :

Oto przykład, jak utworzyć wiadomość HTML z alternatywną wersją zwykłego tekstu:

#! /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
Czy można dołączyć trzecią i czwartą część, z których obie są załącznikami (jeden ASCII, jeden plik binarny)? Jak by to zrobić? Dzięki.
Hamish Grubijan,

1
Witam, zauważyłem, że w końcu jesteś obiektu. Co jeśli chcę wysłać wiele wiadomości? Czy powinienem rezygnować za każdym razem, gdy wysyłam wiadomość, czy wysyłam je wszystkie (w pętli for), a następnie raz na zawsze? quits
xpanta,

Upewnij się, że dołączasz html jako ostatni, ponieważ preferowaną (pokazującą) częścią będzie ta dołączona na końcu. # According to RFC 2046, the last part of a multipart message, in this case # the HTML message, is best and preferred. Chciałbym przeczytać to 2 godziny temu
dwkd

1
Ostrzeżenie: nie powiedzie się, jeśli w tekście znajdują się znaki inne niż ascii.
guettli

2
Hmm, dostaję błąd dla msg.as_string (): obiekt listy nie ma kodowania atrybutów
JohnAndrews

61

Możesz spróbować użyć mojego modułu pocztowego .

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)

Moduł Mailera jest świetny, ale twierdzi, że współpracuje z Gmailem, ale nie działa i nie ma żadnych dokumentów.
MFB,

1
@MFB - Czy próbowałeś repozytorium Bitbucket? bitbucket.org/ginstrom/mailer
Ryan Ginstrom

2
Dla Gmaila należy podać use_tls=True, usr='email'a pwd='password'podczas inicjalizacji Maileri będzie działać.
ToonAlfrink

Polecam dodanie do kodu następującego wiersza zaraz po wiadomości. Wiersz message.Body = """Some text to show when the client cannot show HTML emails"""
HTML

świetnie, ale jak dodać wartości zmiennych do linku, mam na myśli utworzenie linku takiego jak ten <a href=" python.org/somevalues"> link </ a > Tak, żebym mógł uzyskać dostęp do tych wartości z tras, do których prowadzi. Dzięki
TaraGurung,

49

Oto implementacja zaakceptowanej odpowiedzi w Gmailu :

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
Świetny kod, działa dla mnie, jeśli włączyłem niskie bezpieczeństwo w Google
Tovask

15
Używam hasła specyficznego dla aplikacji Google z python smtplib, wykonałem tę sztuczkę bez konieczności obniżania poziomu bezpieczeństwa.
yoyo

2
dla osób czytających powyższe komentarze: „Hasło do aplikacji” jest wymagane tylko wtedy, gdy wcześniej włączyłeś weryfikację dwuetapową na swoim koncie Gmail.
Mugen,

Czy istnieje sposób na dynamiczne dołączanie czegoś w części HTML wiadomości?
magma

40

Oto prosty sposób wysłania wiadomości e-mail w formacie HTML, określając nagłówek Content-Type jako „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
To ładna prosta odpowiedź, przydatna do szybkich i brudnych skryptów, dzięki. BTW można odnieść się do przyjętej odpowiedzi na prosty smtplib.SMTP()przykład, który nie używa tls. Użyłem tego do wewnętrznego skryptu w pracy, w którym używamy ssmtp i lokalnej poczty. Brakuje również tego przykładu s.quit().
Mike S

1
„mailmerge_conf.smtp_server” nie jest zdefiniowany ... przynajmniej tak mówi Python 3.6 ...
ZEE

dostałem błąd podczas korzystania z adresatów opartych na listach AttributeError: obiekt „list” nie ma atrybutu „lstrip” jakieś rozwiązanie?
navotera

10

Oto przykładowy kod. Inspiracją jest kod znaleziony na stronie Python Cookbook (nie można znaleźć dokładnego linku)

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

w przypadku python3 popraw odpowiedź @taltman :

  • użyj email.message.EmailMessagezamiast email.message.Messagedo tworzenia wiadomości e-mail.
  • użyj email.set_contentfunc, przypisz subtype='html'argument. zamiast func niskiego poziomu set_payloadi ręcznie dodawać nagłówek.
  • do wysyłania wiadomości e-mail użyj SMTP.send_messagefunc zamiast SMTP.sendmailfunc.
  • użyj withbloku, aby automatycznie zamknąć połączenie.
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

W rzeczywistości yagmail przyjął nieco inne podejście.

To będzie domyślnie wysyłać HTML, z automatycznym fallback dla niezdolnych czytniki e-mail. To już nie jest XVII wiek.

Oczywiście można to zmienić, ale oto:

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)

Aby uzyskać instrukcje instalacji i wiele innych wspaniałych funkcji, zajrzyj na github .


3

Oto działający przykład wysyłania zwykłego tekstu i wiadomości e-mail z języka Python przy użyciu smtplibopcji CC i 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)

Pomyśl, że ta odpowiedź obejmuje wszystko. Świetny link
stingMantis

1

Oto moja odpowiedź na AWS za pomocą 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

Najprostsze rozwiązanie do wysyłania wiadomości e-mail z konta organizacji w 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()

tutaj df to ramka danych przekonwertowana na tabelę HTML, która jest wstrzykiwana do szablonu HTML


Pytanie nie wspomina nic o korzystaniu z pakietu Office lub konta organizacyjnego. Dobry wkład, ale niezbyt pomocny dla
pytającego
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.