python实现电子邮件附件指定时间段,批量下载以及C#小程序集成实现
目录
一、需求背景
二、需求分析
三、需求实现
3.1 python邮箱附件指定时间下载
3.2 python外部传参
3.3 C#界面设计
四、功能实现
4.1 邮箱设置
4.2 邮件附件下载实现
1、依赖的模块
2、核心代码
3、其他
4、异常处理
5、python代码调用测试
4.3 C#内部代码实现
1、保存路径中“选择路径”
2、运行结束后清空控件中输入的数据
3、各控件内容判断和处理
4、C#调用外部多参数的exe
五、问题或求教
5.1 超大附件无法下载问题
5.2 C#调用exe代码中的弊端
5.3 C#程序运行依赖.NET环境
六、结语
参考:
一、需求背景
由于女朋友做助教,每周需要通过邮箱收数学作业,一个班五十几号人给她发送邮件,一个一个的点击下载非常耗时。所以想使用程序实现一下附件下载功能。
根据网上相关资料,使用python实现邮箱附件批量下载,然后打包生成exe后,虽是脱离了python环境便于她使用,可对于她们这些没有接触编程的人员来说,cmd命令行调用exe的操作不便于理解和操作。为此,界面化程序开发选择了C#,从而实现了C#调用python开发的exe来完成邮箱附件批量下载功能。
二、需求分析
1、指定时间的附件下载:因为作业的收发是每周都要进行的,不可每次邮件全部下载,需要指定起始和终止日期来接收一段时间内的邮箱附件;
2、基于界面化的操作,特别涉及邮箱登录等用户名、密码等信息,需要外部参数传参操作,即python核心代码中的参数输入需要留下外部接口;
3、C#界面开发,需要提供基础的参数入口:邮箱类型、邮箱账号、密码、保存路径、起止时间;
三、需求实现
3.1 python邮箱附件指定时间下载
该部分需要在邮件遍历过程中,设置起止时间根据邮件的接收时间来判断是否下载当前邮件内附件(参考[1]):
# 解析邮件:msg = Parser().parsestr(msg_content)# 获取邮件日期,格式化收件时间date = time.strptime(msg.get('Date')[:24], '%a, %d %b %Y %H:%M:%S')date = time.strftime('%Y%m%d', date)#邮件时间格式转换# 只下载发送日期在start_date 到end_date 之间的邮件附件if date < start_date :breakif date > end_date :continue
3.2 python外部传参
结合需求3,需要在邮件附件下载代码中实现外部参数的传入,传入数量为邮箱账号、密码、保存路径、起止时间和邮箱类型(参考[2]):
import sys#------------------------------------------------------------------
arg1 = sys.argv[1]
arg2 = sys.argv[2]
arg3 = sys.argv[3]
arg4 = sys.argv[4]
arg5 = sys.argv[5]
arg6 = sys.argv[6] host = "pop."+arg6 #163.com"
#host = "pop.163.com" # 邮箱域名,其他邮箱类似
server = poplib.POP3(host) # 建立链接
username = arg1 # 用户名#"xxxxxxx@163.com"
password = arg2 # 密码IMAP/SMTP的密码#"AAAAAAAAAAAAAAAA"
start_date = arg4 #起始时间#'20210929'
end_date = arg5 #终止时间#'20211008'
# 设置储存路径
mail_att_dir = arg3 #r'D:\att_file'
3.3 C#界面设计
提供基础的参数入口:邮箱类型、邮箱账号、密码、保存路径、起止时间
四、功能实现
4.1 邮箱设置
在实现邮件附件下载功能之前,首先需要开启邮箱的pop协议,一般在设置里,以163邮箱为例,设置后会给个密码,这个就是程序访问邮箱的登录密码:
邮箱内测试邮件:
4.2 邮件附件下载实现
1、依赖的模块
import email
import os
import poplib
import time
from email.header import decode_header
from email.parser import Parser
from email.utils import parseaddr
import sys
2、核心代码
python遍历邮件批量下载指定时间段的邮件附件代码(参考[1、3]):
def decode_str(s):"""字符编码转换"""value, charset = decode_header(s)[0]if charset:value = value.decode(charset)return value# 登录
server.user(username)
server.pass_(password)
resp, mails, octets = server.list() #获取所有邮件编号,mails的格式为['mesg_num octets', ...]# 倒序遍历邮件
index = len(mails)
for i in range(index, 0, -1):# lines存储了邮件的原始文本的每一行resp, lines, octets = server.retr(i)# 邮件的原始文本:msg_content = b'\r\n'.join(lines).decode('utf-8') #⭐# 解析邮件:msg = Parser().parsestr(msg_content)# 获取邮件日期,格式化收件时间date = time.strptime(msg.get('Date')[:24], '%a, %d %b %Y %H:%M:%S')date = time.strftime('%Y%m%d', date)#邮件时间格式转换# 只下载发送日期在arg1到arg2之间的邮件附件if date < start_date :breakif date > end_date :continue# 下载附件attachment_files = []for part in msg.walk():file_name = part.get_filename() # 获取附件名称类型contType = part.get_content_type()if file_name:h = email.header.Header(file_name)dh = email.header.decode_header(h) # 对附件名称进行解码filename = dh[0][0]if dh[0][1]:filename = decode_str(str(filename, dh[0][1])) # 将附件名称可读化data = part.get_payload(decode=True) # 下载附件# 创建附件存储文件夹if not os.path.isdir(mail_att_dir ):os.mkdir(mail_att_dir )# 在指定目录下创建文件,注意二进制文件需要用wb模式打开att_file = open(mail_att_dir + os.sep + filename, 'wb')attachment_files.append(filename)att_file.write(data) # 保存附件att_file.close()
server.quit()
3、其他
若需要获取邮件其他信息可以在循环中添加(参考[3-1]):
#获取邮件的发件人,收件人, 抄送人,主题# hdr, addr = parseaddr(msg.get('From'))# From = self.decode_str(hdr)# hdr, addr = parseaddr(msg.get('To'))# To = self.decode_str(hdr)# 方法2:from or Form均可From = parseaddr(msg.get('from'))[1]To = parseaddr(msg.get('To'))[1]Cc = parseaddr(msg.get_all('Cc'))[1] # 抄送人Subject = decode_str(msg.get('Subject'))print('from:%s,to:%s,Cc:%s,subject:%s'%(From,To,Cc,Subject))
这一块还有很多的功能或者细节可以完善(比如函数封装等等),具体的可以自己研究。
4、异常处理
对于有的同学,复制粘贴过去的代码,提示报错TabError: inconsistent use of tabs and spaces in indentation:参考[4-1],主要是代码中应该为空的缩进而没有为空,具体自己重新检查一下。
对于在遍历下载中有可能出现UnicodeDecodeError: 'utf-8' codec can't decode byte..报错,参考[4-2],具体解决将代码中注释为⭐的一行代码如下修改(加上‘ignore’参数):
#修改字符集参数,一般这种情况出现得较多是在国标码(GBK)和utf8之间选择出现了问题。
#出现异常报错UnicodeDecodeError是由于设置了decode()方法的第二个参数errors为严格(strict)形式造成的,因为默认就是这个参数,将其更改为ignore等即可。
msg_content = b'\r\n'.join(lines).decode('utf-8','ignore')
5、python代码调用测试
以上编写后的.py文件在python中的调用测试情况:
如此,则可以将其打包成exe,这个主要参考[2],通过Pyinstaller -F py_word.p打包成exe。
4.3 C#内部代码实现
根据需求设计出界面后,则需要代码实现内部相关的功能。
1、保存路径中“选择路径”
效果如下:
因为保存路径需要输入绝对路径,那么路径太长的时候,手动输入还是比较麻烦,直接点击按钮“选择路径”,会弹出窗口,然后自己选择本机中对应的路径文件夹,然后该路径同时显示在textbox中。
实现代码(参考[5]):
/// <summary>/// 对话框形式选择文件夹路径/// </summary>/// <returns>返回所选择的文件夹路径</returns>public string ChooseFolderPath(){FolderBrowserDialog fbd = new FolderBrowserDialog();fbd.RootFolder = System.Environment.SpecialFolder.Desktop;fbd.ShowNewFolderButton = true;fbd.Description = "请选择目录";if (fbd.ShowDialog() == DialogResult.OK){return fbd.SelectedPath.ToString();}else{return "";}}//点击事件调用private void button3_Click(object sender, EventArgs e){string path;if ((path = ChooseFolderPath()) == ""){//do nothing}else{textBox3.Text = path;}}
2、运行结束后清空控件中输入的数据
这个主要代码(参考[6]):
private void ClearAllTxt()
{foreach (Control ctr in splitContainer1.Panel1.Controls){if (ctr is TextBox){TextBox tb = ctr as TextBox;tb.Text = string.Empty;//ctr.Text = "";}if (ctr is ComboBox){ComboBox cob = ctr as ComboBox;cob.SelectedIndex = -1;}}
}
3、各控件内容判断和处理
各个textbox控件输入信息的判断和处理,包括空值的警告和报错,然后主要的是邮箱账号和邮箱类型的处理与判断,这给用户有很大的便捷。输入账户不带邮箱后缀,将会代码自动补全,另外检查选择的邮箱类型和输入账户邮箱类型是否一致。主要代码:
if (textBox1.Text == ""){MessageBox.Show("邮箱账号不能为空,请输入需要批量下载附件的邮箱账号!", "错误信息", MessageBoxButtons.OK, MessageBoxIcon.Information);return;}string UserName = "";string emailtype = "";string typeEmail = textBox1.Text;//C#中字符串处理后需要再次赋值的,否则不改变int index = typeEmail.IndexOf("@");//检索用户名@后面的字符,获取输入的邮箱类型int len = typeEmail.Length;if(index == -1)//用户名未带邮箱类型{if (comboBox1.Text == ""){MessageBox.Show("未输入邮箱类型,请手动输入或选择!", "错误信息", MessageBoxButtons.OK, MessageBoxIcon.Information);return;}else{UserName = textBox1.Text + "@" + comboBox1.Text;emailtype = comboBox1.Text;}}else{typeEmail = typeEmail.Substring(index+1);//取后面的邮箱类型//typeEmail = typeEmail.Remove(0,index+1);//取后面的邮箱类型 if (comboBox1.Text == ""){//以手动输入为准UserName = textBox1.Text;emailtype = typeEmail;}else{if (typeEmail.Equals(comboBox1.Text)){emailtype = comboBox1.Text;//正确一致}else{MessageBox.Show("选择和手动输入的邮箱类型不一致,请检查!", "错误信息", MessageBoxButtons.OK, MessageBoxIcon.Information);return;}} }
这里面主要涉及了字符串的处理(截取,比较等),参考[7、8]。
4、C#调用外部多参数的exe
主要参考[9],代码为:
string str = Environment.CurrentDirectory;//当前路径的字符串
string exePath = str + @"\GetEmailfile.exe";//这样写的弊端是需将执行的exe文件存放至界面开发的同目录下,命名也是固定的
//调用exe文件
string[] the_args = { UserName, PassWord, FilePath, StarDay, EndDay, emailtype }; // 被调exe接受的参数
StartProcess(exePath, the_args);
这里面存在一定的弊端:需将执行的exe文件存放至界面开发的同目录下,命名也是固定的,大家有什么好的解决方法也可在评论区告知。
五、问题或求教
5.1 超大附件无法下载问题
因为邮件发送形式多样有附件和超大附件等,很多同学发送大文件也必须发送超大附件。特别是其他类型邮箱之间互发送超大附件还要跳转。
在这样情况下,大批量的邮件中如果有同学通过邮箱发送了超大附件该怎么一起下载下来呢?我测试发现以上方法不能下载超大附件,只能下载邮件附件呀。有了解的朋友可以写在评论区呀。
5.2 C#调用exe代码中的弊端
根据我写的代码可以发现调用exe需要与开发的GetEmailFileApp.exe放在一个目录下,即需将执行的exe文件存放至界面开发的同目录下,GetEmailfile.exe命名也必须固定的。大家有什么好的解决方法也可在评论区告知。
5.3 C#程序运行依赖.NET环境
通常情况下,运行C#程序,需要系统安装.NET 框架,为此生成Release版本的exe后,交给别人使用,需要他人电脑上有.NET环境,这个查过一些资料似乎没有特别有效的解决方法,除了安装环境,另外参考[10](需要携带飞信文件夹)。
六、结语
基于上述功能的实现,最终这个小程序的核心也就完成了,细枝末节看个人添加,譬如我就在右边加上了软件参数输入提示,Help内有版本等开发信息等。有兴趣的小伙伴也可以自己练练手,我也将该资源进行了上传,有需要的小伙伴可自己下载。
批量下载电子邮件工程代码.rar-Python文档类资源-CSDN文库https://download.csdn.net/download/nanke_yh/60227439
参考:
[1]python指定时间邮件附件下载:python 批量下载指定时间段的邮箱附件_沈帅杰的博客-CSDN博客
[2]python外部传参和打包:python 外部传参程序编写并打包exe及其调用方式_nanke_yh的博客-CSDN博客
[3]python实现邮件附件下载:[506]python实现邮件接收、附件下载_周小董-CSDN博客_python下载邮件附件
python批量下载邮件附件 - 臭咸鱼 - 博客园 (cnblogs.com)
python实现邮件接收、附件下载操作_u012209894的专栏-CSDN博客
[4]python异常解决:
Python中常出现TabError: inconsistent use of tabs and spaces in indentation错误解决方法_糖糖的唐的博客-CSDN博客Python3解决UnicodeDecodeError: 'utf-8' codec can't decode byte..问题 终极解决方案_技术笔记-CSDN博客
[5]C#窗口形式打开文件路径:C#winForm窗体,以窗口对话形式选择文件夹、文件路径_iceberg的专栏-CSDN博客
[6]控件数据清空:C#小程序执行后及时清空控件中的数据_nanke_yh的博客-CSDN博客
【C#】一次性清空textbox、combobox中所有的内容_李光 未来科技-CSDN博客_c#清空textbox内容
[7]C#字符串截取:C#字符串的截取函数用法总结_C#教程_脚本之家 (jb51.net)
[8]C#字符串操作:c#中字符串操作函数 - 张@天 - 博客园 (cnblogs.com)
[9]C#调用exe:C# 调用外部exe,且带参数_nanke_yh的博客-CSDN博客
[10]C#程序.NET环境问题:C#程序不用安装.NET环境运行(让C#程序脱离.net框架) - 郑文亮 - 博客园 (cnblogs.com)
python实现电子邮件附件指定时间段,批量下载以及C#小程序集成实现相关推荐
- Python 之谷歌瓦片地图影像批量下载
Python 之谷歌瓦片地图影像批量下载 最近在写毕业论文,想用谷歌影像作为底图来展示研究区,然后 Google 了很多脚本,结果发现输出的影像都不带空间坐标系,所以就想自己写个小工具,通过输入空间范 ...
- 在日常生活中,经常会遇到某些需求对文件名称进行修改,借助刚学过的文件操作,编写一个可以批量修改文件名的小程序。
在日常生活中,经常会遇到某些需求对文件名称进行修改,借助刚学过的文件操作,编写一个可以批量修改文件名的小程序. import os path=input('请输入文件路径(结尾加上/):') #获取该 ...
- 中文汉字注音,汉字转拼音,支持图片识别文字,支持结果转图下载,附上小程序核心源码
"文字注音"小程序在微信.字节跳动.支付宝.QQ等小程序平台同步上线,微信.头条.抖音.支付宝.QQ中搜索"文字注音"即可获得. 一.功能 汉字转拼音,支持图片 ...
- @所有人,官网下载的微信小程序开发工具安装后黑屏咋办?
@所有人,官网下载的微信小程序开发工具安装后黑屏咋办? 一直这样,重复安装也是这样 欢迎使用Markdown编辑器 你好! 这是你第一次使用 Markdown编辑器 所展示的欢迎页.如果你想学习如何使 ...
- 文件文档ppt资料付费VIP会员下载流量主小程序开发
文件文档ppt资料付费VIP会员下载流量主小程序开发 支持格式// 支持包含pptx/ppt/ doc/ docx/xsl/xslx/ pdf/zip/rar/网盘等9种格式;并支持6种格式;WORD ...
- Python爬虫系列之爬取某社区团微信小程序店铺商品数据
Python爬虫系列之爬取某社区团微信小程序店铺商品数据 如有问题QQ请> 点击这里联系我们 < 微信请扫描下方二维码 代码仅供学习交流,请勿用于非法用途 数据库仅用于去重使用,数据主要存 ...
- 利用Python调用ECMWF欧洲中心API批量下载数据
前段时间由于需要下载ECMWF(欧洲中期天气预报中心)的再分析数据,学习了如何利用Python调用ECMWF欧洲中心API进行批量下载.这种下载ECMWF数据的方法在官网上有非常详细的介绍.我只是对这 ...
- Python+IDM实现百度网盘批量下载
最近发现了一个Tampermonkey脚本,用来下载百度网盘能达到几十MB/s,然而不能批量下载(比如几十集的电视剧),于是借用爬虫知识,利用Python+Selenium批量调用此脚本获得直链,并在 ...
- img绝对路径图片显示_使用python爬虫去风景图片网站批量下载图片
使用python爬虫(requests,BeautifulSoup)去风景图片网站批量下载图片 1.写代码背景: 今天闲来无事,想弄点图片放到电脑,方便以后使用,故去百度查找一些风景图片网站,发现图片 ...
最新文章
- 宏基因组-微生物组文章目录索引(180401)
- 【目录】 软件测试全栈需要学习什么? 软件测试的各个阶段 ,软件测试学习路径,软件测试方向选择,软件测试的薪资待遇。...
- 2016年光伏系统成本将持续下降
- matlab窗函数带通滤波器,Matlab结合窗函数法设计数字带通FIR滤波器
- Flink 1.11 与 Hive 批流一体数仓实践
- java编写服务器_java编写一个简单的回射服务器
- 当包装类的要与基本类型进行比较时候 需要先将包装类降级为基本类型
- 杭电1862EXCEL排序
- 通用设备的动态DMA映射
- 如何在信用卡反欺诈检测中使用人工智能和机器学习
- gRPC python封装深度学习算法教程
- 无需拆机,Kindle 全系列 5.12.2.2 ~ 5.14.2版本如何越狱?如何安装第三方插件
- 设计模式的艺术 结构性模式之组合模式
- 基于lingo的线性回归和非线性回归
- LeetCode1359. 有效的快递序列数目
- openGL glColor3f函数颜色
- 利用SUMIF和OFFSET+MATCH进行多条件求和
- 雨阳打字通 v1.8 发布
- 怎样用Java求水仙花数和水仙花数的数量
- qt 判断ctrl键被按下_直播 | 当世界被按下暂停键,幸有阅读可慰藉