因为往来邮件量比较大,为了统计分析两年的变化情况,决定把邮件从Outlook读取并写入MySQL,然后通过Excel查询分析。这里分享一下完整的提取Email信息的思路和代码。
另外,如果不用数据库,也可以利用同样的思路直接保存到Excel文件,不过需要注意的是,每个单元格最多存储3.2万字符,一般也足够了。
第一步:创建数据库。
通过MySQL可视化客户端新建数据库,字符集选择utf8,字符集校对选择utf8_general_ci。
第二步:通过Python脚本创建数据表。
字段长度可以修改,需要考虑Email各种信息的不同长度,也需要注意字段类型的匹配。
比如发件人可能只需要很少字符,但邮件正文就可能几万的字符。
# -*- coding: utf-8 -*-
import pymysql
# 1.链接数据库(用户名和密码对应数据库访问user/password)
conn = pymysql.connect(
host='127.0.0.1',
port=3306,
user='xxxx',
passwd='xxxx',
db='myemail_zl',
charset='utf8')
def connect_mysql(conn):
# 判断链接是否正常
conn.ping(True)
# 建立操作游标
cursor=conn.cursor()
# 设置数据输入输出编码格式
cursor.execute('set names utf8')
return cursor
# 建立链接游标
cur=connect_mysql(conn)
# 2、添加数据库表头
# ID, 根级目录, 一级目录, 二级目录, 接收时间, 发件人, 收件人, 抄送人, 邮件主题, 邮件ID, 会话主题, 会话ID, 会话历史记录ID, 邮件内容
cur.execute('''CREATE TABLE IF NOT EXISTS email_box2 (
ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
根级目录 VARCHAR(255),
一级目录 VARCHAR(255),
二级目录 VARCHAR(255),
接收时间 VARCHAR(100),
发件人 VARCHAR(200),
收件人 VARCHAR(2550),
抄送人 VARCHAR(2550),
邮件主题 VARCHAR(255),
邮件ID VARCHAR(255),
会话主题 VARCHAR(255),
会话ID VARCHAR(255),
会话历史记录ID VARCHAR(2550),
邮件内容 MEDIUMTEXT
) DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci''')
# 3、提交&关闭链接
conn.commit()
conn.close()
print ('Done!')
第三步:打开Outlook并运行如下代码,即可把指定的邮件信息写入连接的数据库。
1、这里只读取两级目录(如下图)。
若二级目录还有子项,则可参考读取二级目录的代码,另外,SQL语句/字段都需要改动。
2、说明:
>> 根级目录:Outlook绑定的邮箱账户名称,也可以是Outlook连接的邮件存档名称。
>> 一级目录:是与收件箱(Inbox)同级的目录;
>>二级目录:是一级目录的子目录,就是自建的二级文件夹。
# -*- coding: utf-8 -*-
import pymysql
from win32com.client.gencache import EnsureDispatch as Dispatch
# import win32com.client
# 连接MySQL
conn = pymysql.connect(
host='127.0.0.1',
port=3306,
user='xxxx',
passwd='xxxx',
db='myemail_zl',
charset='utf8')
def connect_mysql(conn):
#判断链接是否正常
conn.ping(True)
#建立操作游标
cursor=conn.cursor()
#设置数据输入输出编码格式
cursor.execute("SET NAMES UTF8")
return cursor
#建立链接游标
cur=connect_mysql(conn)
# SQL语句
insert_sql = 'insert into email_box2 (根级目录,一级目录,二级目录,接收时间,发件人,收件人,抄送人,邮件主题,邮件ID,会话主题,会话ID,会话历史记录ID,邮件内容) values (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)'
# 连接Outlook
outlook = Dispatch("Outlook.Application")
mapi = outlook.GetNamespace("MAPI")
Accounts = mapi.Folders # 根级目录(邮箱名称,包括Outlook读取的存档名称)
for Account_Name in Accounts:
print(' >> 正在查询的帐户名称:',Account_Name.Name,'\n')
Level_1_Names = Account_Name.Folders # 一级目录集合(与inbox同级)
for Level_1_Name in Level_1_Names:
# 首先,向MySQL提交一级目录的邮件
print(' - 正在查询一级目录:' , Level_1_Name.Name)
Mail_1_Messages = Level_1_Name.Items # 一级文件夹的mail合集
for xx in Mail_1_Messages: # xx = 'mail' # 开始查看单个邮件的信息
Root_Directory_Name_1 = Account_Name.Name # 记录根目录名称
Level_1_FolderName_1 = Level_1_Name.Name # 记录一级目录名称
Level_2_FolderName_1 = '' # 一级目录肯定没有二级目录,顾留为空
if (hasattr(xx, 'ReceivedTime')):
ReceivedTime_1 = str(xx.ReceivedTime)[:-6] # 接收时间
else:
ReceivedTime_1 = ''
if (hasattr(xx, 'SenderName')): # 发件人
SenderName_1 = xx.SenderName
else:
SenderName_1 = ''
if (hasattr(xx, 'To')): # 收件人
to_to_1 = xx.To
else:
to_to_1 = ''
if (hasattr(xx, 'CC')): # 抄送人
cc_cc_1 = xx.CC
else:
cc_cc_1 = ''
if (hasattr(xx, 'Subject')): # 主题
Subject_1 = xx.Subject
else:
Subject_1 = ''
if (hasattr(xx, 'EntryID')): # 邮件MessageID
MessageID_1 = xx.EntryID
else:
MessageID_1 = ''
if (hasattr(xx, 'ConversationTopic')): # 会话主题
ConversationTopic_1 = xx.ConversationTopic
else:
ConversationTopic_1 = ''
if (hasattr(xx, 'ConversationID')): # 会话ID
ConversationID_1 = xx.ConversationID
else:
ConversationID_1 = ''
if (hasattr(xx, 'ConversationIndex')): # 会话记录相对位置
ConversationIndex_1 = xx.ConversationIndex
else:
ConversationIndex_1 = ''
if (hasattr(xx, 'Body')): # 邮件内容
EmailBody_1 = xx.Body
else:
EmailBody_1 = ''
# 写入MySQL
cur.execute(insert_sql, (Root_Directory_Name_1, Level_1_FolderName_1, Level_2_FolderName_1, ReceivedTime_1, SenderName_1, to_to_1, cc_cc_1, Subject_1, MessageID_1, ConversationTopic_1, ConversationID_1, ConversationIndex_1, EmailBody_1))
# 然后,判断当前查询的一级邮件目录是否有二级目录(若有多级目录,可以参考此段代码)
if Level_1_Name.Folders:
Level_2_Names = Level_1_Name.Folders # 二级目录的集合(比如,自建目录的子集)
for Level_2_Name in Level_2_Names:
print(' - - 正在查询二级目录:' , Level_1_Name.Name , '//' , Level_2_Name.Name)
Mail_2_Messages = Level_2_Name.Items # 二级目录的邮件集合
for yy in Mail_2_Messages: # xx = 'mail' # 开始查看单个邮件的信息
Root_Directory_Name_2 = Account_Name.Name # 记录根目录名称
Level_1_FolderName_2 = Level_1_Name.Name # 记录一级目录名称
Level_2_FolderName_2 = Level_2_Name.Name # 记录二级目录名称
if (hasattr(yy, 'ReceivedTime')):
ReceivedTime_2 = str(yy.ReceivedTime)[:-6] # 接收时间
else:
ReceivedTime_2 = ''
if (hasattr(yy, 'SenderName')): # 发件人
SenderName_2 = yy.SenderName
else:
SenderName_2 = ''
if (hasattr(yy, 'To')): # 收件人
to_to_2 = yy.To
else:
to_to_2 = ''
if (hasattr(yy, 'CC')): # 抄送人
cc_cc_2 = yy.CC
else:
cc_cc_2 = ''
if (hasattr(yy, 'Subject')): # 主题
Subject_2 = yy.Subject
else:
Subject_2 = ''
if (hasattr(yy, 'EntryID')): # 邮件MessageID
MessageID_2 = yy.EntryID
else:
MessageID_2 = ''
if (hasattr(yy, 'ConversationTopic')): # 会话主题
ConversationTopic_2 = yy.ConversationTopic
else:
ConversationTopic_2 = ''
if (hasattr(yy, 'ConversationID')): # 会话ID
ConversationID_2 = yy.ConversationID
else:
ConversationID_2 = ''
if (hasattr(yy, 'ConversationIndex')): # 会话记录相对位置
ConversationIndex_2 = yy.ConversationIndex
else:
ConversationIndex_2 = ''
if (hasattr(yy, 'Body')): # 邮件正文内容
EmailBody_2 = yy.Body
else:
EmailBody_2 = ''
# 写入MySQL
cur.execute(insert_sql, (Root_Directory_Name_2, Level_1_FolderName_2, Level_2_FolderName_2, ReceivedTime_2, SenderName_2,to_to_2, cc_cc_2, Subject_2, MessageID_2, ConversationTopic_2, ConversationID_2, ConversationIndex_2, EmailBody_2))
else:
pass
# 结尾
conn.commit()
conn.close()
print ('\n',' >> Done!')
最后的说明
1、打印的日志像这样:
>> 正在查询的帐户名称: xxx@xx.com
- 正在查询一级目录: 已删除邮件
- 正在查询一级目录: 收件箱
- 正在查询一级目录: 发件箱
- 正在查询一级目录: 已发送邮件
- 正在查询一级目录: 任务
- 正在查询一级目录: 快速步骤设置
- 正在查询一级目录: RSS 源
- 正在查询一级目录: Working Set
- 正在查询一级目录: 产品支持
- - 正在查询二级目录: 产品支持 // #2016/03/14#
- - 正在查询二级目录: 产品支持 // #更新、新品、例会#
2、因设定的字符集是utf8,若邮件信息包含不支持的字符(比如表情字符),则会提示Warning,如下图。
<1> Warning: (1300, "Invalid utf8 character string: 'F09F99'")
<2> Warning: (1366, "Incorrect string value: '\\xF0\\x9F\\x99\\x8F\\xF0\\x9F...' for column '邮件内容' at row 1")
因为提示的不多,而且只是出现在“邮件内容(邮件正文)”,所以代码里面没有具体修改,如果觉着有必要,推荐的思路是把“数据库/表/字段/连接MySQL的URL”的utf8字符集全部改用utf8mb4。