python邮件管理

一、基本概念

1、协议简介

  • POP3
    收邮件。允许电子邮件客户端下载服务器上的邮件,但是在客户端的操作(如移动邮件、标记已读等),不会反馈到服务器上。
  • IAMP
    收邮件。在电子邮件客户端收取的邮件仍然保留在服务器上,同时在客户端上的操作都会反馈到服务器上。
  • SMTP
    发邮件。必须在提供了账户名和密码之后才可以登录 SMTP 服务器,这就使得那些垃圾邮件的散播者无可乘之机。

2、邮箱地址

189邮箱(SSL加密)

  • POP3:pop.189.cn 端口995
  • SMTP:smtp.189.cn 端口465
  • IMAP:imap.189.cn 端口993

公司邮箱(SSL加密)

  • POP3:pop.chinatelecom.cn 端口995
  • SMTP:smtp.chinatelecom.cn 端口465
  • IMAP:imap.chinatelecom.cn 端口993

QQ邮箱(SSL加密)

  • POP3:pop.qq.cn 端口995
  • SMTP:smtp.qq.cn 端口465
  • IMAP:imap.qq.cn 端口993
    注意: QQ邮件等需要手动开通 SMTP服务

3、模块简介

python发邮件需要掌握两个模块的用法,smtplib和email。smtplib模块主要负责发送接收邮件,email模块主要负责构造邮件

smtplib模块

email模块

email模块下有mime包,mime英文全称为“Multipurpose Internet Mail Extensions”,该mime包下常用的有三个模块:text,image,multpart。
导入方法如下:

from email.mime.multipart import MIMEMultipart    
from email.mime.text import MIMEText    
from email.mime.image import MIMEImage

构造一个邮件对象就是一个Message对象,如果构造一个MIMEText对象,就表示一个文本邮件对象,如果构造一个MIMEImage对象,就表示一个作为附件的图片,要把多个对象组合起来,就用MIMEMultipart对象,而MIMEBase可以表示任何对象。它们的继承关系如下。

  • MIMEBase
    • MIMEMultipart
    • MIMENonMultipart
      • MIMEMessage
      • MIMEText 文本邮件对象
      • MIMEImag图片邮件对象

常见的multipart类型有三种:multipart/alternative, multipart/related和multipart/mixed。

邮件类型为"multipart/alternative"的邮件包括纯文本正文(text/plain)和超文本正文(text/html)。

邮件类型为"multipart/related"的邮件正文中包括图片,声音等内嵌资源。

邮件类型为"multipart/mixed"的邮件包含附件。向上兼容,如果一个邮件有纯文本正文,超文本正文,内嵌资源,附件,则选择mixed类型。

4、中文编码问题

from email.header import Header
subject = '中文标题'
subject=Header(subject, 'utf-8').encode()

二、代码展示

1、SMTP发送邮件

Python对SMTP支持有 smtplib 和 email 两个模块,email 负责构造邮件,smtplib 负责发送邮件。

构造邮件

文本正文:

from email.mime.text import MIMEText
msg = MIMEText('hello, send by Python...', 'plain', 'utf-8')

HTML正文:

from email.mime.text import MIMEText
msg = MIMEText('<html><body><p>test<p></body></html>', 'plain', 'utf-8')

发送邮件

import smtplib

from_addr = '189****3590@189.cn'
password = '*******'
to_addr = 'test_to_addr@qq.com'
smtp_server = 'smtp.189.cn'
server = smtplib.SMTP_SSL(smtp_server, 465) # SMTP协议默认端口是465
server.set_debuglevel(1)    # 打印出和SMTP服务器交互的所有信息
server.login(from_addr, password)   # 登录SMTP服务器
server.sendmail(from_addr, [to_addr], msg.as_string())    # 发邮件
server.quit()

sendmail() 方法就是发邮件,由于可以一次发给多个人,所以传入一个 list,邮件正文是一个 str,as_string() 把MIMEText对象变成 str。

添加邮件标题、收/发件人

message = MIMEText(message_context, 'plain', 'utf-8')
# 设置发件人(声称的)
message["From"] = Header(sender_email_address, "utf-8")
# 设置收件人(声称的)
message["To"] = Header(receiver_email, "utf-8")
# 设置邮件主题
message["Subject"] = Header(message_subject, "utf-8")

添加抄送,暗送

# ccto_list 抄送
# bccto_list 暗送

msg['from'] = user
msg['to'] = ','.join(to_list)   #注意,不是分号
msg['cc'] = ','.join(ccto_list)
msg['subject'] = subject
server.sendmail(sender,to_list+ccto_list+bccto_list, str(msg))

附件

要想发送附件,需要构造一个 MIMEMultipart 对象代表邮件本身,然后往里面加上一个 MIMEText 作为邮件正文,再继续往里面加上表示附件的 MIMEBase 对象

sendfile=open(r'D:\pythontest\1111.txt','rb').read()
text_att = MIMEText(sendfile, 'base64', 'utf-8')    
text_att["Content-Type"] = 'application/octet-stream'    
text_att["Content-Disposition"] = 'attachment; filename="显示的名字.txt"' 

图片

sendimagefile=open(r'D:\pythontest\testimage.png','rb').read()
image = MIMEImage(sendimagefile)
image.add_header('Content-ID','<image1>')

完整代码

#coding: utf-8    
  
import smtplib    
from email.mime.multipart import MIMEMultipart    
from email.mime.text import MIMEText    
from email.mime.image import MIMEImage 
from email.header import Header   
    
#设置smtplib所需的参数
#下面的发件人,收件人是用于邮件传输的。
smtpserver = 'smtp.163.com'
username = 'XXX@163.com'
password='XXX'
sender='XXX@163.com'
#receiver='XXX@126.com'
#收件人为多个收件人
receiver=['XXX@126.com','XXX@126.com']

subject = 'Python email test'
#通过Header对象编码的文本,包含utf-8编码信息和Base64编码信息。以下中文名测试ok
#subject = '中文标题'
#subject=Header(subject, 'utf-8').encode()
    
#构造邮件对象MIMEMultipart对象
#下面的主题,发件人,收件人,日期是显示在邮件页面上的。
msg = MIMEMultipart('mixed') 
msg['Subject'] = subject
msg['From'] = 'XXX@163.com <XXX@163.com>'
#msg['To'] = 'XXX@126.com'
#收件人为多个收件人,通过join将列表转换为以;为间隔的字符串
msg['To'] = ";".join(receiver) 
#msg['Date']='2012-3-16'

#构造文字内容   
text = "Hi!\nHow are you?\nHere is the link you wanted:\nhttp://www.baidu.com"    
text_plain = MIMEText(text,'plain', 'utf-8')    
msg.attach(text_plain)    

#构造图片链接
sendimagefile=open(r'D:\pythontest\testimage.png','rb').read()
image = MIMEImage(sendimagefile)
image.add_header('Content-ID','<image1>')
image["Content-Disposition"] = 'attachment; filename="testimage.png"'
msg.attach(image)

#构造html
#发送正文中的图片:由于包含未被许可的信息,网易邮箱定义为垃圾邮件,报554 DT:SPM :<p><img src="cid:image1"></p>
html = """
<html>  
  <head></head>  
  <body>  
    <p>Hi!<br>  
       How are you?<br>  
       Here is the <a href="http://www.baidu.com">link</a> you wanted.<br> 
    </p> 
  </body>  
</html>  
"""    
text_html = MIMEText(html,'html', 'utf-8')
text_html["Content-Disposition"] = 'attachment; filename="texthtml.html"'   
msg.attach(text_html)    


#构造附件
sendfile=open(r'D:\pythontest\1111.txt','rb').read()
text_att = MIMEText(sendfile, 'base64', 'utf-8') 
text_att["Content-Type"] = 'application/octet-stream'  
#以下附件可以重命名成aaa.txt  
#text_att["Content-Disposition"] = 'attachment; filename="aaa.txt"'
#另一种实现方式
text_att.add_header('Content-Disposition', 'attachment', filename='aaa.txt')
#以下中文测试不ok
#text_att["Content-Disposition"] = u'attachment; filename="中文附件.txt"'.decode('utf-8')
msg.attach(text_att)    
       
#发送邮件
smtp = smtplib.SMTP()    
smtp.connect('smtp.163.com')
#我们用set_debuglevel(1)就可以打印出和SMTP服务器交互的所有信息。
#smtp.set_debuglevel(1)  
smtp.login(username, password)    
smtp.sendmail(sender, receiver, msg.as_string())    
smtp.quit()

2、IAMP接收邮件

接收邮件

import datetime
import imaplib
import email


def recv_email_by_imap4(self):
    imap_server_host = 'imap.chinatelecom.cn'
    # imap_server_host = 'imap.189.cn'
    imap_server_port = 993
    try:
        imap = imaplib.IMAP4_SSL(host=imap_server_host, port=imap_server_port)
    except Exception as e:
        print(e)
    try:
        # 验证邮箱及密码是否正确
        imap.login(self._email_addr, self._email_password)
    except Exception as e:
        print(e)
    # 邮箱中其收到的邮件的数量
    imap.select()

    # 邮件状态设置,新邮件为Unseen
    # Messagestatues = 'All,Unseen,Seen,Recent,Answered, Flagged'
    resp, data = imap.search(None, "All")
    # resp, data = imap.search(None, "Unseen")
    index = data[0].decode().split()
    number = 1
    for i in data[0].split()[::-1]:
        resp, mail_data = imap.fetch(i, "(RFC822)")
        mail_text = mail_data[0][1].decode()
        msg = email.message_from_string(mail_text)
        if msg['Subject'] is not None:
            subject = email.header.decode_header(msg["Subject"])
        sub_fin = ''
        for item in subject:
            if item[1] is not None:
                sub_fin += item[0].decode(item[1])
            else:
                sub_fin += str(item[0])
        email_content, suffix = self.parse_email(msg)

        # 命令窗体输出邮件基本信息
        # 保存邮件正文

        if (suffix != None and suffix != '') and (email_content != None and email_content != ''):
            savefile(str(number) + suffix, email_content, self.mypath)
            number = number + 1

    # 关闭select
    imap.close()
    # 关闭连接
    imap.logout()

解析邮件

解析邮件每部分内容,包括发邮件介绍的,text、html、附件、图片等

def parse_email(self, msg):
    mail_content = None
    #正文类型:text/plain、text/html
    content_type = None
    suffix = None
    # 循环解析multipart
    for part in msg.walk():
        if not part.is_multipart():
            content_type = part.get_content_type()
            filename = part.get_filename()
            charset = part.get_charset()
            # 是否有附件
            if filename:
                dh = email.header.decode_header(filename)
                name = dh[0][0]
                encode_type = dh[0][1]
                if encode_type is not None:
                    if charset is None:
                        name = name.decode(encode_type, 'gbk')
                    else:
                        name = name.decode(encode_type, charset)
                data = part.get_payload(decode=True)
                self.save_file(name, data)
            else:
                if content_type in ['text/plain']:
                    suffix = '.txt'
                if content_type in ['text/html']:
                    suffix = '.htm'
                if charset is None:
                    mail_content = part.get_payload(decode=True)
                else:
                    mail_content = part.get_payload(decode=True).decode(charset)
    return mail_content, suffix

保存附件

def save_file(self, filename, data):
    try:
        file_path = self._path + filename
        f = open(file_path, 'wb+')
        f.write(data)
        f.close()
    except Exception as e:
        print('filename error')
        print(e)
        f.close()
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值