基于Python的邮件收发

1.SMTP发送邮件:

# Python 3.6
# Author:宿命小哥哥
from email.header import Header
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.utils import parseaddr, formataddr
import smtplib


def _format_addr(s):
    name, addr = parseaddr(s)
    return formataddr((Header(name, 'utf-8').encode(), addr))


def send_mail(to_list, sub):
    msg = MIMEMultipart()
    msg['From'] = _format_addr('发送者 <%s>' % from_addr)
    msg['To'] = _format_addr('接受者 <%s>' % to_addr).join(to_list)
    msg['Subject'] = Header(sub, 'utf-8').encode()

    txt = MIMEText('发送测试!!!', _subtype='plain', _charset='utf8')
    msg.attach(txt)

    h = MIMEText('<html><body><h1>Hello,这是一个Python的SMTP程序发送来的邮件</h1>' +
                 '<p>send by 宿命小哥哥</a>...</p>' +
                 '</body></html>', _subtype='html', _charset='utf8')
    msg.attach(h)

    # 添加附件
    img = MIMEText(open('F:\\1.png', 'rb').read(), 'base64', 'utf-8')
    img["Content-Type"] = 'application/octet-stream'
    img["Content-Disposition"] = 'attachment; filename="Picture.png"'
    # filename是自定义附件名字
    msg.attach(img)

    att1 = MIMEText(open('F:\\1.txt', 'rb').read(), 'base64', 'utf-8')
    att1["Content-Type"] = 'application/octet-stream'
    att1["Content-Disposition"] = 'attachment; filename="text.txt"'
    msg.attach(att1)

    try:
        server = smtplib.SMTP_SSL(smtp_server, smtp_port)
        # 加密SMTP会话
        # server.starttls()
        # 打印出和SMTP服务器交互的所有信息
        server.set_debuglevel(1)
        # 登录SMTP服务器
        server.login(from_addr, password)
        # 发邮件
        server.sendmail(from_addr, to_addr, msg.as_string())
        server.quit()
        return True
    except:
        print("出现错误!")
        return False


if __name__ == '__main__':
    # 邮件发送方的邮箱账号
    from_addr = input('From: ')
    # 邮件发送方的邮箱密码
    password = input('Password: ')
    # 邮件接收方的邮件地址
    to_addr = input('To: ')
    # 邮件传送协议服务器
    smtp_server = input('server: ')
    # 使用SSL,端口号465或587
    smtp_port = input('port: ')
    Sub = input('Subject: ')
    if send_mail(from_addr, Sub):
        print("发送成功")
    else:
        print("发送失败")

2.POP3接收邮件:

# Python 3.6
# Author:宿命小哥哥
from email.parser import Parser
from email.header import decode_header
from email.utils import parseaddr
import poplib


# indent用于缩进显示:
def print_info(msg, indent=0):
    # 初始分析
    if indent == 0:
        # 遍历获取:发件人,收件人,主题
        for header in ['From', 'To', 'Subject']:
            # 获得对应的内容
            value = msg.get(header, '')
            # 有内容
            if value:
                # 如果是主题
                if header == 'Subject':
                    # 解码主题
                    value = decode_str(value)
                else:
                    # parseaddr:解析字符串中的email地址
                    hdr, addr = parseaddr(value)
                    # 解码主题
                    name = decode_str(hdr)
                    # 合成内容
                    value = u'%s <%s>' % (name, addr)
            print('%s%s: %s' % ('  ' * indent, header, value))
    # 如果消息由多个部分组成,则返回True。
    if (msg.is_multipart()):
        # 返回list,包含所有的子对象
        parts = msg.get_payload()
        # enumerate将其组成一个索引序列,利用它可以同时获得索引和值
        for n, part in enumerate(parts):
            # 打印消息模块编号
            print('%spart %s' % ('  ' * indent, n))
            # 打印分割符号
            print('%s---------------------------------------' % ('  ' * indent))
            # 递归打印
            print_info(part, indent + 1)
    else:
        # 递归结束条件,打印最基本模块;返回消息的内容类型。
        content_type = msg.get_content_type()
        # 如果是text类型或者是html类型
        if content_type == 'text/plain' or content_type == 'text/html':
            # 返回list,包含所有的子对象,开启解码
            content = msg.get_payload(decode=True)
            # 猜测字符集
            charset = guess_charset(msg)
            # 字符集不为空
            if charset:
                # 解密
                content = content.decode(charset)
            # 打印内容
            print('%sText: %s' % ('  ' * indent, content + '...'))
        else:
            print('%sAttachment: %s' % ('  ' * indent, content_type))


# 邮件的Subject或者Email中包含的名字都是经过编码后的str,要正常显示就必须decode
def decode_str(s):
    # 在不转换字符集的情况下解码消息头值,返回一个list
    value, charset = decode_header(s)[0]
    if charset:
        value = value.decode(charset)
    return value


# 文本邮件的内容也是str,还需要检测编码,否则,非UTF-8编码的邮件都无法正常显示:
def guess_charset(msg):
    # 得到字符集
    charset = msg.get_charset()
    if charset is None:
        # lower:所有大写字符为小写
        content_type = msg.get('Content-Type', '').lower()
        # find:检测字符串中是否包含子字符串,返回charset=头字符的位置
        pos = content_type.find('charset=')
        if pos >= 0:
            # strip:移除字符串头尾指定的字符(默认为空格)
            charset = content_type[pos + 8:].strip()
    return charset


if __name__ == '__main__':
    # 输入邮件地址, 口令和POP3服务器地址:
    email = input('Email: ')
    password = input('Password: ')
    pop3_server = input('POP3 server: ')

    # 连接到POP3服务器:
    server = poplib.POP3_SSL(pop3_server)
    # 可以打开或关闭调试信息:
    server.set_debuglevel(1)
    # 可选:打印POP3服务器的欢迎文字:
    print(server.getwelcome().decode('utf-8'))

    # 身份认证:
    server.user(email)
    server.pass_(password)

    # stat()返回邮件数量和占用空间:
    print('Messages: %s. Size: %s' % server.stat())
    # list()返回所有邮件的编号:
    resp, mails, octets = server.list()
    # 可以查看返回的列表类似[b'1 82923', b'2 2184', ...]
    print(mails)

    # 获取最新一封邮件, 注意索引号从1开始:
    index = len(mails)
    resp, lines, octets = server.retr(index)
    # lines存储了邮件的原始文本的每一行,
    # 可以获得整个邮件的原始文本:
    msg_content = b'\r\n'.join(lines).decode('utf-8')
    # 解析出邮件:
    Msg = Parser().parsestr(msg_content)
    print_info(Msg)
    # 可以根据邮件索引号直接从服务器删除邮件:
    # server.dele(index)
    # 关闭连接:
    server.quit()

3.IMAP接收邮件:

# Python 3.6
# Author:宿命小哥哥
import imaplib
import email


# 解析邮件方法(区分出正文与附件)
def parseEmail(e):
    # 解析邮件/信体
    # 循环信件中的每一个mime的数据块
    for part in e.walk():

        # 这里要判断是否是multipart,是的话,里面的数据是一个message 列表
        if not part.is_multipart():
            charset = part.get_charset()
            print('charset: ', charset)
            contenttype = part.get_content_type()
            print('content-type', contenttype)
            # 如果是附件,这里就会取出附件的文件名
            if contenttype in ['image/jpeg', 'image/png']:
                image_file = part.get_payload(decode=True)
                image_file_name = part.get_filename()
                print('content-type', image_file_name)
            name = part.get_param("name")
            if name:
                # 有附件
                # 下面的三行代码只是为了解码象=?gbk?Q?=CF=E0=C6=AC.rar?=这样的文件名
                fh = email.Header.Header(name)
                fdh = email.Header.decode_header(fh)
                fname = fdh[0][0]
                print('附件名:', fname)
                # 解码出附件数据,然后存储到文件中
                attach_data = part.get_payload(decode=True)

                try:
                    # 注意一定要用wb来打开文件,因为附件一般都是二进制文件
                    f = open(fname, 'wb')
                except:
                    print('附件名有非法字符,自动换一个')
                    f = open('aaaa', 'wb')
                f.write(attach_data)
                f.close()
            else:
                # 不是附件,是文本内容,解码出文本内容,直接输出
                print(part.get_payload(decode=True).decode('utf-8'))


def geimail(host, port, mail, password):
    M = imaplib.IMAP4_SSL(host, port)
    print(M)
    try:
        try:
            M.login(mail, password)
            print('成功登陆邮箱')
        except Exception as e:
            print('登陆错误: %s' % e)
            M.close()
        # 选取收件箱
        M.select('INBOX')
        # 获取未读邮件信息
        unseen = M.search(None, 'Unseen')
        unseen_list = unseen[1][0].split()
        print('未读邮件数:', len(unseen_list))
        # 想获取最新一封的做法是:
        typ, data = M.search(None, 'ALL')
        msglist = data[0].split()
        print('已读邮件数:', len(msglist))
        new = msglist[len(msglist) - 1]
        try:
            typ, data = M.fetch(new, '(RFC822)')
            msg = email.message_from_string(data[0][1].decode('utf-8'))
            sub = email.header.decode_header(msg.get('subject'))[0]
            print("From:", email.utils.parseaddr(msg.get("from"))[1])
            print("To:", email.utils.parseaddr(msg.get("to"))[1])
            if not email.utils.parseaddr(msg .get_all('cc'))[1]:
                print('Cc: 无抄送者')
            else:
                print('Cc:', email.utils.parseaddr(msg .get_all('cc'))[1])
            print("Subject:", sub[0].decode(sub[1]))
            print("Date:", msg["Date"])
            print("_______________________________")
            return msg
        except Exception as e:
            print('got msg error: %s' % e)
        M.close()
    except Exception as e:
        print('imap error: %s' % e)
        M.close()
    M.logout()


if __name__ == "__main__":
    # 输入邮件地址, 口令和服务器地址:
    Email = input('Email: ')
    Password = input('Password: ')
    IMAP_server = input('IMAP server: ')
    IMAP_port = input('IMAP port: ')
    print('【1】开始获取最新一封邮件...')
    Msg = geimail(IMAP_server, IMAP_port, Email, Password)
    print('【2】开始解析邮件内容...')
    parseEmail(Msg)

  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值