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

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

环境

虽说就发邮件这么个小事,很容易兼容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暂时没用到,以后有机会再说吧。最后要注意的是,手机端的显示效果跟电脑网页版的显示效果是不一样的。

参考链接

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

  1. python写机器人程序_用Python写的一个多线程机器人聊天程序

    本人是从事php开发的, 近来想通过php实现即时通讯(兼容windows).后来发现实现起来特别麻烦, 就想到python.听说这家伙在什么地方都能发挥作用.所以想用python来做通讯模块...所 ...

  2. python通过代理发送邮件_使用Python通过SMTP发送邮件

    有些业务可能由于各种各样的原因并不适用于Zabbix监控,这时如果要做到系统出问题能立即发送邮件,就需要自己来写监控脚本了,出问题要实时通过邮件报警,以下案例使用Python脚本实现通过SMTP协议发 ...

  3. python编程免费小说_使用Python开发小说下载器,不再为下载小说而发愁

    有点荒废 这几天有点荒废,之前弃坑的网文<伏天氏>,这几天又给捡起来了.然后一发不可收拾的只想看小说,荒废了我的学习.在这里我要检讨啊..... 像我这样的穷人,看小说肯定是找免费的网站, ...

  4. python朋友圈头像_用python一键生成头像墙,将你微信好友头像全部收集起来

    本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理 以下文章来源于腾讯云 作者:Python编程与实战 ( 想要学习Python?Py ...

  5. 哪些软件是python编写出来的_用Python编程需要什么软件?

    用Python编程需要什么软件?Python编程是一门适合新手入门的编程语言,现在有不少程序员业余时间学习Python编程语言,学习Python找到好工具会大大提高学习的效率.好用的Python编程软 ...

  6. 用python爬虫下载视频_使用Python编写简单网络爬虫抓取视频下载资源

    我第一次接触爬虫这东西是在今年的5月份,当时写了一个博客搜索引擎,所用到的爬虫也挺智能的,起码比电影来了这个站用到的爬虫水平高多了! 回到用Python写爬虫的话题. Python一直是我主要使用的脚 ...

  7. python训练营微信广告_当Python遇上微信,可以这么玩

    词云那里可以换成小黄人图片 -------------------------------------------------------------------------------------- ...

  8. python简历数据提取_提取python简介

    书籍:掌握Python的网络和安全 Mastering Python for Networking and Security - 2018.pdf 简介 掌握Python的网络和安全 掌握Python ...

  9. 自学python 编程基础知识_一个python编程自学者的历程以及给自学新手的一些建议...

    文章原本昨晚已经在电脑写好了,今天准备用手机润润色再发表,结果误操作给删了,又要重新码字,真是日了狗了. 由于手机码字,以下python就用py简称代替了.写之前其实也犹豫再三,一则自己编程水平实在有 ...

最新文章

  1. 算法---最长湍流子数组
  2. 模板使用自定义类型_「Shopify模板」Shopify模板编辑Shopify模板代码更改教程
  3. php 写入文件 格式,在使用php写入文件时如何保证用户的单一
  4. java银行管理系统_java实现银行管理系统
  5. linux开端口不重启,Linux 防火墙开放端口(有时不生效可能是没有保存、重启导致)...
  6. 行、重复-SAP HANA 集合操作 UNION/Union all/INTERSECT/EXCEPT (SAP HANA Set Operations)-by小雨...
  7. 移动端去掉按钮点击热区
  8. 公司的Java框架应具备的通用功能
  9. 一张思维导图,让正则表达式不再难懂
  10. 程序员双十一都该买点啥?
  11. java即时通讯源码 IM即时通讯源码 IM源码 安卓苹果原生APP源码 带音视频无标题】
  12. 3 Layer and 3 Tier
  13. keepass使用坚果云同步
  14. 央视主持人都在用的无限领夹麦克风快充方案
  15. 前端播放视频有声音没有画面
  16. vue的组件内部全局变量按照使用的前端id存储历史数据
  17. 最大数leetcode_Leetcode:最大化有效体验
  18. Cut-Off Wavelength in fiber(光纤的截止波长)
  19. 洞泾智能机器人产业基地_在全球人工智能产业版图中努力树起“G60旗帜”
  20. 特斯拉的市场策略在中国面临“失效”

热门文章

  1. SQL Server 2005远程连接连不上的解决办法收藏 Microsoft给的方法
  2. js获取元素的方法与属性
  3. RDD(弹性分布式数据集)
  4. 离散系数的计算公式_如何求不同变量之间的离散程度
  5. 忆阻器的matlab建模_忆阻器Simulink建模和图形用户界面设计.PDF
  6. python sorted下标_Python列表操作最全面总结
  7. 别再无脑wwm了!在下游任务中不一定有效!
  8. 百度飞桨弯道超车了吗?!
  9. ACL2020 | FastBERT:放飞BERT的推理速度
  10. Spring Cloud构建微服务架构:服务容错保护(Hystrix服务降级)【Dalston版】