python: 邮件收发-以QQ邮箱为例

发邮件比较简单。但收邮件却要麻烦一些。这里涉及到邮件的内容、标题、发件人等解析。
下面以QQ邮箱为例。需要注意的是,一些公司exchange邮箱往往需要公司在后台开启授权。

import smtplib
from email.header import Header    # 用来对Email标题进行编码
from email.mime.text import MIMEText # 负责构造文本
from email.mime.image import MIMEImage  # 负责构造图片
from email.mime.multipart import MIMEMultipart
from email.mime.base import MIMEBase # 添加附件的时候用到
from email.utils import parseaddr, formataddr
from email.mime.application import MIMEApplication
## 需要进行pop设置的邮箱有:ailiyun、qq,163等
#设置登录及服务器信息
import poplib
#import settings
import imaplib
import email  #导入两个库

import base64
from email.parser import Parser
from email.header import decode_header
from email.utils import parseaddr

class UserInfo:
    def __init__(self,mail_address,mail_password):
        self.mail_user_name = mail_address.split("@")[0] # 邮件用户名
        self.mail_password = mail_password 
        self.mail_address = mail_address
## 收发邮箱的配置         
class MailSettings:
    # port => 126,: 25 qq和163: 465 ,ssl: 443,ailiyun:993
    def __init__(self,name,send_host,send_port,server_host,server_port,is_ssl_host ):
        self.send_port = send_port
        self.send_host = send_host
        self.server_host = server_host
        self.server_port = server_port
        self.is_ssl_host= is_ssl_host
        self.name = name

def get_attaches():
    pass

## 指一次邮件内容,发送多个不同的收件人
## 如果一次邮件发送,只显示一个收件人,如果有N个收件人,就需要定义N个邮件的message
def set_email_from_and_to_info(user,receivers,subject):# subject 是一个说明
    #添加一个MIMEmultipart类,处理正文及附件
    message = MIMEMultipart()
    message['From'] = user.mail_address
    message['To'] = ", ".join(receivers) ## 可以针对多个,这个会在这封邮件上显示所有的发送的邮件
    message['Subject'] = subject
    return message
## 可以处理各类附件
def set_content_and_attaches(message,content_body,content_type,attache_paths):
    
    #正文通常有html和普通文本(plain)格式; html格式比较方便排版和制表
    content = MIMEText(content_body, content_type, 'utf-8') ## plain 和 html不同的方式
    message.attach(content) ## 正文 
    ## 下面处理相关的附件
    attach_num =0
    for attach_path in attache_paths:
        attach_num += 1
        attach_name = get_filename_from_path(attach_path) ## 把路径拆成文件
        file_name = "附件_:"+ str(attach_num) + ":" + attach_name
        _part = MIMEApplication(open(attach_path,'rb').read()) ## 附件1
        _part.add_header('Content-Disposition', 'attachment', filename=file_name)
        message.attach(_part)
    return message

def get_filename_from_path(path):
    split_info = path.split("\\")
    return split_info[-1]

def send_email(message,user,mail_info,receivers): ## to be continued
    try:
        if mail_info.is_ssl_host:
            print("smtp_ssl connect -> ")
            smtp = smtplib.SMTP_SSL(mail_info.send_host,mail_info.send_port) ## 
            #smtp.set_debuglevel(2) ## 如果需要打印出调试信息的话
        else:
            print("smtp connect ->")
            smtp = smtplib.SMTP()
            smtp.connect(mail_info.send_host,mail_info.send_port) 
            smtp.ehlo()
            smtp.starttls()
            #smtp.set_debuglevel(2) ## 如果需要打印出调试信息的话
        print("login .....")
        smtp.login(user.mail_user_name,user.mail_password)
        ## 单独发送还是统一发送
        print("login 成功! send_mail....")
        #print(message)
        smtp.sendmail(user.mail_address,receivers,message.as_string()) ##单独发送;不是集合发送; 统一发送是另外模式
        print('邮件发送成功!',receivers)
        smtp.quit()
    except smtplib.SMTPException as e:
        print('邮件发送失败,具体信息:',e)

# SMTP 协议用于发送邮件,POP3 和 IMAP 协议用于接收邮件
def pop_receive_email(user,mail_info):
    try:
        # 连接到POP3服务器:
        server = poplib.POP3(mail_info.server_host) #settings.pop3_server)
        # 身份认证:
        server.user(user.mail_user_name) # mail_address ?
        server.pass_(user.mail_password)
        
        # stat()返回邮件数量和占用空间:
        print('Messages: %s. Size: %s' % server.stat())
        # list()返回所有邮件的编号:
        resp, mails, octets = server.list()
        # 可以查看返回的列表类似[b'1 82923', b'2 2184', ...]
        
        # 获取最新一封邮件, 注意索引号从1开始:
        latest_mail_index = len(mails)
        resp, lines, octets = server.retr(latest_mail_index)

        # lines存储了邮件的原始文本的每一行,
        # 可以获得整个邮件的原始文本:
        msg_content = b'\r\n'.join(lines).decode('gbk') ## utf-8
        # 稍后解析出邮件:
        msg = Parser().parsestr(msg_content)
        print(msg)
        # 邮件索引号直接从服务器删除邮件
        # server.dele(index)
        # 关闭连接:
        server.quit()
    except BaseException as e: 
        print(e)


def imap_receive_email(user,mail_info):
    try:
        M = imaplib.IMAP4_SSL(host = mail_info.server_host,port = mail_info.server_port)
        print('已连接服务器')
        M.login(user.mail_user_name,user.mail_password)
        print('已登陆')
        print(M.noop())
        M.select()
        
        typ, data = M.search(None, 'ALL')
        for num in data[0].split():
            typ, data = M.fetch(num, '(RFC822)')
            # print('Message %s\n%s\n' % (num, data[0][1]))
            # print(data[0][1].decode('utf-8'))
            msg = email.message_from_string(data[0][1].decode('gbk')) # bug
            print(msg)
            break
        M.close()
        M.logout()
    except BaseException as e:
        print(e)

# 主题解析
def parser_subject(msg):
    subject = msg['Subject']
    value, charset = decode_header(subject)[0]
    if charset:
        value = value.decode(charset)
        print('邮件主题: {0}'.format(value))
    return value
# 邮件信息解析
def parser_address(msg):
    hdr, addr = parseaddr(msg['From'])
	# name 发送人邮箱名称, addr 发送人邮箱地址
    name, charset = decode_header(hdr)[0]
    if charset:
        name = name.decode(charset)
    print('发送人邮箱名称: {0},发送人邮箱地址: {1}'.format(name, addr))

## 如何收特定日期的邮件?
## 邮件的接收是全量推送?
## 邮件的解析,如何落附件?

qq_send_host = 'smtp.qq.com'#
qq_server_host = "imap.qq.com" 
qq_send_port = 465 #465
qq_server_port = 993 ## 收邮件
qq_is_ssl_host = True

mail_address = '*****@qq.com'
mail_pass ='n********' ## qq是授权码,不是账户密码

receivers = ['h*****@sina.com.cn',"s****@163.com"]
subject = "标题:这是测试邮件,请不要回复!"
content_body = "正文:这是测试邮件的正文"
content_type = "plain"

#content_html = r'D:\mail\content.html' # 正文html空模版

attach_01 = r"D:\mail\df_y.csv" # xlsx
attach_02 = r'D:\mail\签名.jpg' #jpg
attach_03 = r'D:\mail\上海房地产市场最新报告.pdf' #pdf
attaches = [attach_01,attach_02,attach_03]

user = UserInfo(mail_address,mail_pass)
mail_settings = MailSettings("qq",qq_send_host,qq_send_port,qq_server_host,qq_server_port,qq_is_ssl_host)
mode = 1 # 0 :=>发邮件; 1: 收邮件
if mode ==0:
    message = set_email_from_and_to_info(user,receivers,subject)
    message = set_content_and_attaches(message,content_body,content_type,attaches)
    #print("message :",message)
    send_email(message,user,mail_settings,receivers)
else:
    if 'imap' in mail_settings.server_host: # imap
        imap_receive_email(user,mail_settings)
    else:                                   # pop3
        pop_receive_email(user,mail_settings)
      
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值