python发邮件图片太长显示不出来_小白入门,用python 发送定时邮件,将Dataframe转为邮件正文,链接显示为图片...

在实际工作中,我们常常会遇到定时发送邮件的任务,基于我的实践,分享给大家,也许一篇文章写不完,就先列个目录。

本文想要解决的问题:

用python构造一封邮件,并设置定时发送出去。往往,这只是最低级的需求,实际工作中会有各种细节和附加条件。

学会构造文本、HTML两种格式的邮件正文,学会构造和添加附件,其中,HTML格式要学会使用超链接,学会添加CSS用来美化正文。

将Dataframe格式的表格直接转化为HTML格式的表格,如果有超链接,要学会更改超链接,使之能完全显示,并在HTML正文显示对应的连接内容(比如显示连接的图片)。

1. 初步学会使用python编写发送邮件的脚本

关于python发邮件的类似文章有很多,不过,作为初学者,依然有许多需要注意的细节,如果作者没有写清楚的话,是很容易让人抓狂的。

由于2020年官方就停止更新和支持python2,所以本文顺应大势,使用的python3.6

1. python库

email库,用来编辑邮件内容的,包括标题,发件人,接收人,正文等。

smtplib库,用来发送邮件的,包括创建邮件服务,登陆,发送,退出等动作

一般来说,我是做如下导入,每一个模块都有相应的说明,具体应用继续看后面的内容。

# 导入相关库-email

from email.mime.multipart import MIMEMultipart # 构建邮件头信息,包括发件人,接收人,标题等

from email.mime.text import MIMEText # 构建邮件正文,可以是text,也可以是HTML

from email.mime.application import MIMEApplication # 构建邮件附件,理论上,只要是文件即可,一般是图片,Excel表格,word文件等

from email.header import Header # 专门构建邮件标题的,这样做,可以支持标题中文

import smtplib

2. 发送一个最简单的hello word的邮件(有重点)

发件人信息(重点)

这一小节的重点,也是很多小白容易犯糊涂的地方,就是发件人的账号和密码,以及相应的邮件服务器设置。不同的邮箱,其规则完全不一样,如果你有企业邮箱,那最好用企业邮箱,这点要记住,因为个人邮箱很容易出现网络问题、触发反垃圾机制等等,这是实践的出来的经验。另外,如果你使用过Foxmail、outlook等第三方邮件服务器,那你就更容易理解了。

上面箭头所指,就是163个人邮箱的发件服务器

上面箭头所指,就是163个人邮箱的发件服务器:smtp.163.com,如果是163的企业邮箱,其服务器地址则是:smtp.ym.163.com,我就是用的这个。

下面我要将的内容很关键:163个人邮箱的密码,不是登陆密码,而是客户端授权码,如下图所示:

image.png

我们这里是属于使用SMTP服务登陆和发送邮件的,所以使用常规的登陆密码,是无法发送邮件的。

然而,163的企业邮箱,却没有这个选项,直接使用登陆密码就可以发送邮件(我一直没明白为什么不一样,也许企业邮箱默认的就是开通了这些服务的,给我们的密码也即是授权码)。

常见的qq邮箱,谷歌邮箱,雅虎邮箱都是有这些区别的,新手一定要注意。下面就是我发送邮件的账号的密码设置,大家可以参照一下,不懂的直接在评论区@我:

# 邮件服务信息,个人

# smtp_server = 'smtp.163.com'

# username = "[email protected]"

# password = 'xxxxxx' # 授权码,并不是邮箱登陆密码

# 邮件服务信息,公司

smtp_server = 'smtp.ym.163.com'

username = "[email protected]"

password = 'xxxxxxxxx' # 授权码,企业163的就是登陆密码

这些信息,我们在构建邮件的发件人的时候需要用到,在使用SMTP发送邮件的时候也会用到,所以,一开始就给出来。

构建邮件正文

# 邮件发送和接收人

sender = username

receiver = ['[email protected]', '[email protected]']

# 邮件头信息

msg = MIMEMultipart('related')

msg['Subject'] = Header("我的第一封python邮件")

msg["From"] = sender

msg['To'] = ','.join(receiver) # 这里要注意

# text 内容

content_text = MIMEText("Hello World", "text", "utf-8")

msg.attach(content_text)

可以看到,这一节没有什么难点,先是定义发送者和接收人,然后使用MIMEMultipart类构建一个消息体msg,然后定义msg中的主题,发件人,接收人。其中,主题使用了Header类封装,目的是为了支持中文,最后,添加一段text的正文“hello world”,使用的是MIMEText类封装,第一个参数代表内容,第二个参数代表类型是text,另外还有html类型可选,下节介绍,最后一个参数是定义编码。

这里面只有一个地方需要注意,那就是msg['To'] = ','.join(receiver)这里,我们的邮件接收人是可以很多人的(列表),但是还需要用逗号把它们连接成一个字符串(email库的bug),如果是直接将列表扔给它,是要出错的。

发送邮件

# 发送邮件,测试成功,流程都是固定的:创建客户端,登陆,发送,关闭

email_client = smtplib.SMTP(smtp_server)

email_client.login(username, password)

email_client.sendmail(sender, receiver, msg.as_string())

email_client.quit()

这段代码,先是使用前面定义的邮件发送服务器:smtp_server = 'smtp.ym.163.com'来创建一个SMTP服务,然后传入账号和密码执行登陆,然后是发送邮件,需要的参数有:发送人,接收人,消息体,其中消息体执行了as_string(),将整个msg对象转化为了字符串,最后是退出服务。

这样,我们的第一封邮件就发送成功了。下面是这一阶段的完整代码,我将自己账号的password隐藏了,你只需要将你的账号信息替换进去,执行即可,如果没有成功,出现了任何不能解决的问题,请在评论区@我。

# 导入相关库-email

from email.mime.multipart import MIMEMultipart # 构建邮件头信息,包括发件人,接收人,标题等

from email.mime.text import MIMEText # 构建邮件正文,可以是text,也可以是HTML

from email.mime.application import MIMEApplication # 构建邮件附件,理论上,只要是文件即可,一般是图片,Excel表格,word文件等

from email.header import Header # 专门构建邮件标题的,这样做,可以支持标题中文

import smtplib

def send_email():

"""发送邮件的脚本"""

# 邮件服务信息,个人

# smtp_server = 'smtp.163.com'

# username = "[email protected]"

# password = 'xxxxx' # 授权码,并不是邮箱登陆密码

# 邮件服务信息,公司

smtp_server = 'smtp.ym.163.com'

username = "[email protected]"

password = 'xxxxx' # 授权码,企业163的就是登陆密码

# 邮件发送和接收人

sender = username

receiver = ['[email protected]', '[email protected]']

# 邮件头信息

msg = MIMEMultipart('related')

msg['Subject'] = Header("我的第一封python邮件")

msg["From"] = sender

msg['To'] = ','.join(receiver) # 这里要注意

# text 内容

content_text = MIMEText("Hello World", "text", "utf-8")

msg.attach(content_text)

# 发送邮件,测试成功,流程都是固定的:创建客户端,登陆,发送,关闭

email_client = smtplib.SMTP(smtp_server)

email_client.login(username, password)

email_client.sendmail(sender, receiver, msg.as_string())

email_client.quit()

if __name__ == '__main__':

send_email()

2. 学会构建HTML格式的正文,添加附件

前面我们已经学会了基本的邮件发送脚本编写,正文使用的是text,但是,我们常见的邮件基本都是以HTML格式作为正文的,偶尔还会带上一些附件。

HTML

HTML就是网页,使用这种格式的正文,可以使我们的邮件内容变得丰富无比,理论上,网页可以做成什么样,我们HTML格式的邮件正文就可以做成什么样!!

比如,我有下面这样一个网页:

Title

这是一封python写的邮件,使用的是HTML格式构造正文

可以为文字添加超链接,比如:简书-小溏


还可以添加图片,比如下面这张

在浏览器中显示如下:

image.png

现在,我将它放进我的邮件正文中,使用HTML格式,这种方式可以为文字添加超链接,可以插入图片

# 定义一个字符串,内容就是HTML代码

html_msg = \

"""

Title

这是一封python写的邮件,使用的是HTML格式构造正文

可以为文字添加超链接,比如:简书-小溏


还可以添加图片,比如下面这张

"""

# html 内容

content_html = MIMEText(html_msg, "html", "utf-8")

msg.attach(content_html)

我们定义好HTML字符串,然后使用MIMEText类封装它,第二个参数写“html”,同样添加(attach)到msg对象中。这和我们前面添加“hello word”这种纯text的内容方式是一样的,如果你现在还不明白上面这段代码该放在哪个位置,稍后我会给出完整的代码。

添加附件

关于附件,有2个问题需要重视:

附件的路径,最好是使用全路径。

附件的中文名称,需要设置编码。

添加附件前,我们需要确定附件的位置,也就是在系统上的路径。关于路径,我是吃过大亏的,所以各位新手也要注意,在不同的系统(linux和windows)是不一样的路径,分隔符也有区别,特别是要定时跑的脚本,在linux系统中的不同位置运行该脚本,相对路径都不一样,稍不注意就会break掉。

假如我要添加的附件是下面这个:

excel_file_path = r'E:\WorkSpace\pythonProjects\Ontime_Script\attach_table\recurring_pay_failed_user_info_2018-05-09.xlsx'

我写的是windows下的全路径,分隔符使用的是单个的正斜杠,前面加了个r,可以使那种类似转义符的代码失效。

如果是Linux下,该是这样的:

excel_file_path = '/root/pythonProjects/Ontime_Script/attach_table/recurring_pay_failed_user_info_2018-05-09.xlsx'

写成全路径,无论是在哪个目录下运行该脚本,都不会出现错误,这点要注意,相对路径是很坑人的。

# 构造附件,测试成功,附件有很多类型,现在构建的是html文件

attach_table = MIMEApplication(open(excel_file_path, 'rb').read())

# 给附件增加标题

attach_table.add_header('Content-Disposition', 'attachment',filename='我的附件.xlsx')

# 这样的话,附件名称就可以是中文的了,不会出现乱码

attach_table.set_charset('utf-8')

msg.attach(attach_table)

上面就是为msg对象添加附件的全过程了:先将xlsx文件读成二进制,作为参数构造MIMEApplication类,第二步是为这个附件添加名称(这个名称是在邮件中显示的),如果是中文,还需要设置一下编码,否则中文会显示为乱码,最后添加到msg中。

下面就是此节的全部代码:

# 导入相关库-email

from email.mime.multipart import MIMEMultipart # 构建邮件头信息,包括发件人,接收人,标题等

from email.mime.text import MIMEText # 构建邮件正文,可以是text,也可以是HTML

from email.mime.application import MIMEApplication # 构建邮件附件,理论上,只要是文件即可,一般是图片,Excel表格,word文件等

from email.header import Header # 专门构建邮件标题的,这样做,可以支持标题中文

import smtplib

def send_email(html_msg):

"""发送邮件的脚本"""

# 邮件服务信息,个人

# smtp_server = 'smtp.163.com'

# username = "[email protected]"

# password = 'xxxxx' # 授权码,并不是邮箱登陆密码

# 邮件服务信息,公司

smtp_server = 'smtp.ym.163.com'

username = "[email protected]"

password = 'xxxxxx' # 授权码,企业163的就是登陆密码

# 邮件发送和接收人

sender = username

receiver = ['[email protected]', '[email protected]']

# 邮件头信息

msg = MIMEMultipart('related')

msg['Subject'] = Header("我的第一封python邮件")

msg["From"] = sender

msg['To'] = ','.join(receiver) # 这里要注意

html_msg = \

"""

Title

这是一封python写的邮件,使用的是HTML格式构造正文

可以为文字添加超链接,比如:简书-小溏


还可以添加图片,比如下面这张

"""

# html 内容

content_html = MIMEText(html_msg, "html", "utf-8")

msg.attach(content_html)

excel_file_path = r'E:\WorkSpace\pythonProjects\Ontime_Script\email_market_report\attach_table\recurring_pay_failed_user_info_2018-05-09.xlsx'

# 构造附件,测试成功,附件有很多类型,现在构建的是xlsx文件

attach_table = MIMEApplication(open(excel_file_path, 'rb').read())

# 给附件增加标题

attach_table.add_header('Content-Disposition', 'attachment',filename='我的附件.xlsx')

# 这样的话,附件名称就可以是中文的了,不会出现乱码

attach_table.set_charset('utf-8')

msg.attach(attach_table)

# 发送邮件,测试成功,流程都是固定的:创建客户端,登陆,发送,关闭

email_client = smtplib.SMTP(smtp_server)

email_client.login(username, password)

email_client.sendmail(sender, receiver, msg.as_string())

email_client.quit()

if __name__ == '__main__':

send_email()

如果你需要添加其他类型的附件,比如图片,word,压缩包等,都是一样的,只是把文件名换一下即可,还有附件名称的后缀。

学到此处,基本的邮件发送是没问题了,但,往往实际工作中没有这么简单,HTML代码不是现成的,附件也需要临时生成等等。

3. 将Dataframe转为HTML,用CSS美化表格,设置URL,使之显示完全等细节工作

定时邮件,经常会伴随着实时数据的展现,在python中使用最多的是pandas包下面的DataFrame类,它就像一个Excel表格一样,可以完美的展示数据,但是,我们该如何将它完美的展现在邮件的正文中呢?

现在我给出一个示例的表格数据:

源数据链接:https://pan.baidu.com/s/1m9v3i153-M17Q8D6cmnMjw 密码:k8pk

image.png

如果是直接将这个Excel文件作为附件发送到邮件里,查看邮件的人是很苦恼的,首先还要下载附件,打开Excel,后面的缩略图还只是URL,想看具体长什么样,还得一个一个点开在浏览器里面查看。

现在,如果用HTML正文格式展示这个表格,上面讲到的痛点都会解决。

首先,我们读取Excel文件成为Dataframe格式

import pandas as pd

df = pd.read_excel(r"E:\WorkSpace\pythonProjects\Ontime_Script\attach_table\template_use.xlsx")

Dataframe有一个函数是to_html(),可以直接将df转为HTML中的table,它的参数相当多

def to_html(self, buf=None, columns=None, col_space=None, header=True,

index=True, na_rep='NaN', formatters=None, float_format=None,

sparsify=None, index_names=True, justify=None, bold_rows=True,

classes=None, escape=True, max_rows=None, max_cols=None,

show_dimensions=False, notebook=False, decimal='.',

border=None):

现在,我们先把df中的缩略图包装一下,以适应HTML中显示图片的格式

df['缩略图'] = ''

然后执行转换

df_html = df.to_html(escape=False)

escape这个参数是:Convert the characters , and & to HTML-safe sequences.=

就是说,我们df里面,如果有HTML的特有元素,是转化为转义的呢?还是保持本身的样子不变。显然,我们设置了img的格式,要在HTML中展示图片,比如下面这个

我们不希望将

现在,我们的任务就是,构造一个HTML的完整格式,然后将这个df_html 放进去即可,对于HTML的美化,我也一并放在代码中了,不在这里一一讲解。

本节全部的代码:

import pandas as pd

# 导入相关库-email

from email.mime.multipart import MIMEMultipart # 构建邮件头信息,包括发件人,接收人,标题等

from email.mime.text import MIMEText # 构建邮件正文,可以是text,也可以是HTML

from email.mime.application import MIMEApplication # 构建邮件附件,理论上,只要是文件即可,一般是图片,Excel表格,word文件等

from email.header import Header # 专门构建邮件标题的,这样做,可以支持标题中文

pd.set_option('display.max_colwidth', -1) # 能显示的最大宽度, 否则to_html出来的地址就不全

def get_html_msg():

"""

1. 构造html信息

"""

df = pd.read_excel(r"E:\WorkSpace\pythonProjects\Ontime_Script\email_market_report\attach_table\template_use.xlsx")

df['缩略图'] = ''

df_html = df.to_html(escape=False)

head = \

"""

table.dataframe {

border-collapse: collapse;

border: 2px solid #a19da2;

/*居中显示整个表格*/

margin: auto;

}

table.dataframe thead {

border: 2px solid #91c6e1;

background: #f1f1f1;

padding: 10px 10px 10px 10px;

color: #333333;

}

table.dataframe tbody {

border: 2px solid #91c6e1;

padding: 10px 10px 10px 10px;

}

table.dataframe tr {

}

table.dataframe th {

vertical-align: top;

font-size: 14px;

padding: 10px 10px 10px 10px;

color: #105de3;

font-family: arial;

text-align: center;

}

table.dataframe td {

text-align: center;

padding: 10px 10px 10px 10px;

}

body {

font-family: 宋体;

}

h1 {

color: #5db446

}

div.header h2 {

color: #0002e3;

font-family: 黑体;

}

div.content h2 {

text-align: center;

font-size: 28px;

text-shadow: 2px 2px 1px #de4040;

color: #fff;

font-weight: bold;

background-color: #008eb7;

line-height: 1.5;

margin: 20px 0;

box-shadow: 10px 10px 5px #888888;

border-radius: 5px;

}

h3 {

font-size: 22px;

background-color: rgba(0, 2, 227, 0.71);

text-shadow: 2px 2px 1px #de4040;

color: rgba(239, 241, 234, 0.99);

line-height: 1.5;

}

h4 {

color: #e10092;

font-family: 楷体;

font-size: 20px;

text-align: center;

}

td img {

/*width: 60px;*/

max-width: 300px;

max-height: 300px;

}

"""

# 构造模板的附件(100)

body = \

"""

我的python邮件,使用了Dataframe转为table


带图片展示的表格

{df_html}


—— 本次报告完 ——

""".format(df_html=df_html)

html_msg= "" + head + body + ""

# 这里是将HTML文件输出,作为测试的时候,查看格式用的,正式脚本中可以注释掉

fout = open('t4.html', 'w', encoding='UTF-8', newline='')

fout.write(html_msg)

return html_msg

def send_data_df(html_msg):

"""发送邮件的脚本"""

# 邮件服务信息,个人

# smtp_server = 'smtp.163.com'

# username = "[email protected]"

# password = 'xxxxxx' # 授权码,并不是邮箱登陆密码

# 邮件服务信息,公司

smtp_server = 'smtp.ym.163.com'

username = "[email protected]"

password = 'xxxxxx' # 授权码,企业163的就是登陆密码

# 邮件发送和接收人

sender = username

receiver = ['[email protected]', '[email protected]']

# 邮件头信息

msg = MIMEMultipart('related')

msg['Subject'] = Header("我的第一封python邮件")

msg["From"] = sender

msg['To'] = ','.join(receiver) # 这里要注意

# html 内容

content_html = MIMEText(html_msg, "html", "utf-8")

msg.attach(content_html)

# 发送邮件,测试成功,流程都是固定的:创建客户端,登陆,发送,关闭

email_client = smtplib.SMTP(smtp_server)

email_client.login(username, password)

email_client.sendmail(sender, receiver, msg.as_string())

email_client.quit()

if __name__ == '__main__':

html_msg = get_html_msg()

send_data(html_msg)

上面的代码里,CSS占了很长一段,我没有解释,如果有任何问题,请联系我。

另外,这段代码里还有一个很重要的

pd.set_option('display.max_colwidth', -1) # 能显示的最大宽度, 否则to_html出来的地址就不全

这是设置Dataframe的显示宽度的,因为缩略图那一列的内容很长,如果没有上诉设置的话,转出来的地址就被省略了一部分,使得无法显示图片,如果大家想测试其功能,可以注释掉,看看会发生什么结果。最后,附上这个邮件的发送结果:

image.png

很漂亮有木有~~~~,一眼就看到了图片长什么样,还有跟它相关的信息在一起,也不用下载附件再点开url了。

还有,如果大家想知道没有CSS美化的结果是什么样,可以注释掉CSS部分代码,然后运行看一看。

今天的分享就这样了,祝大家学习愉快。

你可能感兴趣的:(python发邮件图片太长显示不出来_小白入门,用python 发送定时邮件,将Dataframe转为邮件正文,链接显示为图片...)