Python:邮件:outlook:基本用法

5,269 阅读5分钟

零、前情提要

最近编写自动化邮件监控时,由于公司的邮箱是outlook, 自动化有两种方式, 这边记录一下已被之后使用

一、协议用法

1.1 邮件路径概述

1.1.1 发送电子邮件的过程

发件人 —> MUA -> MTA -> 若干个MTA - MDA <- MUA <- 收件人

发件人通过电子邮件软件MUA将邮件传输给本电子邮件的Email服务提供商,比如说@163.com则会传递给网易的服务器MTA,再由服务提供商投递到对方的服务器MDA存储,如果邮件的接收方是@sina.com则投递到新浪的服务器MDA上, 如果对方要收取邮件, 则需要通过MUA从对应的MDA中提取邮件.

邮件的内容其实都存在MUA上, 即从电子邮箱软件看到的内容. 操作电子邮件软件的邮件就是直接操作MUA上的内容.

1.1.2 邮件概述

名词 释义
MUA Mail User Agent, 电子邮件软件, 比如outlookfoxmail
MTA Mail Transfer Agent, 邮件传输代理,即Email服务提供商,比如网易、新浪
MDA Mail Delivery Agent, 邮件投递代理, 即服务提供商的服务器

1.1.3 协议概述

有了以上的概念, 那么收发邮件的本质就是:

  • 编写MUA把邮件发送到MTA. 此时使用的协议就是SMTP协议.
  • 编写MUAMDA上收邮件.

在邮件客户端在发送邮件时会先配置SMTP服务器, 也就是需要发到哪个MTA上. 如果此时你用的是@163.com,则只能发也必须发到网易的MTA, 新浪的MTA是不服务网易的用户的. 为了验证你是网易的用户, 因此SMTP服务器要求提供邮件地址和邮件口令.

1.2 协议用法介绍

协议名 释义
MIME 多用途互联网邮件扩展类型。是设定某种扩展名的文件用一种应用程序来打开的方式类型
SMTP Simple Mail Transfer Protocol, 邮件发送协议,建立在FTP文件传输服务上的一种邮件服务.
POP Post Office Protocol, 目前的版本是3, 俗称POP3; 邮件接收协议, 本协议主要用于支持使用客户端远程管理在服务器上的电子邮件。
IMAP Internet Message Access Protocol, 目前版本是4, 交互邮件访问协议, 它的主要作用是邮件客户端可以通过这种协议从邮件服务器上获取邮件的信息,下载邮件, 直接操作MDA上存储的邮件,比如从收件箱一道垃圾箱.

1.2 导入

## pop协议
import poplib ## python内置库

## 邮件解析
from email.parser import Parser ## 解析邮件原始文本
from email.header import decode_header
from email.utils import parseaddr

## smtp协议
import smtplib

## 邮件构造
from email.mime.text import MIMEText

1.3 POP3协议

pop3协议收取的不是一个可以阅读的邮件本身, 而是邮件的原始文本, 需要使用email模块提供类来解析原始文本, 变成可阅读的邮件对象.

1.3.1 登录邮箱

## 基础配置
email_address = 'xxx@outlook.com'
email_password = 'xxxx'
pop_server_host = 'partner.outlook.cn' ## 公司级(office365)的链接地址, 个人申请的可能不同
pop_server_port = 995 ## 端口

## 登录邮件
### 链接pop服务器
email_server = poplib.POP3_SSL(host=pop_server_host, port=pop_server_port, timeout=10)
email_server = poplib.POP3(host=pop_server_host, port=pop_server_port, timeout=10)

### 验证邮箱是否存在
email_server.user(email_address)

### 验证邮件密码是否正确
email_server.pass_(email_password)

1.3.2 获取邮件

## 返回邮件数量和占用空间
email_server.stat()

## 返回邮件编号
resp, mails, octets = email_server.list()

## 返回邮件数量
index = len(mails)

## 获取特定序号邮件, 索引从1开始
resp, lines, octets = email_server.retr(index) ## lines 储存邮件原始文本所有信息.

## 获取邮件原始文本
email_content = b'\r\n'.join(lines).decode('utf-8')

## 解析邮件文本
## 解析为`Message`对象, 此时对象本身可能是一个`MIMEMultipart`对象, 即包含嵌套的其他`MIME`对象, 嵌套可能还不止一层.
content = Parser().parsestr(email_content) 

1.3.3 删除邮件及其他

## 删除邮件
## 通过邮件索引号直接从服务器删除邮件.
email_server.dele(index)

## 关闭连接
email_server.quit()

1.4 MIME解析

MIME(Multipurpose Internet Mail Extensions): 描述消息内容类型的因特网标准, 能包含文本、图像、音频、视频以及其他应用程序专用的数据

MIME参考手册: www.w3school.com.cn/media/media…

1.4.1 MIME示例

类型/子类型 扩展名
application/pdf pdf
image/jpeg jpe/jpg/jpeg

1.4.2 邮件解析

## Suject解析
## 邮件的Subject或者Email中包含的名字都是经过编码后的str, 要正常显示, 就必须decode.
def decode_str(s):
    value, charset = decode_header(s)[0] ## decode_header()返回的是一个list, 抄送多人时会返回多个元素. 可以用索引选择对应元素.
    if charset: ## charset是得到的编码类型
        value = value.decode(charset)
    
    return value

## 得到对应元素比如说收件人、发件人的原始文本值
for header in ['From','To','Subject']
    content = content.get(header,'')
    
## Subject解析
value  = decode_str(value) ## 此时header = 'Subject'
## From、To解析 发件人、收件人解析
hdr, addr = parseaddr(value) ## 此时header in ('From','To')
name = decode_str(hdr)
## 邮件正文解析
## 邮件文本也是str,需要检测编码,否则非utf-8编码的邮件无法正常显示
## 编码确认
def guess_charset(msg):
    charset = msg.get_charset()
    if charset is None:
        content_type = msg.get('Content-Type','').lower()
        pos = content_type.find('charset=')
        if pos >= 0:
            charset = content_type[pos + 8:].strip()
        
    return charset
    
## 正文解析
content_type = content.get_content_type()
if content_type = 'text/plain' or content_type = 'text/html':
    content_email = content.get_payload(decode=True)
    charset = guess_charset(content)
    if charset:
        content_email = content_email.decode(content)

1.5 SMTP协议

PythonSMTP支持有smtplibemail两个模块,email负责构建邮件,smtplib负责发送邮件.

1.5.1 基础用法

## 基础数据
### 发件人 密码 收件人 服务器
from_addr = 'xxx@163.com'
password = 'xxxx'
to_addr = 'xxx@outlook.com'
smtp_server = 'smtp.163.com'

## 构建基础文件
def _format_addr(s):
    name, addr = parseaddr(s)
    return formataddr((Header(name,'utf-8').encode(), addr))


msg = MIMEText('hello, send by Python...','plain','utf-8')
msg['From'] = _format_addr('name <%s>' % from_addr)
msg['To'] = _format_addr('name <%s>' % to_addr)
msg['Subject'] = Header('来自SMTP的问候...','utf-8').encode()

## 邮件发送
server  = smtplib.SMTP(smtp_server,25) # SMTP协议默认端口是25, 25端口是明文传输 如果要SSL安全连接 则需要: server.starttls()
server.ser_debuglevek(1) ## 打印初和SMTP服务器交互的所有信息
server.login(from_addr,password)
server.sendmail(from_addr, [to_addr], msg.as_string()) ## 邮件正文是一个`str` as_string()把MIMEText对象变成`str`.
server.quit()

二、配置用法

2.1 配置用法介绍 - 只适用于window

配置用法的核心是通过pywin32(python for windows)库调用本地outlook配置(office提供基于COM接口的编程)进行邮件读取, 但会存在一个问题读取配置需要授权, 授权方法一是会唤起授权窗口进行短时间临时授权, 二是通过后台配置进行永久授权.

2.2 导入

## pip install pywin32
import win32com

2.3 基本配置

## 启动outlook进程
outlook = win32com.client.Dispatch("Outlook.Application").GetNamespace("MAPI") ## Dispatch派遣 即调用Outlook.Application.

## 获取配置中所有账号
accounts = win32com.client.Dispatch("Outlook.Application").Session.Accounts

## 获取一级目录
inbox = outlook.Folders(account.DeliveryStore.DisplayName)
folders = inbox.Folders