使用 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,不幸的是,这里的大多数答案仍然建议使用它。带有MIMEText
或MIMEMultipart
的任何内容都是旧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 电子邮件的主要内容,如果未能解决你的问题,请参考以下文章
对于从 java 程序发送的电子邮件,html 内容中的 png 图像未显示在 gmail 客户端上