最近研究邮件透明加密技术,需要测试imap服务,然而邮件客户端不好用所以需要自己编写代码,这里使用python编写。这里关于邮件透明加密技术,推荐天御云安的隐密邮,部署简单,不影响用户使用习惯,非常好的一款产品。网址:https://mail.tyyunan.com/
import getpass, imaplib
import time
import pickle
import email,string,sys,os
from email.header import Header
from email.header import decode_header
from time import strptime, strftime
from email.parser import Parser
import hashlib
ISOTIMEFORMAT="%Y-%m-%d %X"
#定义邮件服务器常量
IMAPSever='192.168.61.4'
IMAPPort='143'
IMAPUser='laoww@163.com'
IMAPPassword='123456'
tmp_dir='E:\\python\\'
def GetFileMd5(filename):
try:
if not os.path.isfile(filename):
return None
myhash = hashlib.md5()
f = open(filename, 'rb')
while True:
b = f.read(8096)
if not b: break
myhash.update(b)
f.close()
return myhash.hexdigest()
except :
return None
#def writelog(log):
# fn = tmp_dir + 'log.txt'
# f = open(fn, 'a+')
# f.write(log+'\n')
# f.close
def writelog(log):
f = open('E:\\log.txt', 'a+')
f.write(log+'\n')
f.close
def test_log(log):
fn = tmp_dir + 'test_log.txt'
f = open(fn, 'a+')
f.write(log)
f.close
##附件MD5映射表
#attr_md5_dic = {'c:\\tmp1\imap\\1_python.eml':'db38f30bf46982b51998acf7878586ed',
# 'c:\\tmp1\imap\\2_python.eml':'f6865b3e0e0d5592dc94c0db2c397c0c',
# 'c:\\tmp1\\imap\\3_python.eml':'a51e1fca402febe65e7a097cea299a43',
# 'c:\\tmp1\\imap\\4_python.eml':'2ecd56ec0dac8fd0742763be9c756a5f',
# 'c:\\tmp1\\imap\\5_python.eml':'9218a63c8bce5b1ff57d02deb8ba03b5',
# 'c:\\tmp1\\imap\\6_python.eml':'36e1ae8414a39f3af757a1b47d669191',
# 'c:\\tmp1\\imap\\7_python.eml':'2f34d001116515b35e2edbb79e4c229c',
# 'c:\\tmp1\\imap\\8_python.eml':'8c12c98b9062b2a1c16bedb21d554135',
# 'c:\\tmp1\\imap\\9_python.eml':'0b8ffc79c11a0dfb2f75291dfd75f29b',
# 'c:\\tmp1\\imap\\10_python.eml':'b5451f68d6cb9cec7403affd2b5157ed',
# 'c:\\tmp1\\imap\\11_python.eml':'895c22a04d6d574bbf6cdd050b9e0162',
# 'c:\\tmp1\\imap\\12_python.eml':'42bacecc8c6746a3878bfb0157e48440',
# 'c:\\tmp1\\imap\\13_python.eml':'2f7847fb47c3f94add85dcf71eebb89b',
# 'c:\\tmp1\\imap\\14_python.eml':'db3b78eae3146fb5b7c858849fb93084'
# }
#附件MD5映射表
attr_md5_dic = {'1.jpg':'7C6426E4F8CD8B12D6CDE3DFDB8F2E9F',
'1M-good.txt':'D1240F099E53AF249541AC95B7B0FA95',
'2.jpg':'B167F5EE9B7F12E615106D0DE5A194C6',
'3.jpg':'622E1A2410C21667F731FD2D5C67596F',
'4.pdf':'DCB7434FCA1034EBA641EBFEE23C7283',
'5.pdf':'5DBC1699C1C0CABE08E571654885693E',
'6.rar':'0031E302AEABD0262B0F38FA537DF0BE',
'7.docx':'3F471FC456F1917AE282022ECD6DDB5D',
'8.docx':'4684DFA7FE8B87B0181855AA095D9C9D',
'9.7z':'08C9CE615196E95475DA832E2A7C43AF',
'10.xlsx':'24895653E8D04D2F3E756964A44A274E',
'11.txt':'4973E43DB511BA94A4A4F96DC0AD161A',
'12.txt':'2F0670DA4398CFC7E04DC6D7F77F8411',
'13.txt':'D51BEB408B4829BA895B2A5F7AF10894',
'14.txt':'066F8F57FBC8F77698CDA4B72B45C129',
'15.txt':'14F4A15ABF92BF4866BE9FD8A4A00338',
'16.pdf':'451B25E4AD13B671192F4E6548C1B632',
'17.rar':'F63CEC86FF2877FAA6383C28C6F3B7EF',
'18.rar':'57555CC3B82EDD8734558372CBB50BC9',
'20180911.txt':'9B7C71319B104F5DD30545C1B1C711E4'
}
def save_file(fn, data, msdir="inbox"):
filename = tmp_dir + fn + '_' + msdir + '_python.eml'
f = open(filename, 'wb') # 注意一定要用wb来打开文件,因为附件一般都是二进制文件
f.write(data)
f.close()
#
fileMd5 = GetFileMd5(filename)
ret_str = ''
ret_str = 'FAIL'
if fileMd5 is None:
writelog("file md5 get fail =>filename:%s"%filename)
else:
#filename 是bytes类型 需要解码 才能变为字符串
if filename not in attr_md5_dic:
writelog("file not in attr_md5_dic =>filename:%s"%filename)
else:
if fileMd5 in attr_md5_dic[ filename]:
ret_str = 'OK'
#输出md5 list
f = open('E:\\imap-client\\tmp\\python\\md5_list', 'a')
t=time.strftime( ISOTIMEFORMAT, time.localtime())
#f.write("Md5 of"+ filename +"is " + fileMd5+ "\r\n")
f.write("%s Md5 of %s is %s result is %s\n"%(t, filename, fileMd5, ret_str))
#md5content = t + " Md5 of " + filename + "is" + (fileMd5)
#f.write( md5content )
f.close()
return None
#取信息编码
def get_charset(message, default="ascii"):
#Get the message charset
return message.get_charset()
return default
#解析邮件
def ParseMail(mail):
try:
textplain = ''
texthtml = ''
atta = {}
fileMd5= ''
if mail.is_multipart():
for par in mail.walk():
if not par.is_multipart(): # 这里要判断是否是multipart,是的话,里面的数据是无用的,至于为什么可以了解mime相关知识。
#name = par.get_param("name") # 如果是附件,这里就会取出附件的文件名
name = par.get_filename()
if name:
# 有附件
# 下面的三行代码只是为了解码象=?gbk?Q?=CF=E0=C6=AC.rar?=这样的文件名
#print("filename:" + filename)
h = email.header.Header(name)
dh = email.header.decode_header(h)
fname = dh[0][0]
#print(dh)
print("fname:" + fname.decode())
# print '有附件'+fname
data = par.get_payload(decode=True) # 解码出附件数据,然后存储到文件中
atta[fname] = data
try:
f = open(fname, 'wb') # 注意一定要用wb来打开文件,因为附件一般都是二进制文件
except:
print('附件名有非法字符,自动换一个' + fname.decode())
f = open('aaaa', 'wb')
f.write(data)
f.close()
fileMd5 = GetFileMd5(fname)
os.remove(fname) #del attr
if fileMd5 is None:
writelog("file md5 get fail =>fname:%s"%fname)
return (None, None, None)
else:
#fname 是bytes类型 需要解码 才能变为字符串
if fname.decode() not in attr_md5_dic:
writelog("file not in attr_md5_dic =>fname:%s"%fname.decode())
return (None, None, None)
#writelog("md5:%s md5:%s"%(fileMd5.upper() ,attr_md5_dic[ fname.decode()]) )
if fileMd5.upper() not in attr_md5_dic[ fname.decode()]:
return (None, None, None)
else:
# 不是附件,是文本内容
content_type = par.get_content_type()
charset = get_charset(par)
if content_type in ['text/plain']:
if charset == None:
textplain = par.get_payload(decode=True)
else:
textplain = par.get_payload(decode=True).decode(charset)
if content_type in ['text/html']:
if charset == None:
texthtml = par.get_payload(decode=True)
else:
texthtml = par.get_payload(decode=True).decode(charset)
else:
type = mail.get_content_charset()
if type == None:
textplain = mail.get_payload()
else:
content_type = mail.get_content_type()
charset = get_charset(mail)
if content_type in ['text/plain']:
if charset == None:
textplain = mail.get_payload(decode=True)
else:
textplain = mail.get_payload(decode=True).decode(charset)
return (textplain, texthtml, atta)
except Exception as e:
writelog("error parse mail=>"+str(e))
return (None, None, None)
def imap_get_mail_body(IMAPSever,IMAPPort,IMAPUser,IMAPPassword,BaseNum,StepNum):
#M = imaplib.IMAP4_SSL(IMAPSever, IMAPPort)
M = imaplib.IMAP4(IMAPSever, IMAPPort)
M.login(IMAPUser, IMAPPassword)
result, msg = M.select('inbox')
#print('result %s msg is %s\n' %(result, msg))
#typ, data = M.search(None, 'ALL')
#print('search result is [%s]--type is [%s]\n' %(data,typ))
#typ, maildata = M.fetch('13', '(RFC822)')
#save_file(str(int('13')), maildata[0][1])
#print('Message %s\n%s\n' %('1', maildata[0][1]))
#exit(0)
success_num = 0
fail_num = 0
#for num in data[0].split():
for num in range(BaseNum,BaseNum+StepNum):
#if( int(num) > 3 ):
# exit(0)
print('Message [%s]\n' %(str(num)))
typ, maildata = M.fetch(str(num), '(UID BODY[1])')
#print(maildata)
#save_file(str(int(num)), maildata[0][1])
mail = Parser().parsestr(maildata[0][1].decode('utf-8'))
TextContent,HTMLContent,MailAtta = ParseMail(mail)
if MailAtta != None and TextContent != None and HTMLContent != None:
success_num += 1
else:
fail_num += 1
writelog('success:%d fail:%d'% (success_num, fail_num) )
#print('Message [%s]\n[%s]\n' %(num, maildata[0][1]))
#writelog('success:%d fail:%d'% (success_num, fail_num) )
t=time.strftime( ISOTIMEFORMAT, time.localtime())
writelog('----------------imapClient.quit---------------------now time is[%s]'%t)
M.close()
M.logout()
BaseNum=1
for num in range(1,30):
imap_get_mail_body(IMAPSever,IMAPPort,IMAPUser,IMAPPassword,BaseNum,160000)
BaseNum+=5000