电子邮件的历史起源

  • 1969 Leonard K. 教授发给同时的 “LO”
  • 1971 美国国防部自主的阿帕网(Arpanet)的通讯机制
  • 通讯地址里用@,
  • 1987年中国的第一份电子邮件  “Across the Great Wall we can reach every corner in the world"

管理程序

  • Euroda使邮件普及
  • Netscape,outlook,forxmail后来居上
  • Hotmal使用浏览器发送邮件i

参考资料

  • [官网](https://docs.python.org/3/library/email.mime.html)

邮件工作流程

  • MUA(MailUserAgent)邮件用户代理
  • MTA(MailTransferAgent)邮件传输代理
  • MDA(MailDeliveryAgent)邮件投递代理
  • 流程
  1. MUA->MTA, 邮件已经在服务器上了
  2. qq MTA->.........->sina MTA, 邮件在新浪的服务器上
  3. sina MTA-> sina MDA, 此时邮件已经在你的邮箱里了
  4. sina MDA -> MUA(Foxmail/Outlook), 邮件下载到本地电脑

编写程序

  • 发送:  MUA->MTA with SMTP:SimpleMailTransferProtocal,包含MTA->MTA
  • 接受:  MDA->MUA with POP3 and IMAP:PostOfficeProtocal v3 and  InternetMessageAccessProtocal v4

准备工作

  • 注册邮箱(以qq邮箱为例)
  • 第三方邮箱需要特殊设置, 以qq邮箱为例
    • 进入设置中心
    • 取得授权码

Python for mail

1.SMTP协议负责发送邮件

  • 使用email模块构建邮件

    • 纯文本邮件
    • 案例见下方代码
  • HTML格式邮件发送
    • 准备HTML代码作为内容
    • 把邮件的subtpye设为html
    • 发送
    • 案例见下方代码
  • 发送带附件的邮件
    • 可以把邮件看作是一个文本邮件和一个附件的合体
    • 一封邮件如果涉及多个部分,需要使用MIMEMultipart格式构建
    • 添加一个MIMEText正文
    • 添加一个MIMEBase或者MEMEText作为附件
    • 案例见下方代码
  • 添加邮件头, 抄送等信息
    • mail["From"] 表示发送着信息,包括姓名和邮件
    • mail["To"]  表示接收者信息,包括姓名和邮件地址
    • mail["Subject"] 表示摘要或者主题信息
    • 案例见下方代码
  • 同时支持html和text格式
    • 构建一个MIMEMultipart格式邮件
    • MIMEMultipart的subtype设置成alternative格式
    • 添加HTML和text邮件
    • 案例见下方代码
  • 使用smtplib模块发送邮件

2.POP3协议接受邮件

  • 本质上是MDA到MUA的一个过程
  • 从 MDA下载下来的是一个完整的邮件结构体,需要解析才能得到每个具体可读的内容
  • 步骤:

1. 用poplib下载邮件结构体原始内容
                1. 准备相应的内容(邮件地址,密码,POP3实例)
                2. 身份认证
                3. 一般会先得到邮箱内邮件的整体列表
                4. 根据相应序号,得到某一封信的数据流
                5. 利用解析函数进行解析出相应的邮件结构体
            2. 用email解析邮件的具体内容

  • 案例见下方代码

使用email模块构建邮件案例:

# 导入相应的包
import smtplib
from email.mime.text import MIMEText
# MIMEText三个主要参数
# 1. 邮件内容
# 2. MIME子类型,在此案例我们用plain表示text类型
# 3. 邮件编码格式msg = MIMEText("Hello, i am beijing tulingxueyuan ", "plain", "utf-8")# 发送email地址,此处地址直接使用我的qq有偶像,密码一般需要临时输入,此处偷懒
from_addr = "1366798119@qq.com"
# 此处密码是经过申请设置后的授权码,不是不是不是你的qq邮箱密码
from_pwd = "hjpovygcxmrshhcj"# 收件人信息
# 此处使用qq邮箱,我给自己发送
to_addr = "1366798119@qq.com"# 输入SMTP服务器地址
# 此处根据不同的邮件服务商有不同的值,
# 现在基本任何一家邮件服务商,如果采用第三方收发邮件,都需要开启授权选项
# 腾讯qq邮箱所的smtp地址是 smtp.qq.comsmtp_srv = "smtp.qq.com"try:# 两个参数# 第一个是服务器地址,但一定是bytes格式,所以需要编码# 第二个参数是服务器的接受访问端口srv = smtplib.SMTP_SSL(smtp_srv.encode(), 465) #SMTP协议默认端口25#登录邮箱发送srv.login(from_addr, from_pwd)# 发送邮件# 三个参数# 1. 发送地址# 2. 接受地址,必须是list形式# 3. 发送内容,作为字符串发送srv.sendmail(from_addr, [to_addr], msg.as_string())srv.quit()
except Exception as e:print(e)

HTML格式邮件发送案例:

from email.mime.text import  MIMETextmail_content = """<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>Title</title></head><body><h1> 这是一封HTML格式邮件</h1></body></html>"""msg = MIMEText(mail_content, "html", "utf-8")# 构建发送者地址和登录信息
from_addr = "1366798119@qq.com"
from_pwd = "hjpovygcxmrshhcj"# 构建邮件接受者信息
to_addr = "1366798119@qq.com"smtp_srv = "smtp.qq.com"try:import smtplibsrv = smtplib.SMTP_SSL(smtp_srv.encode(), 465)srv.login(from_addr, from_pwd)srv.sendmail(from_addr, [to_addr], msg.as_string())srv.quit()except Exception as e:print(e)

发送带附件的邮件案例:

from email.mime.text import MIMEText #构建附件使用
from email.mime.multipart import MIMEBase, MIMEMultipart # 构建基础邮件使用mail_mul = MIMEMultipart()
# 构建邮件正文
mail_text = MIMEText("Hello, i am liudana", "plain", "utf-8")
# 把构建好的邮件正文附加入邮件中
mail_mul.attach(mail_text)# 构建附加
# 构建附件,需要从本地读入附件
# 打开一个本地文件
# 以rb格式打开
with open("02.html", "rb") as f:s = f.read()# 设置附件的MIME和文件名m = MIMEText(s, 'base64', "utf-8")m["Content-Type"] = "application/octet-stream"# 需要注意,# 1. attachment后分好为英文状态# 2. filename 后面需要用引号包裹,注意与外面引号错开m["Content-Disposition"] = "attachment; filename='02.html'"# 添加到MIMEMultipartmail_mul.attach(m)# 发送email地址,此处地址直接使用我的qq有偶像,密码一般需要临时输入,此处偷懒
from_addr = "1366798119@qq.com"
# 此处密码是经过申请设置后的授权码,不是不是不是你的qq邮箱密码
from_pwd = "hjpovygcxmrshhcj"# 收件人信息
# 此处使用qq邮箱,我给自己发送
to_addr = "1366798119@qq.com"# 输入SMTP服务器地址
# 此处根据不同的邮件服务商有不同的值,
# 现在基本任何一家邮件服务商,如果采用第三方收发邮件,都需要开启授权选项
# 腾讯qq邮箱所的smtp地址是 smtp.qq.comsmtp_srv = "smtp.qq.com"try:import smtplibsrv = smtplib.SMTP_SSL(smtp_srv.encode(), 465) #SMTP协议默认端口25#登录邮箱发送srv.login(from_addr, from_pwd)# 发送邮件# 三个参数# 1. 发送地址# 2. 接受地址,必须是list形式# 3. 发送内容,作为字符串发送srv.sendmail(from_addr, [to_addr], mail_mul.as_string())srv.quit()
except Exception as e:print(e)

添加邮件头, 抄送等信息案例:

from email.mime.text import MIMEText
from email.header import Headermsg = MIMEText("Hello wold",  "plain", "utf-8")
# 下面代码故意写错,说明,所谓的发送者的地址,只是从一个Header的第一个参数作为字符串构建的内容
# 用utf8编码是因为很可能内容包含非英文字符
header_from = Header("从图灵学院邮箱发出去的<TuLingXueYuan@qq.cn>", "utf-8")
msg['From'] = header_from# 填写接受者信息
header_to = Header("去王晓静的地方<wangxiaojing@sina.com>", 'utf-8')
msg['To'] = header_toheader_sub = Header("这是图灵学院的主题", 'utf-8')
msg['Subject'] = header_sub# 构建发送者地址和登录信息
from_addr = "1366798119@qq.com"
from_pwd = "hjpovygcxmrshhcj"# 构建邮件接受者信息
to_addr = "1366798119@qq.com"smtp_srv = "smtp.qq.com"try:import smtplibsrv = smtplib.SMTP_SSL(smtp_srv.encode(), 465)srv.login(from_addr, from_pwd)srv.sendmail(from_addr, [to_addr], msg.as_string())srv.quit()except Exception as e:print(e)

同时支持html和text格式案例:

from email.mime.text import  MIMEText
from email.mime.multipart import  MIMEMultipart# 构建一个MIMEMultipart邮件
msg = MIMEMultipart("alternative")# 构建一个HTML邮件内容
html_content = """<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>Title</title></head><body><h1> 这是一封HTML格式邮件</h1></body></html>"""
#
msg_html = MIMEText(html_content, "html", "utf-8")
msg.attach(msg_html)msg_text = MIMEText("just text content", "plain", "utf-8")
msg.attach(msg_text)# 发送email地址,此处地址直接使用我的qq邮箱,密码临时输入
from_addr = "1366798119@qq.com"
#from_pwd = input('163邮箱密码: ')
from_pwd = "hjpovygcxmrshhcj"# 收件人信息:
# 此处使用我注册的163邮箱
to_addr = "1366798119@qq.com"# 输入SMTP服务器地址:
# 此地址根据每隔邮件服务商有不同的值,这个是发信邮件服务商的smtp地址
# 我用的是qq邮箱发送,此处应该填写腾讯qq邮箱的smtp值,即smtp.163.com,
# 需要开启授权码,
smtp_srv = "smtp.qq.com"try:import smtplib# 加密传输#server = smtplib.SMTP_SSL(smtp_srv.encode(), 465) # SMTP协议默认端口是25# qq邮箱要求使用 TLS加密传输server = smtplib.SMTP(smtp_srv.encode(), 25) # SMTP协议默认端口是25server.starttls()# 设置调试级别# 通过设置调试等级,可以清楚的看到发送邮件的交互步骤server.set_debuglevel(1)# 登录发送邮箱server.login(from_addr, from_pwd)server.sendmail(from_addr, [to_addr], msg.as_string())server.quit()
except Exception as e:print(e)

POP3协议接受邮件案例:

# 导入相关包
# poplib负责从MDA到MUA下载
import poplib# 以下包负责相关邮件结构解析
from email.parser import Parser
from email.header import decode_header
from email.utils import parseaddr# 得到邮件的原始内容
# 这个过程主要负责从MDA到MUA的下载并使用Parse粗略解析
def getMsg():# 准备相应的信息email = "1366798119@qq.com"# 邮箱的授权码pwd = "hjpovygcxmrshhcj"# pop3服务器地址pop3_srv = "pop.qq.com" # 端口995# ssl代表是安全通道srv = poplib.POP3_SSL(pop3_srv)# user代表email地址srv.user(email)# pass_代表密码srv.pass_(pwd)# 以下操作根据具体业务具体使用# stat返回邮件数量和占用空间# 注意stat返回一个tuple格式msgs, counts = srv.stat()print("Messages: {0}, Size: {1}".format(msgs, counts))# list返回所有邮件编号列表# mails是所有邮件编号列表rsp, mails, octets = srv.list()# 可以查看返回的mails列表类似[b'1 82923', b'2 2184', ...]print(mails)# 获取最新一封邮件,注意,邮件索引号是从1开始, 最新代表索引号最高index = len(mails)# retr负责返回一个具体索引号的一封信的内容,此内容不具有可读性# lines 存储邮件的最原始文本的每一行rsp, lines, octets = srv.retr(index)# 获得整个邮件的原始文本msg_count = b'\r\n'.join(lines).decode("utf-8")# 解析出邮件整个结构体# 参数是解码后的邮件整体msg = Parser().parsestr(msg_count)#关闭链接srv.quit()return msg# 详细解析得到的邮件内容
# msg代表是邮件的原始内容
# idnent代表的是邮件嵌套的层级
def parseMsg(msg, indent=0):'''1. 邮件完全可能是有嵌套格式2. 邮件只有一个From,To,Subject之类的信息:param msg::param indent: 描述邮件里面有几个邮件MIMEXXX类型的内容,展示的时候进行相应缩进:return:'''# 想办法提取出头部信息# 只有在第一层的邮件中才会有相关内容,# 此内容只有一个if indent == 0:for header in ['From', "To", 'Subject']:# 使用get可以避免如果没有相关关键字报错的可能性# 如果没有 关键字”From“, 我们使用 msg["From"]会报错value = msg.get(header, '')if value:# Subject中的内容直接解码就可以,他是字符串类型if header == 'Subject':value = decodeStr(value)# 如果是From和To字段,则内容大概是 "我的邮箱<xxxxx@qq.com>“这种格式else:hdr, addr = parseaddr(value)name = decodeStr(hdr)# 最终返回形如  "我的邮箱<xxx@qq.com>的格式value = "{0}<{1}>".format(name, addr)print("{0}, {1}: {2}".format(indent, header, value))# 下面代码关注邮件内容本身# 邮件内容中,有可能是multipart类型,也有可能是普通邮件类型# 下面的解析使用递归方式if (msg.is_multipart()):# 如果是multipart类型,则调用递归解析# 得到多部分邮件的一个基础邮件部分parts = msg.get_payload()# enumerate 函数是内置函数# 作用是将一个列表,此处是parts,生成一个有索引和parts原内容构成的新的列表# 例如 enumerate(['a', 'b', 'c']) 结果是:  [(1,'a'), (2, 'b'), (3, 'c')]for n,part in enumerate(parts):# 一个字符串乘以一个数字的意思是对这个字符串进行n倍扩展# 比如 ”aa" * 2 -> "aaaa"print("{0}spart: {1}".format(' '*indent, n))parseMsg(part, indent+1)else: # 基础类型# get_content_type是系统提供函数,得到内容类型content_type = msg.get_content_type()# text/plain 或者 text/html是固定值if content_type == 'text/plain' or content_type == 'text/html':content = msg.get_payload(decode=True)charset = guessCharset(msg)if charset:content = content.decode(charset)print("{0}Text: {1}".format(indent, content))else: #不是文本内容,则应该是附件print('{0}Attachment: {1}'.format(indent, content_type))def decodeStr(s):'''s代表一封邮件中From,To,Subject中的任一项对s进行解码,解码是编码的逆过程:param s::return:'''value, charset = decode_header(s)[0]# charset完全可能为空if charset:# 如果指定编码,则用指定编码格式进行解码value = value.decode(charset)return valuedef guessCharset(msg):'''猜测邮件的编码格式:param msg::return:'''# 调用现成的函数charset = msg.get_charset()if charset is None:# 找到内容类型,并转换成小写content_type = msg.get("Content-Type", "").lower()pos = content_type.find("charset=")if pos >= 0:# 如果包含chraset,则内容形如 charset=xxxxcharset = content_type[pos+8:].strip()return  charsetif __name__ == "__main__":# 得到邮件的原始内容msg = getMsg()print(msg)# 精确解析邮件内容parseMsg(msg, 0)

Python之Mail编程(电子邮件编程)相关推荐

  1. Python 的电子邮件编程

    目录 python 的电子邮件编程 1.开启SMTP服务设置, 获取验证码 2.编写Python程序发送邮件示例 python 的电子邮件编程 两个内建模块 email 模块, 用于准备邮件内容的模块 ...

  2. 用python解算法谜题_编程的乐趣 用Python解算法谜题

    这是一本介绍通过解决复杂谜题来学习编程的书,书中的代码用Python语言编写.与以往的编程书不同,本书将对代码功能的理解与编程语言语法和语义的理解分离开来,从解每个谜题开始,先给出解谜题的算法,随后用 ...

  3. 全国青少年软件编程python等级考试-全国青少年软件编程等级考试:Python一级考试大纲...

    少儿编程:全国青少年软件编程等级考试 考试性质 全国青少年软件编程等级考试标准(Python)由中国电子学会科普培训与应用推广中心指定.由全国青少年电子信息科普创新联盟标准工作组开发,由中国电子学会普 ...

  4. python界面颜色-给Python点颜色——青少年学编程

    书名:给Python点颜色--青少年学编程 定价:59.8 ISBN:9787115512321 作者:佘友军 版次:第1版 出版时间:2019-09 内容提要: 面对科技驱动的未来,编程是学生们茁壮 ...

  5. VII Python(9)socket编程

    VII Python(9)socket编程 socket编程: 网络基础: TCP/IP: socket模型: python socket C/S开发: 非阻塞(select.poll.epoll) ...

  6. Python学习笔记:面向对象编程(1)

    前言 最近在学习深度学习,已经跑出了几个模型,但Pyhton的基础不够扎实,因此,开始补习Python了,大家都推荐廖雪峰的课程,因此,开始了学习,但光学有没有用,还要和大家讨论一下,因此,写下这些帖 ...

  7. Dave Python 练习十五 -- 面向对象编程

    #encoding=utf-8 ### *************** 面向对象编程 ******************** #*********** Part 1: 面向对象编程 ******** ...

  8. python流行趋势_Python流行度再创新高,学Python就从风变编程开始

    10月初,全球编程语言社区TIOBE公布了2020年10月编程语言排行榜,排名情况相较前几个月变化不大,前十名分别为C.Java.Python.C++ .C#.Visual Basic.JavaScr ...

  9. python教程很详细_Python编程入门教程:从入门到高级,非常详细

    本文的资料和内容是我下载的,觉得非常有用,于是转过来大家瞧瞧: 这里给初学Python的朋友提供一些建议和指导吧.大神请无视, 俗话说:授人以鱼不如授人以渔.所以我这里只是阐述学习过程,并不会直接详细 ...

最新文章

  1. 模板模式(TemplateMethod)和策略(StrategyMethod)模式
  2. 设计模式之四:抽象工厂(披萨店生产披萨模拟流程)
  3. 分布式系统基本副本协议
  4. Activiti源码 之 DataManager EntityManager
  5. android 多线程类,Android 多线程处理之多线程用法大集合
  6. 手写一款符合Promise/A+规范的Promise
  7. IOS开发之视图和视图控制器
  8. this指向问题 php,js中的this指向问题
  9. 分享Android开发的一些工具
  10. 嵌入式C语言面试题剖析100,嵌入式c语言面试题汇总超.docx
  11. 各大平台热搜排行榜原型
  12. 面阵相机行业研究分析报告
  13. 多元线性回归的spss应用
  14. alm系统的使用流程_HPQC测试管理平台ALM操作使用手册.doc
  15. 免认证使用校园网(2022.6.3更新)
  16. 数据预处理的步骤和方法
  17. F:\ 上的回收站已损坏。是否清空该驱动器上的“回收站“?
  18. One-hot的使用
  19. R语言实战应用精讲50篇(三十)-R语言实现支持向量机(附R语言代码)
  20. CAXA AutoCAD标注小数后位数设置

热门文章

  1. 自动化运维(使用api自动化管理f5设备)
  2. MCE公司:MCE 中国生命科学研究促进奖获奖论文集锦一
  3. flume三种方式收集日志的案例
  4. scott被锁住了怎么办
  5. 分布式系统的容错性(二)——检错和纠错
  6. VBA程序 在PPT中使用宏命令删除空白的文本框
  7. python + selenium 实现 问卷星自动抢讲座
  8. http://www.xxjp.org/Software/Catalog96/1681.html
  9. L289N驱动小车方向
  10. 16款蔬果 吃吃就降糖