整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

进阶Python邮件发送(三)-HTML邮件与附件

亲爱的读者,我们已经成功地发送了简单的文本邮件。但在实际应用中,我们可能还需要发送格式更加丰富的HTML邮件,或者包含附件的邮件。今天,我们就来探索如何使用Python来构建并发送这样的邮件。

一、发送HTML邮件

HTML邮件可以让你的邮件内容更加丰富多彩,包含图片、链接、样式等。在Python中,我们同样可以使用email模块来构建HTML邮件。

from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText

# HTML邮件正文内容
html_content = """
<html>
<head></head>
<body>
    <h1>Hello, this is an HTML email from Python!</h1>
    <p>Here's a <a href="https://www.python.org">link to Python's website</a>.</p>
    <img src="cid:image1">  <!-- 注意:这里使用了cid引用,稍后我们将添加图片附件 -->
</body>
</html>
"""

# 创建一个多部分邮件对象
msg = MIMEMultipart('related')
msg['From'] = 'your_email@gmail.com'
msg['To'] = 'receiver_email@example.com'
msg['Subject'] = 'HTML Email with Python'

# 添加HTML邮件正文
msg_alternative = MIMEMultipart('alternative')
msg.attach(msg_alternative)
html_part = MIMEText(html_content, 'html', 'utf-8')
msg_alternative.attach(html_part)

# (可选)添加图片附件(这里仅为示例,实际发送时请确保图片文件存在)
# 注意:由于示例中HTML中引用了图片,我们需要在邮件中添加这个图片作为附件,并使用cid引用
# 这里为了简化,我们略过实际文件读取和添加的过程,仅展示逻辑
# ... 添加图片附件的代码会涉及到打开文件、读取内容、创建MIMEImage对象,并设置Content-ID为"image1"

# 发送邮件(假设SMTP连接和登录已经完成)
# ... 使用smtplib发送msg对象,与之前的示例类似

注意:上面的代码示例中,关于添加图片附件的部分被省略了,因为它涉及到文件I/O操作和MIMEImage对象的使用,这可能会让示例变得复杂。在实际应用中,你需要读取图片文件,创建MIMEImage对象,并将其附加到邮件中,同时确保HTML中的<img>标签通过cid属性正确引用该图片。

二、发送带附件的邮件

发送带附件的邮件与发送HTML邮件类似,但你需要创建一个多部分邮件(MIMEMultipart),并为每个部分(文本、HTML、附件等)设置不同的MIME类型。

from email.mime.base import MIMEBase
from email import encoders

# 假设我们要发送一个名为"example.txt"的文本文件作为附件
filename = 'example.txt'

# 读取文件内容并编码为base64
with open(filename, 'rb') as attachment:
    part = MIMEBase('application', 'octet-stream')
    part.set_payload((attachment).read())
encoders.encode_base64(part)

# 添加文件头信息
part.add_header('Content-Disposition', "attachment; filename= %s" % filename)

# 将附件添加到邮件中
msg.attach(part)

# 现在,msg对象包含了文本(或HTML)和附件,你可以使用smtplib发送它
# ... 发送邮件的代码与之前相同

结语

恭喜你,现在你已经掌握了使用Python发送文本邮件、HTML邮件以及带附件邮件的技能!这些技能将帮助你在自动化任务、通知系统或任何需要邮件通信的应用程序中大展拳脚。记得在实践中不断探索和尝试,你会发现Python在邮件处理方面的更多可能性。

文为霍格沃兹测试开发学社学员学习笔记分享

原文链接:allure2报告中添加附件-html、视频 L3 - 学习笔记 - 测试人社区

1、Allure2 报告中添加附件-html

Allure2 报告中添加附件(html)应用场景

  • 应用场景:可以定制测试报告页面效果,可以将 HTML 类型的附件显示在报告页面上。
  • 解决方案:
    • Python:使用 allure.attach() 添加 html 代码。
    • Java:直接通过注解或调用方法添加。

Allure2 报告中添加附件(html)- Python

  • 语法:allure.attach(body, name, attachment_type, extension),参数解释:
    • body:要写入附件的内容(HTML 代码块)。
    • name:附件名字。
    • attachment_type:附件类型,是 allure.attachment_type 其中的一种。
    • extension:附件的扩展名。
class TestWithAttach:
    def test_html(self):
        allure.attach('<head></head><body> a page </body>',
                      '附件是HTML类型',
                      allure.attachment_type.HTML)
                      
    def test_html_part(self):
        allure.attach('''html代码块''',
                      '附件是HTML类型',
                      allure.attachment_type.HTML)
import allure

from utils.log_util import logger


class TestAllureHtml:
    def test_html_part(self):
        logger.info("这是添加一个 html 部分代码的测试用例")
        allure.attach("""
        <a href="/" data-auto-route="true"><img src="https://ceshiren.com/uploads/default/original/1X/809c63f904a37bc0c6f029bbaf4903c27f03ea8a.png" alt="测试人社区" id="site-logo" class="logo-big"></a>""", name="添加html片段", attachment_type=allure.attachment_type.HTML, extension="html")

    def test_html_whole(self):
        logger.info("这是添加一个 html 完整代码的测试用例")
        allure.attach("""........""",
                      name="添加html片段", attachment_type=allure.attachment_type.HTML, extension="html")

Allure2 报告中添加附件(html) - Java

Allure 支持两种方法: - 注解方式添加。

  • 调用方法添加。

注解方式 - Java

  • 直接传入html文件。
@Attachment(value = "html名", type = "text/html", fileExtension = "后缀")

调用方法添加 - Java

  • 使用Allure方法传入html。
Allure.addAttachment("html名", "text/html",
      图片路径, "后缀");

2、Allure2 报告中添加附件-视频

Allure2 报告中添加附件(视频)应用场景

  • 应用场景:在做 UI 自动化测试时,可以将页面截图,或者出错的页面进行截图,将截图添加到测试报告中展示,辅助定位问题。
  • 解决方案:
    • Python:使用 allure.attach.file() 添加视频。
    • Java:直接通过注解或调用方法添加。

Allure2 报告中添加视频附件 - Python

  • 语法:allure.attach.file(source, name, attachment_type, extension),参数解释:
    • source:文件路径,相当于传一个文件。
    • name:附件名字。
    • attachment_type:附件类型,是 allure.attachment_type 其中的一种。
    • extension:附件的扩展名。
"""
@Author: 霍格沃兹测试开发学社-西西
@Desc: 更多测试开发技术探讨,请访问:https://ceshiren.com/t/topic/15860
"""
import allure

class TestWithAttach:
    def test_video(self):
        allure.attach.file("xxx.mp4",
                           name="视频",
                           attachment_type=allure.attachment_type.MP4,
                           extension="mp4")
import allure

from utils.log_util import logger


class TestWithAttach:
    def test_video(self):
        logger.info("测试用例执行过程视频")
        allure.attach.file("/Users/juanxu/Movies/Allure2安装.mp4",
                           name="这是一个mp4视频文件",
                           attachment_type=allure.attachment_type.MP4,
                           extension="mp4")

Allure2 报告中添加视频附件 - Java

Allure 支持两种方法:

  • 注解方式添加。
  • 调用方法添加。

注解方式 - Java

  • 注解方式直接传入视频。
@Attachment(value = "视频名", type = "video/mp4", fileExtension = "后缀")

调用方法添加 - Java

  • 使用Allure方法传入视频。



在前面

今年国庆假期终于可以憋在家里了不用出门了,不用出去看后脑了,真的是一种享受。这么好的光阴怎么浪费,睡觉、吃饭、打豆豆这怎么可能(耍多了也烦),完全不符合我们程序员的作风,赶紧起来把文章写完。

这篇文章比较基础,在国庆期间的业余时间写的,这几天又完善了下,力求把更多的前端所涉及到的关于文件上传的各种场景和应用都涵盖了,若有疏漏和问题还请留言斧正和补充。

自测读不读

以下是本文所涉及到的知识点,break or continue ?

  • 文件上传原理
  • 最原始的文件上传
  • 使用 koa2 作为服务端写一个文件上传接口
  • 单文件上传和上传进度
  • 多文件上传和上传进度
  • 拖拽上传
  • 剪贴板上传
  • 大文件上传之分片上传
  • 大文件上传之断点续传
  • node 端文件上传

原理概述

原理很简单,就是根据 http 协议的规范和定义,完成请求消息体的封装和消息体的解析,然后将二进制内容保存到文件。

我们都知道如果要上传一个文件,需要把 form 标签的enctype设置为multipart/form-data,同时method必须为post方法。

那么multipart/form-data表示什么呢?

multipart互联网上的混合资源,就是资源由多种元素组成,form-data表示可以使用HTML Forms 和 POST 方法上传文件,具体的定义可以参考RFC 7578。

multipart/form-data 结构

看下 http 请求的消息体



  • 请求头:

Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryDCntfiXcSkPhS4PN 表示本次请求要上传文件,其中boundary表示分隔符,如果要上传多个表单项,就要使用boundary分割,每个表单项由———XXX开始,以———XXX结尾。

  • 消息体- Form Data 部分

每一个表单项又由Content-Type和Content-Disposition组成。

Content-Disposition: form-data 为固定值,表示一个表单元素,name 表示表单元素的 名称,回车换行后面就是name的值,如果是上传文件就是文件的二进制内容。

Content-Type:表示当前的内容的 MIME 类型,是图片还是文本还是二进制数据。

解析

客户端发送请求到服务器后,服务器会收到请求的消息体,然后对消息体进行解析,解析出哪是普通表单哪些是附件。

可能大家马上能想到通过正则或者字符串处理分割出内容,不过这样是行不通的,二进制buffer转化为string,对字符串进行截取后,其索引和字符串是不一致的,所以结果就不会正确,除非上传的就是字符串。

不过一般情况下不需要自行解析,目前已经有很成熟的三方库可以使用。

至于如何解析,这个也会占用很大篇幅,后面的文章在详细说。

最原始的文件上传

使用 form 表单上传文件

在 ie时代,如果实现一个无刷新的文件上传那可是费老劲了,大部分都是用 iframe 来实现局部刷新或者使用 flash 插件来搞定,在那个时代 ie 就是最好用的浏览器(别无选择)。

DEMO



这种方式上传文件,不需要 js ,而且没有兼容问题,所有浏览器都支持,就是体验很差,导致页面刷新,页面其他数据丢失。

HTML

 <form method="post" action="http://localhost:8100" enctype="multipart/form-data">

        选择文件:
            <input type="file" name="f1"/> input 必须设置 name 属性,否则数据无法发送<br/>
<br/>
            标题:<input type="text" name="title"/><br/><br/><br/>

        <button type="submit" id="btn-0">上 传</button>

</form>

复制代码

文件上传接口

服务端文件的保存基于现有的库koa-body结合 koa2实现服务端文件的保存和数据的返回。

在项目开发中,文件上传本身和业务无关,代码基本上都可通用。

在这里我们使用koa-body库来实现解析和文件的保存。

koa-body 会自动保存文件到系统临时目录下,也可以指定保存的文件路径。



然后在后续中间件内得到已保存的文件的信息,再做二次处理。

  • ctx.request.files.f1 得到文件信息,f1为input file 标签的 name
  • 获得文件的扩展名,重命名文件

NODE

/**
 * 服务入口
 */
var http = require('http');
var koaStatic = require('koa-static');
var path = require('path');
var koaBody = require('koa-body');//文件保存库
var fs = require('fs');
var Koa = require('koa2');

var app = new Koa();
var port = process.env.PORT || '8100';

var uploadHost= `http://localhost:${port}/uploads/`;

app.use(koaBody({
    formidable: {
        //设置文件的默认保存目录,不设置则保存在系统临时目录下  os
        uploadDir: path.resolve(__dirname, '../static/uploads')
    },
    multipart: true // 开启文件上传,默认是关闭
}));

//开启静态文件访问
app.use(koaStatic(
    path.resolve(__dirname, '../static') 
));

//文件二次处理,修改名称
app.use((ctx) => {
    var file = ctx.request.files.f1;//得道文件对象
    var path = file.path;
    var fname = file.name;//原文件名称
    var nextPath = path+fname;
    if(file.size>0 && path){
        //得到扩展名
        var extArr = fname.split('.');
        var ext = extArr[extArr.length-1];
        var nextPath = path+'.'+ext;
        //重命名文件
        fs.renameSync(path, nextPath);
    }
    //以 json 形式输出上传文件地址
    ctx.body = `{
        "fileUrl":"${uploadHost}${nextPath.slice(nextPath.lastIndexOf('/')+1)}"
    }`;
});

/**
 * http server
 */
var server = http.createServer(app.callback());
server.listen(port);
console.log('demo1 server start ......   ');
复制代码

CODE

https://github.com/Bigerfe/fe-learn-code/