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

很多人学习python,不知道从何学起。
很多人学习python,掌握了基本语法过后,不知道在哪里寻找案例上手。
很多已经做案例的人,却不知道如何去学习更加高深的知识。
那么针对这三类人,我给大家提供一个好的学习平台,免费领取视频教程,电子书籍,以及课程的源代码!
QQ群:101677771

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

环境

虽说就发邮件这么个小事,很容易兼容 Python 2, 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 = """<html>
<head>
<title>Page Title</title>
</head>
<body>
<h3>这是一张图片</h3>
<p><img src="cid:{{image_name}}" height="112" width="200" ></p>
</body>
</html>
"""
 
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", "<%s>" % 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 = """<html>
<head>
<title>Page Title</title>
</head>
<body>
<h3>这是一张图片</h3>
<p><img src="cid:{{image_name}}" ></p>
</body>
</html>
"""
 
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", "<%s>" % 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 = """<html>
<head>
    <style type="text/css">
        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;
        }
    </style>
</head>
<body>
<p>一共有以下{{record_size}}条数据</p>
<table width="90%" class="table">
    <thead>
        <tr>
        {% for label in labels %}
            <th>{{label}}</th>
        {% endfor %}
        </tr>
    </thead>
    <tbody>
{% for item in items %}
    <tr>
    {% for value in item %}
        <td>{{value}}</td>
    {% endfor %}
    </tr>
{% endfor %}
    </tbody>
</table>
</html>"""
 
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

源代码地址

https://github.com/youerning/blog/tree/master/sendmail

用Python发一封图文并茂的邮件的更多相关文章

  1. [转]简单三步,用 Python 发邮件

    https://zhuanlan.zhihu.com/p/24180606 0. 前言 发送电子邮件是个很常见的开发需求.比如你写了个监控天气的脚本,发现第二天要下雨,或者网站上关注的某个商品降价了, ...

  2. python发邮件遇到的端口号问题

    在学习使用python发邮件的过程中, 遇到了一个问题:由于测试的时候使用的是QQ邮箱,要求必须使用SSL/TLS加密,所以有了下面的代码, from email.mime.text import M ...

  3. 使用python发邮件

    使用python发邮件 网上有很多发邮件的例子,本人在网上找了一份,稍加修改后使用 上源码 # encoding=utf-8 from email.mime.image import MIMEImag ...

  4. 如何用python发邮件

    python发送各类邮件的主要方法 一.相关模块介绍 发送邮件主要用到了smtplib和email两个模块,这里首先就两个模块进行一下简单的介绍:     1.smtplib模块 smtplib.SM ...

  5. Python 发邮件例子

    Python 发邮件例子 例子 #!/usr/bin/env python # -*- coding: utf-8 -*- # @Date : 2019-04-23 16:12:33 # @Autho ...

  6. python发QQ邮件

    python发qq邮件相对比较简单,网上教程一大把:固定套路,后面封装看自己怎么方便可以怎样进行封装:原版代码如下: """ # -*- coding : utf-8 - ...

  7. Python爬虫突破封禁的6种常见方法

    转 Python爬虫突破封禁的6种常见方法 2016年08月17日 22:36:59 阅读数:37936 在互联网上进行自动数据采集(抓取)这件事和互联网存在的时间差不多一样长.今天大众好像更倾向于用 ...

  8. Python发送邮件(常见四种邮件内容)

    Python发送邮件(常见四种邮件内容) 转载 2017年03月03日 17:17:04   转自:http://lizhenliang.blog.51cto.com/7876557/1875330 ...

  9. 用DataBaseMail发图片并茂的邮件

    不知道各位的老板有没有这样的要求, 一些系统中的数据需要定时发出邮件提醒, 如呆料就要到期或者一些待办的事项提醒. 当然这些用SSRS报表订阅可以实现,但有些公司没有设定相应的报表服务,又或者只是一些 ...

随机推荐

  1. HTML与XHTML之间的区别

    HTML与XHTML之间的差别,粗略可以分为两大类比较:一个是功能上的差别,另外是书写习惯的差别.关于功能上的差别,主要是XHTML可兼容各大浏览器.手机以及PDA,并且浏览器也能快速正确地编译网页. ...

  2. JavaSwing+Mysql实现简单的登录界面+用户是否存在验证

    原生Java+mysql登录验证 client login.java 功能:实现登录页面,与服务端传来的数据验证 package LoginRegister; import java.awt.Cont ...

  3. 还分不清 Cookie、Session、Token、JWT?一篇文章讲清楚

    还分不清 Cookie.Session.Token.JWT?一篇文章讲清楚 转载来源 公众号:前端加加 作者:秋天不落叶 什么是认证(Authentication) 通俗地讲就是验证当前用户的身份,证 ...

  4. java进阶(3)--接口

    一.基本概念 1.接口为引用数据类型,编译后也是class字节码文件 2.接口是完全抽象的,(抽象类是半抽象的),属于特殊的抽象类 3.接口定义方法:[修饰符列表]interface 接口名{} 4. ...

  5. 【HEOI2015】公约数数列 题解(分块)

    前言:毒瘤数据结构题,半个下午都在搞它了…… --------------------------- 题目链接 题目大意:给定一个长度为$n$的序列,有两种操作:1.把$a_x$的值改成$y$.2.求 ...

  6. 【转载-学习】[一个前端必会的 Nginx免费教程 - 技术胖]

    本文学习资料:https://www.jspang.com/detailed?id=39 Nginx官网:https://www.nginx.com/ Nginx:轻量级HTTP服务器: 采用事件驱动 ...

  7. java web Session会话技术(原理图解+功能+与Cookie的区别+基本使用)

    java web Session会话技术(原理图解+功能+与Cookie的区别+基本使用) 这是我关于会话技术的第二篇文章,对 Cookie有不了解的兄弟可以点击下方的Cookie跳转 Cookie链 ...

  8. JS 鼠标、键盘事件对象

    鼠标事件对象     mouseEvent鼠标事件对象     e.clientX 在可视区的x和y的坐标     e.pageX 在页面文档的X和Y的坐标 <script> docume ...

  9. 正确认识springcloud的作用。分布式从了解架构到springcloud支撑

    转载于 https://www.cnblogs.com/williamjie/p/9369681.html 基于springCloud的分布式架构体系   Spring Cloud作为一套微服务治理的 ...

  10. java 用集合完成随机点名器和库存管理案例

    一 随机点名器 1.案例需求 随机点名器,即在全班同学中随机的找出一名同学,打印这名同学的个人信息. 我们来完成随机点名器,它具备以下3个内容: 存储所有同学姓名 总览全班同学姓名 随机点名其中一人, ...