使用 Python 发送 HTML 电子邮件

Posted

技术标签:

【中文标题】使用 Python 发送 HTML 电子邮件【英文标题】:Send HTML emails with Python 【发布时间】:2010-10-27 07:57:19 【问题描述】:

如何使用 Python 在电子邮件中发送 html 内容?我可以发送简单的文本。

【问题讨论】:

只是一个大警告。如果您使用 Python ASCII 电子邮件,请考虑使用Django 中的电子邮件。它正确地包装了UTF-8 字符串,并且使用起来也更简单。您已被警告 :-) 如果您想发送带有 unicode 的 HTML,请参见此处:***.com/questions/36397827/… 【参考方案1】:

来自Python v2.7.14 documentation - 18.1.11. email: Examples:

下面是一个如何使用替代纯文本版本创建 HTML 消息的示例:

#! /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()

【讨论】:

是否可以附加第三和第四部分,两者都是附件(一个ASCII,一个二进制)?如何做到这一点?谢谢。 嗨,我注意到最后你 quit s 对象。如果我想发送多条消息怎么办?我应该在每次发送消息时退出还是将它们全部发送(在 for 循环中)然后一劳永逸地退出? 确保最后附加 html,因为首选(显示)部分将是最后附加的部分。 # According to RFC 2046, the last part of a multipart message, in this case # the HTML message, is best and preferred.我希望我能在 2 小时前读到这篇文章 警告:如果文本中包含非 ascii 字符,则会失败。 嗯,我得到 msg.as_string() 的错误:列表对象没有属性编码【参考方案2】:

这是已接受答案的Gmail 实现:

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

【讨论】:

很棒的代码,如果我打开low security in google,它对我有用 我使用 google application specific password 和 python smtplib,做到了这一点而不必降低安全性。 对于阅读上述 cmets 的任何人:如果您之前在 Gmail 帐户中启用了两步验证,则只需要“应用程序密码”。 有没有办法在邮件的 HTML 部分动态附加一些东西? 不知何故,只有最后一个附加部分似乎有效。【参考方案3】:

您可以尝试使用我的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)

【讨论】:

Mailer 模块很棒,但它声称可以与 Gmail 一起使用,但实际上并没有,也没有文档。 @MFB -- 你尝试过 Bitbucket 存储库吗? bitbucket.org/ginstrom/mailer 对于 gmail,在初始化 Mailer 时应提供 use_tls=True,usr='email'pwd='password',它会起作用。 我建议在 message.Html 行之后添加以下行:message.Body = """Some text to show when the client cannot show HTML emails""" 很好,但是如何将变量值添加到链接我的意思是创建一个像这样的链接 python.org/somevalues">link</a> 这样我就可以从它去的路由中访问这些值。谢谢【参考方案4】:

这是发送 HTML 电子邮件的简单方法,只需将 Content-Type 标头指定为“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()

【讨论】:

这是一个很好的简单答案,对于快速和肮脏的脚本很方便,谢谢。顺便说一句,可以参考一个简单的smtplib.SMTP() 示例的公认答案,该示例不使用 tls。我在工作中将其用于内部脚本,我们使用 ssmtp 和本地 mailhub。此外,此示例缺少 s.quit() "mailmerge_conf.smtp_server" 没有定义……至少 Python 3.6 是这么说的……【参考方案5】:

对于python3,改进@taltman 's answer:

使用email.message.EmailMessage 而不是email.message.Message 来构建电子邮件。 使用email.set_content 函数,分配subtype='html' 参数。而不是低级 func set_payload 并手动添加标题。 使用SMTP.send_message func 代替SMTP.sendmail func 来发送电子邮件。 使用with 块自动关闭连接。
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)

【讨论】:

作为改进,如果您想另外发送附件,请使用email.add_alternative()(与使用email.set_content() 相同的方式添加HTML,然后使用@ 添加附件987654333@(我花了很长时间才弄清楚) EmailMessage API 仅从 Python 3.6 开始正式可用,尽管它已在 3.3 中作为替代方案提供。新代码绝对应该使用它而不是旧的 email.message.Message 遗留 API,不幸的是,这里的大多数答案仍然建议使用它。带有MIMETextMIMEMultipart 的任何内容都是旧API,除非您有遗留原因,否则应避免使用。【参考方案6】:

这里是示例代码。这灵感来自Python Cookbook 网站上的代码(找不到确切的链接)

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

【讨论】:

仅供参考;这来自code.activestate.com/recipes/67083-send-html-mail-from-python/… 这比email.message.Message API 更古老、更复杂。 MimeWriter 库于 2003 年在 Python 2.3 中被弃用。【参考方案7】:

实际上,yagmail 采取了一些不同的方法。

它会默认发送 HTML,并为无能力的电子邮件阅读者自动回退。现在已经不是 17 世纪了。

当然,它可以被覆盖,但这里是:

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)

有关安装说明和更多强大功能,请查看github。

【讨论】:

只对 gmail 用户有帮助【参考方案8】:

这是一个使用 smtplib 以及 CC 和 BCC 选项从 Python 发送纯文本和 HTML 电子邮件的工作示例。

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)

【讨论】:

认为这个答案涵盖了一切。很好的链接【参考方案9】:

这是我使用 boto3 对 AWS 的回答

    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
        
    

【讨论】:

【参考方案10】:

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

这里的df是转换成html Table的dataframe,正在注入到html_template

【讨论】:

这个问题没有提到任何关于使用 Office 或组织帐户的内容。贡献不错,但对提问者帮助不大【参考方案11】:

我可能迟到在这里提供答案,但问题询问了一种发送 HTML 电子邮件的方法。使用像“电子邮件”这样的专用模块是可以的,但我们可以在不使用任何新模块的情况下获得相同的结果。这一切都归结为 Gmail 协议。

以下是我仅使用“smtplib”发送 HTML 邮件的简单示例代码。

```
import smtplib

FROM = "....@gmail.com"
TO = "another....@gmail.com"
SUBJECT= "Subject"
PWD = "thesecretkey"

TEXT="""
<h1>Hello</h1>
""" #Your Message (Even Supports HTML Directly)

message = f"Subject: SUBJECT\nFrom: FROM\nTo: TO\nContent-Type: text/html\n\nTEXT" #This is where the stuff happens

try:
    server=smtplib.SMTP("smtp.gmail.com",587)
    server.ehlo()
    server.starttls()
    server.login(FROM,PWD)
    server.sendmail(FROM,TO,message)
    server.close()
    print("Successfully sent the mail.")
except Exception as e:
    print("Failed to send the mail..", e)
```

【讨论】:

email 库不是一个“新模块”,它和smtplib 一样是标准库的一部分。您绝对不应该通过组合这样的字符串来创建消息;它似乎适用于非常简单的消息,但是一旦您移出仅具有 7 位 US-ASCII 内容的单个 text/plain 有效负载的舒适领域,它就会以灾难性的方式失败(即使这样,也有一些极端情况是可能会绊倒你,特别是如果你不知道自己在做什么)。【参考方案12】:

如果你想要更简单的东西:

from redmail import EmailSender
email = EmailSender(host="smtp.myhost.com", port=1)

email.send(
    subject="Example email",
    sender="me@example.com",
    receivers=["you@example.com"],
    html="<h1>Hi, this is HTML body</h1>"
)

Pip install Red Mail from PyPI:

pip install redmail

Red Mail 很可能拥有您发送电子邮件所需的一切,并且它具有许多功能,包括:

Attachments Templating (with Jinja) Embedded images Prettified tables Send as cc or bcc Gmail preconfigured

文档:https://red-mail.readthedocs.io/en/latest/index.html

源码:https://github.com/Miksus/red-mail

【讨论】:

以上是关于使用 Python 发送 HTML 电子邮件的主要内容,如果未能解决你的问题,请参考以下文章

Python 邮件发送

对于从 java 程序发送的电子邮件,html 内容中的 png 图像未显示在 gmail 客户端上

python接口自动化(三十三)-python自动发邮件总结及实例说明番外篇下(详解)

使用 Python 发送 HTML 电子邮件

我似乎无法让我的表格成功通过电子邮件发送

Access 2016 定时发送自动电子邮件