收发邮件

打开IMAP/SMTP服务

以QQ邮箱为例,打开IMAP/SMTP服务,生成授权码,设置收取选项

QQ邮箱->设置->账户->开启,IMAP/SMTP服务->生成授权码->收取选项

收取邮件

在Python中,poplib和imaplib库都支持邮件的接收协议,可以让我们登陆服务器接收邮件

imaplib库支持IMAP协议,而poplib库支持POP3协议,IMAP协议在支持双向操作的功能上更加强大

并且能把客户端对邮件的删除等操作同步到服务端,也能把服务端对邮件删除的操作同步到客户端

与POP3协议只能把服务端的操作单向同步给客户端相比,会更加灵活


import imaplib
import config
import email
from pathlib import Path
from email.header import decode_header

# 附件路径
attachments_dir = Path.cwd()

conn = imaplib.IMAP4_SSL(host="imap.qq.com", port=993)
conn.login("123456789@qq.com", config.MAIL_AUTH_CODE)

# 列出邮箱中所有的列表,如:收件箱、垃圾箱、草稿箱
# conn.list()

# 只查收件箱
conn.select("INBOX")

# 搜索最近30天(可以在QQ邮箱中设置)的未读邮件的id
# 可以用ALL搜索全部,也可以按照发件人使用FROM过滤,也可以使用日期过滤
# _, data = conn.search(None, 'unseen')

_, data = conn.search(None, 'FROM', '张三')

# 解析邮件头
def parse_header(message):
    # 主题、发件人、收件人、抄送人
    result = {
        'subject': message.get('subject'),
        'from': email.utils.parseaddr(message.get('from'))[1],
        'to': email.utils.parseaddr(message.get('to'))[1],
        'cc': email.utils.parseaddr(message.get_all('cc'))[1]
    }

    # 解码标题
    result['subject'] = email.header.decode_header(result['subject'])[0][0]
    # 再次解码标题
    result['subject'] = result['subject'].decode('utf-8')
    return result


# 解析邮件内容
def parse_body(message):
    if message.is_multipart():
        return parse_body(message.get_payload(0))
    else:
        result = message.get_payload(None, decode=True)
        return result.decode('utf-8')


# 保存附件
def save_attachments(message):
    file_paths = []
    for part in message.walk():
        if part.get_content_maintype() == 'multipart':
            continue
        if part.get('Content-Disposition') is None:
            continue
        filename = part.get_filename()
        # 如果文件名为纯数字、字母时不需要解码,否则需要解码
        filename = decode_header(filename)[0][0].decode(decode_header(filename)[0][1])

        if bool(filename):
            filepath = attachments_dir.joinpath(filename)
            with open(filepath, 'wb') as f:
                f.write(part.get_payload(decode=True))
                file_paths.append(filepath)
    return file_paths


for mail_id in data[0].decode().split(" "):
    # 获取每一封未读邮件的内容,不判断code了,用_接收掉
    _, mail_data = conn.fetch(str(mail_id), '(RFC822)')
    # 对每一封邮件的内容进行解析
    message = email.message_from_string(mail_data[0][1].decode('utf-8'))

    # 解析头信息
    header = parse_header(message)
    print(header)
    # 解析内容
    body = parse_body(message)
    print(body)

    # 保存附件
    attachments = save_attachments(message)
    print(attachments)

    # 将邮件标记为已读
    # conn.store(mail_id, '+FLAGS', '\\seen')

conn.close()
conn.logout()

发送邮件

在邮件服务的协议规范中,规定发送邮件采用的是SMTP协议,因此,我们可以使用smtplib库来实现发送邮件的功能

由于smtplib需要配置较多的通用参数,所以还有一个对它进行了更高级的封装的第三方库yagmail库

SMTP()函数默认端口为465,SMTP-MSA端口改为587


import yagmail
import config

conn = yagmail.SMTP(
    user="666666@qq.com",
    password=config.MAIL_AUTH_CODE,
    host="smtp.qq.com",
    port=465
)

conn.send(to="123456.qq.com", subject="标题", cc="1234567.qq.com", contents="内容",
          attachments="附件.excel")

conn.close()

results matching ""

    No results matching ""