Python 之 pop 接收邮件和附件 smtplib 发送邮件

Python 之 pop 获取邮件和附件

有些库可能用不上的,大家自行判断吧

import re
import module.UpExcel as moduleExcel
import os
from email.utils import parseaddr, parsedate, getaddresses
from email.header import decode_header, Header
from email.parser import Parser
import xlwings as xw
import time
import email
import datetime
import poplib
import pandas as pd
poplib._MAXLINE = 20480


# 此函数通过使用poplib实现接收邮件
email_address = '****@263.com'
email_password = 'password'

def recv_email_by_pop3(email_address, email_password,interval_day):
    # 要进行邮件接收的邮箱。改成自己的邮箱
    # email_address = ""
    # 要进行邮件接收的邮箱的密码。改成自己的邮箱的密码
    # 设置 -> 账户 -> POP3/IMAP/SMTP/Exchange/CardDAV/CalDAV服务 -> 开启服务:POP3/SMTP服务
    # 设置 -> 账户 -> POP3/IMAP/SMTP/Exchange/CardDAV/CalDAV服务 -> 生成授权码
    # email_password = ""
    # 邮箱对应的pop服务器,也可以直接是IP地址
    # 改成自己邮箱的pop服务器;
    pop_server_host = "pop.263.net"
    # 邮箱对应的pop服务器的监听端口。改成自己邮箱的pop服务器的端口;qq邮箱不需要修改此值
    pop_server_port = 110

    try:
        # 连接pop服务器。如果没有使用SSL,将POP3_SSL()改成POP3()即可其他都不需要做改动
        email_server = poplib.POP3(host=pop_server_host, timeout=30, port=pop_server_port)
    except:
        print("pop3----sorry the given email server address connect time out")
        exit(1)
    try:
        # 验证邮箱是否存在
        email_server.user(email_address)
    except:
        print("pop3----sorry the given email address seem do not exist")
        exit(1)
    try:
        # 验证邮箱密码是否正确
        email_server.pass_(email_password)
    except:
        print("pop3----sorry the given username seem do not correct")
        exit(1)

    # 邮箱中其收到的邮件的数量
    email_count = len(email_server.list()[1])

    # list()返回所有邮件的编号:
    resp, mails, octets = email_server.list()
    # 遍历所有的邮件
    for i in range(len(mails), 0, -1):
        # 通过retr(index)读取第index封邮件的内容;这里读取最后一封,也即最新收到的那一封邮件
        resp, lines, octets = email_server.retr(i)
        # lines是邮件内容,列表形式使用join拼成一个byte变量
        email_content = b'\r\n'.join(lines)
        try:
            # 再将邮件内容由byte转成str类型
            email_content = email_content.decode('utf-8')
        except Exception as e:
            print(str(e))
            continue
        # # 将str类型转换成<class 'email.message.Message'>
        # msg = email.message_from_string(email_content)
        msg = Parser().parsestr(email_content)
        print('-------------  分隔符  ---------------')
        # 写入邮件内容到文件
        list = []
        list = parse_email(list, msg, 0, interval_day)
        # 时间判断
        nowTime = (datetime.datetime.now()+datetime.timedelta(days=interval_day)
                   ).strftime("%Y-%m-%d") + ' 00:00:00'
        if list[0] < nowTime:
            email_server.close()
            return
        if len(list) > 2:
            riqi = str(time.strftime("%Y-%m-%d", time.localtime()))
            filename = r'D:\AutoEmail\Get\Get' + riqi + '.xlsx'
            app = xw.App(visible=False, add_book=False)
            wb = app.books.open(filename)  # 读入已有工作簿
            sht = wb.sheets[0]  # 引用活动sheet
            info = sht.used_range
            nrows = info.last_cell.row
            sht.range('A'+str(nrows+1)).value = [list]
            # 自动调整表格
            # sht.autofit()
            info.column_width = 40
            sht.range('A1:A'+str(nrows+1)).column_width = 16
            # 保存工作簿
            wb.save(filename)
            wb.close()  # 关闭工作簿(程序不能编辑了)----显示的文件不关闭
            # app.quit()  # 退出
            app.kill()

    # 关闭连接
    email_server.close()

# 下载附件


def get_att(msg):
    attachment_files = []
    for part in msg.walk():
        file_name = part.get_filename()  # 获取附件名称类型
        contentType = part.get_content_type()  # 获取数据类型
        mycode = part.get_content_charset()  # 获取编码格式
        if file_name:
            h = Header(file_name)
            dh = decode_header(h)  # 对附件名称进行解码
            filename = dh[0][0]
            if dh[0][1]:
                filename = decode_str(str(filename, dh[0][1]))  # 将附件名称可读化
            attachment_files.append(filename)
            data = part.get_payload(decode=True)  # 下载附件
            with open(filename, 'wb') as f:  # 在当前目录下创建文件,注意二进制文件需要用wb模式打开
                #with open('指定目录路径'+filename, 'wb') as f: 也可以指定下载目录
                f.write(data)  # 保存附件
            print(f'附件 {filename} 已下载完成')
        elif contentType == 'text/plain':  # or contentType == 'text/html':
            # 输出正文 也可以写入文件
            data = part.get_payload(decode=True)
            content = data.decode(mycode)
            print('正文:', content)
    print('附件文件名列表', attachment_files)

# 读取信息( indent用于缩进显示:)


def parse_email(list, msg, indent,interval_day):
    if indent == 0:
        # print('msg:',msg)
        # 邮件的From, To, Subject存在于根对象上:
        for header in ['Date', 'From', 'To', 'CC', 'Subject']:
            value = msg.get(header, '')
            # if value:
            # 时间
            if header == 'Date':
                strDate = time.strftime("%Y-%m-%d %H:%M:%S", parsedate(value))
                # 获取当日发件
                nowTime = (datetime.datetime.now(
                )+datetime.timedelta(days=interval_day)).strftime("%Y-%m-%d") + ' 00:00:00'
                list.append(strDate)
                if strDate[:10] < nowTime:
                    print('%s%s: %s' % ('  ' * indent, header, strDate))
                    return list
                print('%s%s: %s' % ('  ' * indent, header, strDate))
            # 发件人
            elif header == 'From':
                # 需要解码Email地址:
                hdr, addr = parseaddr(value)
                # name = decode_str(hdr)
                # strFrom = u'%s <%s>' % (name, addr)
                strFrom = u'<%s>' % (addr)
                list.append(strFrom)
                print('%s%s: %s' % ('  ' * indent, header, strFrom))
            # 收件人
            elif header == 'To':
                listTo = []
                tos = msg.get_all('to', [])
                for to in getaddresses(tos):
                    to = to[0] + ' <' + to[1] + '>'
                    hdr, addr = parseaddr(to)
                    name = decode_str(hdr)
                    # strTo = u'%s <%s>' % (name, addr)
                    strTo = u'<%s>' % (addr)
                    listTo.append(strTo)
                strlistto = ''.join(listTo)
                # # 需要解码Email地址:
                # hdr, addr = parseaddr(value)
                # name = decode_str(hdr)
                # strTo = u'%s <%s>' % (name, addr)
                list.append(strlistto)
                print('%s%s: %s' % ('  ' * indent, header, strlistto))
            # 抄送
            elif header == 'CC':
                listCc = []
                ccs = msg.get_all('cc', [])
                for cc in getaddresses(ccs):
                    cc = cc[0] + ' <' + cc[1] + '>'
                    hdr, addr = parseaddr(cc)
                    name = decode_str(hdr)
                    # strCc = u'%s <%s>' % (name, addr)
                    strCc = u'<%s>' % (addr)
                    listCc.append(strCc)
                strlistCc = ''.join(listCc)
                if strlistCc == '':
                    strlistCc = '空'
                # # 需要解码Email地址:
                # hdr, addr = parseaddr(value)
                # name = decode_str(hdr)
                # strCc = u'%s <%s>' % (name, addr)
                list.append(strlistCc)
                print('%s%s: %s' % ('  ' * indent, header, strlistCc))
            # 主题
            elif header == 'Subject':
                # 需要解码Subject字符串:
                strSubject = decode_str(value)
                list.append(strSubject)
                print('%s%s: %s' % ('  ' * indent, header, strSubject))
    if (msg.is_multipart()):
        # 如果邮件对象是一个MIMEMultipart,
        # get_payload()返回list,包含所有的子对象:
        parts = msg.get_payload()
        for n, part in enumerate(parts):
            # 递归打印每一个子对象:
            parse_email(list, part, indent + 1,interval_day)
        return list
    else:
        for part in msg.walk():  # 遍历所有payload
            # 邮件对象不是一个MIMEMultipart,
            # 就根据content_type判断:
            content_type = msg.get_content_type()
            file_name = part.get_filename()
            if content_type == 'text/plain' or content_type == 'text/html':
                if len(list) < 6:
                    # 纯文本或HTML内容:
                    content = msg.get_payload(decode=True)
                    # 要检测文本编码:
                    charset = guess_charset(msg)
                    if charset:
                        try:
                            content = content.decode(charset)
                        except:
                            content = content.decode("gb2312", errors='ignore')
                    print('%sText: %s' % ('  ' * indent, content))
                    list.append('text:' + content.replace(' ',
                                '').replace('\n', '').replace('\r', '')[:300])

            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]))  # 将附件名称可读化
                    #filename = filename.encode("utf-8")
                data = part.get_payload(decode=True)  # 下载附件

                riqi = str(time.strftime("%Y-%m-%d", time.localtime()))
                attfileadd = 'D:\\AutoEmail\\Att\\Get\\'+riqi
                if not os.access(attfileadd, os.X_OK):
                    os.mkdir('D:\\AutoEmail\\Att\\Get\\' + './'+riqi+'')

                with open(attfileadd + '\\' + filename, 'wb') as f:  # 在当前目录下创建文件,注意二进制文件需要用wb模式打开
                    f.write(data)  # 保存附件
                print('%sAtt: %s' % ('  ' * indent, filename))
                list.append(filename)
            # else:
            #     # 不是文本,作为附件处理:
            #     print('%sAttachment: %s' % ('  ' * indent, content_type))
            #     list.append('Attachment:' + content_type)
    return list

# 解码


def decode_str(s):
    value, charset = decode_header(s)[0]
    # if charset or value[:2]=='Re':
    try:
        value = value.decode(charset)
    except:
        try:
            value = value.decode("gb2312", errors='ignore')
        except:
            pass
    return value

# 猜测字符编码


def guess_charset(msg):
    try:
        # 先从msg对象获取编码:
        charset = msg.get_charset()
        if charset is None:
            # 如果获取不到,再从Content-Type字段获取:
            content_type = msg.get('Content-Type', '').lower()
            for item in content_type.split(';'):
                item = item.strip()
                if item.startswith('charset'):
                    charset = item.split('=')[1]
                    break
        return charset
    except:
        pass

smtplib 发送邮件

# ! /usr/bin/env python
# -*- coding: UTF-8 -*-
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
import sys
import os
import pandas as pd
import datetime
import tkinter.messagebox
import traceback
import xlwings as xw


# 参数:收件人,主题,正文,文件名集合(可发送多个文件),文件路径(文件在同一个路径)
def wain_send_mail(mail_user,mail_pass,sub, content, files, path):
    mailto_list = ['']  # 收件人列表,以英文逗号分隔
    mail_host = "smtp.263.net"  # 使用的邮箱的smtp服务器地址,这里是263的smtp地址
    # mail_user = "****@qq.com"  # 用户名
    # mail_pass = ""  # 授权码,不是密码,授权码要在邮箱设置中获取
    Cc_list = ['抄送人员列表']

    me = "<" + mail_user + ">"
    msg = MIMEMultipart()
    msg.attach(MIMEText(content, _subtype='html', _charset='utf-8'))
    msg['Subject'] = sub
    msg['From'] = me
    msg['To'] = ",".join(mailto_list)  # 将收件人列表以‘,’分隔
    msg['Cc'] = ",".join(Cc_list)  # 将收件人列表以‘,’分隔
    for file in files:
        if os.path.isfile(path + '/' + file):
            # 构造附件
            att = MIMEText(open(path + '/' + file, 'rb').read(), 'base64', 'utf-8')
            att["Content-Type"] = 'application/octet-stream'
            att.add_header("Content-Disposition", "attachment", filename=("gbk", "", file))
            msg.attach(att)
    try:
        server = smtplib.SMTP()
        if mail_host == 'smtp.gmail.com':
            server.connect(mail_host, port=587)  # 连接服务器
            server.starttls()
        else:
            server.connect(mail_host)
        server.login(mail_user, mail_pass)  # 登录操作
        server.sendmail(me, mailto_list + Cc_list, msg.as_string())
        server.close()
        print('Mail sent successfully')
        shijian = '已发送,' + str(datetime.datetime.now())
        return shijian
    except Exception as e:
        print('Mail sent failed')
        print(sys.exc_info()[0], sys.exc_info()[1])
        shijian = '1,发送失败'
        return shijian


posted @   Ivan丶ky  阅读(718)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
点击右上角即可分享
微信分享提示