python怎么发图文_用Python发一封图文并茂的邮件

最近使用了不少通讯工具的接口, 比如企业微信机器人,钉钉,微信公众号的接口(未认证的订阅公众号),相对于邮件来说,它们的表现形式太弱。比如没有更丰富的版本方式。当然了,并不是说表现形式越棒就是约好的通知手段,这个依个人情况而定,而我恰恰需要比较丰富的表现形式,最终还是回到了邮件,邮件真香!

而个人微信号的接口我没有合适的微信号可以登录,如果网页版微信没有被封的话,我想这个是表现形式与消息时效性结合的最好的方式。

环境

虽说就发邮件这么个小事,很容易兼容Python2, Python3, 但是大家还是拥抱Python3吧, 我这里没有做python2的兼容写法,所以需要python3以上。

邮件的格式

邮件的格式主要就两种: plain和html

plain就像一个普通的文本, 没有格式。

html就如其名, 是html的格式,相当于一个邮件就是一个静态的网页,这样的话可玩性就很高了,你可以通过css控制表现形式.

注意: 这里的css虽然语法一样,但,是否与浏览器渲染结果完全一致, 是不一定的。

那么可能有人要问了,我要发一个动态的网页怎么办? 发个链接呀

邮箱账号

无论是QQ邮箱抑或网易邮箱都是没有问题的,重要的是有一个可以通过smtp服务器发送邮件的账户名及密码,这里大家百度吧。

发送邮件的代码

因为发送邮件的代码在下面每个步骤都是一样的所以线贴出来

def send_email(msg, mail_to, smtp_host, smtp_username, smtp_password, subject, from_):

msg["Subject"] = Header(subject, "utf-8")

msg["From"] = Header(from_, "utf-8")

if not isinstance(mail_to, list):

mail_to = [mail_to]

msg["To"] = COMMASPACE.join(mail_to)

try:

print("准备连接smtp邮件服务器: %s" % smtp_host)

client = smtplib.SMTP(smtp_host)

print("连接成功")

# client = smtplib.SMTP("localhost")

# client.set_debuglevel(1)

# print(self.mail_user, self.mail_pass)

client.login(smtp_username, smtp_password)

print("登录成功")

# print("=====>", self.mail_from, mail_to)

print("通过邮箱[%s]发送邮件给 %s" % (smtp_username, COMMASPACE.join(mail_to)))

client.sendmail(smtp_username, mail_to, msg.as_string())

print("发送成功...")

return True

except Exception:

print("发送邮件失败")

finally:

client.quit()

如果遇到邮件发送的问题可以将client.set_debuglevel(1)的注释取消,这样会显示足够多的debug信息用于排查问题。

发送本地图片

这里发送图片的意思是指, 图片内嵌在邮件中而不是以附件的形式出现。

效果如下:

代码如下:

EMAIL_IMAGE_TEMPLATE = """

Page Title

这是一张图片

"""

def create_image_eamil_contant(fp):

tpl = Template(EMAIL_IMAGE_TEMPLATE)

if not path.exists(fp):

sys.exit("要发送的本地图片不存在")

msg = MIMEMultipart("related")

image_name = "demo"

with open(fp, "rb") as rf:

mime_image = MIMEImage(rf.read())

# 注意: 一定需要<>括号

mime_image.add_header("Content-ID", "" % image_name)

msg.attach(mime_image)

# 渲染邮件文本内容

text = tpl.render(image_name=image_name)

msg_alternative = MIMEMultipart("alternative")

msg_alternative.attach(MIMEText(text, "html", "utf-8"))

msg.attach(msg_alternative)

return msg

如果你使用过python的web框架,你对文本的渲染一定不陌生,因为大多数web框架都支持文本渲染,这里使用的jinja2.

发送程序生成的照片

其实这里跟上面没什么区别的,唯一的区别就是是否保存在本地,既然能发送本地图片,我就先保存到本地然后再按照上面的方式不久可以了么? 首先这个方法是没有问题的,不过多了一次IO, 能在内存中解决的事为什么要放到本地呢?

这种情况主要是应对回去图片的方式是从其他接口获取到的,或者实时生成的时候。虽然很简单,但觉得说说也挺有意思的。

这里的模拟方式是假设在网上获取到了多张base64编码的图片,需要将其组合在一起,然后在不保存在本地情况下直接发送这张照片。

这个base64编码的图片已经保存在本地了,名字是demo_base64.txt

效果如下:

代码如下:

EMAIL_ONLINE_IMAGE_TEMPLATE = """

Page Title

这是一张图片

"""

def create_online_image_content():

from PIL import Image

tpl = Template(EMAIL_ONLINE_IMAGE_TEMPLATE)

fp = "demo_base64.txt"

if not path.exists(fp):

sys.exit("要发送的base64编码的图片不存在")

msg = MIMEMultipart("related")

image_name = "demo"

with open(fp, "rb") as rf:

base64_data = rf.read()

img_data = base64.b64decode(base64_data)

# 因为open方法需要一个file-like文件对象,而我们解码后的对象类型是bytes类型

# bytes类型没有文件对象的read, close方法,所以我们需要通过BytesIO对象包装一下,它会返回一个file-like文件对象

img = Image.open(BytesIO(img_data))

img_width, img_height = img.size

repeat_times = 5

# compose images

ret_img = Image.new(img.mode, (img_width, img_height * repeat_times))

for index in range(repeat_times):

ret_img.paste(img, box=(0, index * img_height))

# 因为MIMEImage需要一个bytes对象,所以们需要获取图片编码后的二进制数据而不是图片的array数据

img_bytes = BytesIO()

# 如果不指定图片格式,会因为没有文件名而报错

ret_img.save(img_bytes, "png")

mime_image = MIMEImage(img_bytes.getvalue())

# 注意: 一定需要<>括号

mime_image.add_header("Content-ID", "" % image_name)

msg.attach(mime_image)

# 渲染邮件文本内容

text = tpl.render(image_name=image_name)

msg_alternative = MIMEMultipart("alternative")

msg_alternative.attach(MIMEText(text, "html", "utf-8"))

msg.attach(msg_alternative)

return msg

这里很有意思一点是用BytesIO模拟file-like对象。这里需要安装PIL哦

发送一个带样式的静态网页

前面的代码已经足够说明图片怎么发了,这里通过一个写了css样式的表格进行演示

效果如下:

代码如下:

EMAIL_TEMPLATE = """

table

{

border-collapse: collapse;

margin: 0 auto;

text-align: center;

}

table td, table th

{

border: 1px solid #cad9ea;

color: #666;

height: 30px;

}

table thead th

{

background-color: #CCE8EB;

width: 100px;

}

table tr:nth-child(odd)

{

background: #fff;

}

table tr:nth-child(even)

{

background: #F5FAFA;

}

一共有以下{{record_size}}条数据

{% for label in labels %}

{{label}}

{% endfor %}

{% for item in items %}

{% for value in item %}

{{value}}

{% endfor %}

{% endfor %}

"""

def create_html_content():

tpl = Template(EMAIL_TEMPLATE)

record_size = 10

label_size = 5

labels = ["label-%s" % i for i in range(label_size)]

items = []

for _ in range(record_size):

item = ["item-%s" % value_index for value_index in range(label_size)]

items.append(item)

text = tpl.render(record_size=record_size, items=items, labels=labels)

msg = MIMEText(text, "html", "utf-8")

return msg

源代码地址

如果期待后续文章可以关注我的微信公众号(又耳笔记),头条号(又耳笔记),github.

后记

其实发送一个附件也是不错的方式,比如发送一个生成的PDF, PDF是一个很棒的文件格式。但是PDF暂时没用到,以后有机会再说吧。最后要注意的是,手机端的显示效果跟电脑网页版的显示效果是不一样的。

参考链接

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/486249.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

evalin matlab,求解MATLAB问题

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼这个是代码&#xff1a;syms x y z[deltafd]xlsread(附件2.xls,FDOA,B2:B290);[x1]xlsread(附件3.xls,主星星历,B2:B290);[x2]xlsread(附件3.xls,邻星星历,B2:B290);[y1]xlsread(附件3.xls,主星星历,C2:C290);[y2]xlsread(附件3.xl…

从源码的角度再看 React JS 中的 setState

在这一篇文章中&#xff0c;我们从源码的角度再次理解下 setState 的更新机制&#xff0c;供深入研究学习之用。 在上一篇手记「深入理解 React JS 中的 setState」中&#xff0c;我们简单地理解了 React 中 setState “诡异”表现的原因。 源码的部分为了保证格式显示正常就截…

科普|深度解析5G与未来天线技术

来源&#xff1a;电子万花筒过去二十年&#xff0c;我们见证了移动通信从1G到4G LTE的转变。在这期间&#xff0c;通信的关键技术在发生变化&#xff0c;处理的信息量成倍增长。而天线&#xff0c;是实现这一跨越式提升不可或缺的组件。按照业界的定义&#xff0c;天线是一种变…

python的百分号和斜杠 除_关于python:如何替换除字母,数字,正斜杠和反斜杠之外的所有字符...

想要解析文本并仅返回字母&#xff0c;数字&#xff0c;正斜杠和反斜杠&#xff0c;并用替换所有其他斜杠。是否可以仅使用一种正则表达式模式&#xff0c;而不是随后需要循环的几种正则表达式模式&#xff1f; 无法获取下面的样式&#xff0c;不能替换正斜杠。line1 "1/R…

php-curl-class,一个简单PHP CURL类

这里要说明一下...这个类的形成是参考了晚上前辈们的代码加上我自己的理解见解而集成的...前辈们的代码出处已经忘记了我在这里感谢这些前辈们给我的启发...希望这个类能给大家带来帮助...如果有不足的地方...请大家多多指点指点这是一个PHP CURL的类public $cookieFile; …

input输入数字验证

function clearNoNum(obj){obj.value obj.value.replace(/[^\d.]/g,""); //清除“数字”和“.”以外的字符obj.value obj.value.replace(/\.{2,}/g,"."); //只保留第一个. 清除多余的obj.value obj.value.replace(".","$#$").repl…

平行进化论再添证据 牙形刺远隔千里却发育模式相同

来源&#xff1a;科技日报记者&#xff1a;聂翠蓉平行进化观点认为&#xff0c;具有共同祖先的有机体即使彼此被分隔在相距千里的不同地域&#xff0c;也会以同样的方式进化。据物理学家组织网11月23日报道&#xff0c;德国爱尔兰根-纽伦堡大学和加拿大卡尔加里大学的古生物学家…

word光标一直闪动_6个一分钟就能学会的Word实用小技巧,你会几个?【Word教程】...

点击图片 1元抢购 Excel、Word、PPT全套课程你用word有几年了&#xff1f;一年、两年、三年......甚至更久&#xff1f;我相信你应该也是曾受到Word折磨的人吧&#xff01;为什么&#xff1f;因为曾有很多人都不知道Word的一些小技巧&#xff0c;因此工作上浪费了不少时间。于…

timewait php,timewait是什么意思

一、IME_WAIT的意思是结束了这次连接。二、以tcp中time_wait状态为例如下&#xff1a;1、简单来说&#xff1a;time_wait状态是四次挥手中server向client发送FIN终止连接后进入的状态。2、从上图能够看到time_wait状态存在于client收到serverFin并返回ack包时的状态 &#xff0…

DARPA新局长维多利亚·科尔曼展望未来发展

来源&#xff1a;空天防务观察2020年11月20日&#xff0c;美空军协会《空军杂志》网站报道称&#xff0c;在入主美国防部国防高级研究计划局&#xff08;DARPA&#xff09;之前&#xff0c;新任局长维多利亚科尔曼&#xff08;Victoria Coleman&#xff09;大多数职业生涯都在五…

死磕JDK源码之String

String本质是对char数组的封装 Serializable接口 实现Serializable接口的类可以被序列化 Comparable接口 实现Comparable接口的类可以支持排序&#xff0c;需要重写的compareTo方法返回两个字符串中第一个不同的字符的ASCII码差值 CharSequence接口 多态&#xff0c;String、St…

一个神奇的测试_这4个在线黑科技工具拥有神奇的魔法,值得收藏!

本期神器妹分享4个超实用在线黑科技工具&#xff0c;其典型特点就是无需安装任何软件&#xff0c;打开网址就可以使用&#xff0c;另外就是个个都有其独到之处&#xff0c;用起来也很爽。下面来详细介绍这4个工具&#xff1a;2.万能命令这是一个神奇的在线工具效率平台&#xf…

php task todolist,Todolist--(4)登录

login.php登录页面session_start();$dbcmysqli_connect(127.0.0.1, root,123456,todolist)or die(could not connect to mysql);mysqli_set_charset($dbc,utf8);$errorarray();if($_SERVER[REQUEST_METHOD]POST){if(!empty($_POST[username])){$username$_POST[username];}else…

量子纠缠背后的故事(廿五):深藏幕后的神秘力量

来源&#xff1a;程鹗科学网博客。链接地址&#xff1a;http://blog.sciencenet.cn/blog-3299525-1259740.html 还只有四五岁时&#xff0c;爱因斯坦有次生病&#xff0c;父亲给了他一个指南针玩耍。小小的爱因斯坦立刻着了迷。成年后&#xff0c;他多次回顾那次经历&#xff0…

Python day7之mysql

写在前面&#xff1a; 由于毕业论文撰写和答辩耽搁了几个月&#xff0c;但是在这几个月没有放弃学习Python&#xff0c;就是没有时间写博客。进行我们主要对数据库mysql的操作指令集的学习。 一、mysql术语 Mysql是最流行的关系型数据库管理系统&#xff0c;接下来介绍术语。 数…

vuerouter传参方式_VUE Router学习原理(一)

点击蓝字 关注我们Vue Router一. 安装二. 导入三. 说明四. 使用4.1 静态页面跳转4.2 动态页面跳转4.3 子路由4.4 通过程序传参4.5 同时(同级)展示多个视图4.6 导航钩子壹安装shellcnpm i vue-router -S贰导入jsimport Vue from vue;import VueRouter from vue-router;Vue.use(V…

php为图片添加渐变背景,HTML_CSS实例:通过定义渐变边框给图片加阴影,一般我们可以使用背景图的方 - phpStudy...

CSS实例:通过定义渐变边框给图片加阴影一般我们可以使用背景图的方式给图片添加阴影&#xff0c;但对于不固定尺寸的图片如何实现呢&#xff1f;我们可以采取“视觉欺骗大法”——定义渐变边框来实现代码&#xff1a;body {background:#2e334d;}img {border:none;}a.pic-shadow…

Nature:新聘“诺奖级泰斗”研究揭示大脑中执行不同认知功能环路之间的协同作用

| 中科院神经所官网报道大脑的一个核心功能是创造和保留外部世界的内在表征并指导行为&#xff0c;记忆&#xff08;Memory&#xff09;一词指的就是这种 "保留"。传统来说&#xff0c;人们认为记忆包括三个主要过程&#xff1a;编码&#xff08;Encoding&#xff09…

Java基础11-封装(思想、访问权限、this、构造方法)

一、什么是封装呢&#xff1f; 封装是面向对象的三大特征之一。 隐藏对象的属性和实现细节&#xff0c;仅对外提供公共的访问方式。 ①封装就是将面对对象的状态和行为看成是一个整体&#xff0c;将二者存放在一个独立的模块中&#xff0c;比如说类 ②封装也是信息隐藏&#xf…

值对于 int32 太大或太小_怎样将视频文件变小却对画质没有太大影响呢?

不管是我们平时没事儿时喜欢追的电视剧&#xff0c;电影&#xff0c;还是自己拍的视频&#xff0c;我们经常会遇到一个问题&#xff0c;就是视频文件太大&#xff0c;导致想要将好看好玩的视频传到手机上时&#xff0c;上传时间太长&#xff0c;而且有的时候可能上传了一半却又…