Python之Mail编程(电子邮件编程)
生活随笔
收集整理的這篇文章主要介紹了
Python之Mail编程(电子邮件编程)
小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
電子郵件的歷史起源
- 1969 Leonard K. 教授發(fā)給同時(shí)的 “LO”
- 1971 美國(guó)國(guó)防部自主的阿帕網(wǎng)(Arpanet)的通訊機(jī)制
- 通訊地址里用@,?
- 1987年中國(guó)的第一份電子郵件 ?“Across the Great Wall we can reach every corner in the world"
管理程序
- Euroda使郵件普及?
- Netscape,outlook,forxmail后來(lái)居上
- Hotmal使用瀏覽器發(fā)送郵件i
參考資料
- ?[官網(wǎng)](https://docs.python.org/3/library/email.mime.html)
郵件工作流程
- MUA(MailUserAgent)郵件用戶代理
- MTA(MailTransferAgent)郵件傳輸代理
- MDA(MailDeliveryAgent)郵件投遞代理
- 流程
編寫程序
- 發(fā)送: ?MUA->MTA with SMTP:SimpleMailTransferProtocal,包含MTA->MTA
- 接受: ?MDA->MUA with POP3 and IMAP:PostOfficeProtocal v3 and ?InternetMessageAccessProtocal v4
? ??
準(zhǔn)備工作
- 注冊(cè)郵箱(以qq郵箱為例)
- 第三方郵箱需要特殊設(shè)置, 以qq郵箱為例
- 進(jìn)入設(shè)置中心
- 取得授權(quán)碼
? ? ? ??
Python for mail
1.SMTP協(xié)議負(fù)責(zé)發(fā)送郵件
- 使用email模塊構(gòu)建郵件
- 純文本郵件
- 案例見(jiàn)下方代碼
- HTML格式郵件發(fā)送
- 準(zhǔn)備HTML代碼作為內(nèi)容
- ?把郵件的subtpye設(shè)為html
- 發(fā)送
- 案例見(jiàn)下方代碼
- 發(fā)送帶附件的郵件
- 可以把郵件看作是一個(gè)文本郵件和一個(gè)附件的合體
- 一封郵件如果涉及多個(gè)部分,需要使用MIMEMultipart格式構(gòu)建
- 添加一個(gè)MIMEText正文
- 添加一個(gè)MIMEBase或者M(jìn)EMEText作為附件
- 案例見(jiàn)下方代碼
- 添加郵件頭, 抄送等信息
- mail["From"] 表示發(fā)送著信息,包括姓名和郵件
- mail["To"] ?表示接收者信息,包括姓名和郵件地址
- mail["Subject"] 表示摘要或者主題信息
- 案例見(jiàn)下方代碼
- 同時(shí)支持html和text格式
- 構(gòu)建一個(gè)MIMEMultipart格式郵件
- MIMEMultipart的subtype設(shè)置成alternative格式
- 添加HTML和text郵件
- 案例見(jiàn)下方代碼
- 使用smtplib模塊發(fā)送郵件
2.POP3協(xié)議接受郵件?
- 本質(zhì)上是MDA到MUA的一個(gè)過(guò)程
- 從 MDA下載下來(lái)的是一個(gè)完整的郵件結(jié)構(gòu)體,需要解析才能得到每個(gè)具體可讀的內(nèi)容
- 步驟:
? ? ? ? ? ? 1. 用poplib下載郵件結(jié)構(gòu)體原始內(nèi)容
? ? ? ? ? ? ? ? 1. 準(zhǔn)備相應(yīng)的內(nèi)容(郵件地址,密碼,POP3實(shí)例)
? ? ? ? ? ? ? ? 2. 身份認(rèn)證
? ? ? ? ? ? ? ? 3. 一般會(huì)先得到郵箱內(nèi)郵件的整體列表
? ? ? ? ? ? ? ? 4. 根據(jù)相應(yīng)序號(hào),得到某一封信的數(shù)據(jù)流
? ? ? ? ? ? ? ? 5. 利用解析函數(shù)進(jìn)行解析出相應(yīng)的郵件結(jié)構(gòu)體
? ? ? ? ? ? 2. 用email解析郵件的具體內(nèi)容
- 案例見(jiàn)下方代碼
使用email模塊構(gòu)建郵件案例:
# 導(dǎo)入相應(yīng)的包 import smtplib from email.mime.text import MIMEText # MIMEText三個(gè)主要參數(shù) # 1. 郵件內(nèi)容 # 2. MIME子類型,在此案例我們用plain表示text類型 # 3. 郵件編碼格式msg = MIMEText("Hello, i am beijing tulingxueyuan ", "plain", "utf-8")# 發(fā)送email地址,此處地址直接使用我的qq有偶像,密碼一般需要臨時(shí)輸入,此處偷懶 from_addr = "1366798119@qq.com" # 此處密碼是經(jīng)過(guò)申請(qǐng)?jiān)O(shè)置后的授權(quán)碼,不是不是不是你的qq郵箱密碼 from_pwd = "hjpovygcxmrshhcj"# 收件人信息 # 此處使用qq郵箱,我給自己發(fā)送 to_addr = "1366798119@qq.com"# 輸入SMTP服務(wù)器地址 # 此處根據(jù)不同的郵件服務(wù)商有不同的值, # 現(xiàn)在基本任何一家郵件服務(wù)商,如果采用第三方收發(fā)郵件,都需要開(kāi)啟授權(quán)選項(xiàng) # 騰訊qq郵箱所的smtp地址是 smtp.qq.comsmtp_srv = "smtp.qq.com"try:# 兩個(gè)參數(shù)# 第一個(gè)是服務(wù)器地址,但一定是bytes格式,所以需要編碼# 第二個(gè)參數(shù)是服務(wù)器的接受訪問(wèn)端口srv = smtplib.SMTP_SSL(smtp_srv.encode(), 465) #SMTP協(xié)議默認(rèn)端口25#登錄郵箱發(fā)送srv.login(from_addr, from_pwd)# 發(fā)送郵件# 三個(gè)參數(shù)# 1. 發(fā)送地址# 2. 接受地址,必須是list形式# 3. 發(fā)送內(nèi)容,作為字符串發(fā)送srv.sendmail(from_addr, [to_addr], msg.as_string())srv.quit() except Exception as e:print(e)HTML格式郵件發(fā)送案例:
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")# 構(gòu)建發(fā)送者地址和登錄信息 from_addr = "1366798119@qq.com" from_pwd = "hjpovygcxmrshhcj"# 構(gòu)建郵件接受者信息 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)發(fā)送帶附件的郵件案例:
from email.mime.text import MIMEText #構(gòu)建附件使用 from email.mime.multipart import MIMEBase, MIMEMultipart # 構(gòu)建基礎(chǔ)郵件使用mail_mul = MIMEMultipart() # 構(gòu)建郵件正文 mail_text = MIMEText("Hello, i am liudana", "plain", "utf-8") # 把構(gòu)建好的郵件正文附加入郵件中 mail_mul.attach(mail_text)# 構(gòu)建附加 # 構(gòu)建附件,需要從本地讀入附件 # 打開(kāi)一個(gè)本地文件 # 以rb格式打開(kāi) with open("02.html", "rb") as f:s = f.read()# 設(shè)置附件的MIME和文件名m = MIMEText(s, 'base64', "utf-8")m["Content-Type"] = "application/octet-stream"# 需要注意,# 1. attachment后分好為英文狀態(tài)# 2. filename 后面需要用引號(hào)包裹,注意與外面引號(hào)錯(cuò)開(kāi)m["Content-Disposition"] = "attachment; filename='02.html'"# 添加到MIMEMultipartmail_mul.attach(m)# 發(fā)送email地址,此處地址直接使用我的qq有偶像,密碼一般需要臨時(shí)輸入,此處偷懶 from_addr = "1366798119@qq.com" # 此處密碼是經(jīng)過(guò)申請(qǐng)?jiān)O(shè)置后的授權(quán)碼,不是不是不是你的qq郵箱密碼 from_pwd = "hjpovygcxmrshhcj"# 收件人信息 # 此處使用qq郵箱,我給自己發(fā)送 to_addr = "1366798119@qq.com"# 輸入SMTP服務(wù)器地址 # 此處根據(jù)不同的郵件服務(wù)商有不同的值, # 現(xiàn)在基本任何一家郵件服務(wù)商,如果采用第三方收發(fā)郵件,都需要開(kāi)啟授權(quán)選項(xiàng) # 騰訊qq郵箱所的smtp地址是 smtp.qq.comsmtp_srv = "smtp.qq.com"try:import smtplibsrv = smtplib.SMTP_SSL(smtp_srv.encode(), 465) #SMTP協(xié)議默認(rèn)端口25#登錄郵箱發(fā)送srv.login(from_addr, from_pwd)# 發(fā)送郵件# 三個(gè)參數(shù)# 1. 發(fā)送地址# 2. 接受地址,必須是list形式# 3. 發(fā)送內(nèi)容,作為字符串發(fā)送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") # 下面代碼故意寫錯(cuò),說(shuō)明,所謂的發(fā)送者的地址,只是從一個(gè)Header的第一個(gè)參數(shù)作為字符串構(gòu)建的內(nèi)容 # 用utf8編碼是因?yàn)楹芸赡軆?nèi)容包含非英文字符 header_from = Header("從圖靈學(xué)院郵箱發(fā)出去的<TuLingXueYuan@qq.cn>", "utf-8") msg['From'] = header_from# 填寫接受者信息 header_to = Header("去王曉靜的地方<wangxiaojing@sina.com>", 'utf-8') msg['To'] = header_toheader_sub = Header("這是圖靈學(xué)院的主題", 'utf-8') msg['Subject'] = header_sub# 構(gòu)建發(fā)送者地址和登錄信息 from_addr = "1366798119@qq.com" from_pwd = "hjpovygcxmrshhcj"# 構(gòu)建郵件接受者信息 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)同時(shí)支持html和text格式案例:
from email.mime.text import MIMEText from email.mime.multipart import MIMEMultipart# 構(gòu)建一個(gè)MIMEMultipart郵件 msg = MIMEMultipart("alternative")# 構(gòu)建一個(gè)HTML郵件內(nèi)容 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)# 發(fā)送email地址,此處地址直接使用我的qq郵箱,密碼臨時(shí)輸入 from_addr = "1366798119@qq.com" #from_pwd = input('163郵箱密碼: ') from_pwd = "hjpovygcxmrshhcj"# 收件人信息: # 此處使用我注冊(cè)的163郵箱 to_addr = "1366798119@qq.com"# 輸入SMTP服務(wù)器地址: # 此地址根據(jù)每隔郵件服務(wù)商有不同的值,這個(gè)是發(fā)信郵件服務(wù)商的smtp地址 # 我用的是qq郵箱發(fā)送,此處應(yīng)該填寫騰訊qq郵箱的smtp值,即smtp.163.com, # 需要開(kāi)啟授權(quán)碼, smtp_srv = "smtp.qq.com"try:import smtplib# 加密傳輸#server = smtplib.SMTP_SSL(smtp_srv.encode(), 465) # SMTP協(xié)議默認(rèn)端口是25# qq郵箱要求使用 TLS加密傳輸server = smtplib.SMTP(smtp_srv.encode(), 25) # SMTP協(xié)議默認(rèn)端口是25server.starttls()# 設(shè)置調(diào)試級(jí)別# 通過(guò)設(shè)置調(diào)試等級(jí),可以清楚的看到發(fā)送郵件的交互步驟server.set_debuglevel(1)# 登錄發(fā)送郵箱server.login(from_addr, from_pwd)server.sendmail(from_addr, [to_addr], msg.as_string())server.quit() except Exception as e:print(e)POP3協(xié)議接受郵件案例:
# 導(dǎo)入相關(guān)包 # poplib負(fù)責(zé)從MDA到MUA下載 import poplib# 以下包負(fù)責(zé)相關(guān)郵件結(jié)構(gòu)解析 from email.parser import Parser from email.header import decode_header from email.utils import parseaddr# 得到郵件的原始內(nèi)容 # 這個(gè)過(guò)程主要負(fù)責(zé)從MDA到MUA的下載并使用Parse粗略解析 def getMsg():# 準(zhǔn)備相應(yīng)的信息email = "1366798119@qq.com"# 郵箱的授權(quán)碼pwd = "hjpovygcxmrshhcj"# pop3服務(wù)器地址pop3_srv = "pop.qq.com" # 端口995# ssl代表是安全通道srv = poplib.POP3_SSL(pop3_srv)# user代表email地址srv.user(email)# pass_代表密碼srv.pass_(pwd)# 以下操作根據(jù)具體業(yè)務(wù)具體使用# stat返回郵件數(shù)量和占用空間# 注意stat返回一個(gè)tuple格式msgs, counts = srv.stat()print("Messages: {0}, Size: {1}".format(msgs, counts))# list返回所有郵件編號(hào)列表# mails是所有郵件編號(hào)列表rsp, mails, octets = srv.list()# 可以查看返回的mails列表類似[b'1 82923', b'2 2184', ...]print(mails)# 獲取最新一封郵件,注意,郵件索引號(hào)是從1開(kāi)始, 最新代表索引號(hào)最高index = len(mails)# retr負(fù)責(zé)返回一個(gè)具體索引號(hào)的一封信的內(nèi)容,此內(nèi)容不具有可讀性# lines 存儲(chǔ)郵件的最原始文本的每一行rsp, lines, octets = srv.retr(index)# 獲得整個(gè)郵件的原始文本msg_count = b'\r\n'.join(lines).decode("utf-8")# 解析出郵件整個(gè)結(jié)構(gòu)體# 參數(shù)是解碼后的郵件整體msg = Parser().parsestr(msg_count)#關(guān)閉鏈接srv.quit()return msg# 詳細(xì)解析得到的郵件內(nèi)容 # msg代表是郵件的原始內(nèi)容 # idnent代表的是郵件嵌套的層級(jí) def parseMsg(msg, indent=0):'''1. 郵件完全可能是有嵌套格式2. 郵件只有一個(gè)From,To,Subject之類的信息:param msg::param indent: 描述郵件里面有幾個(gè)郵件MIMEXXX類型的內(nèi)容,展示的時(shí)候進(jìn)行相應(yīng)縮進(jìn):return:'''# 想辦法提取出頭部信息# 只有在第一層的郵件中才會(huì)有相關(guān)內(nèi)容,# 此內(nèi)容只有一個(gè)if indent == 0:for header in ['From', "To", 'Subject']:# 使用get可以避免如果沒(méi)有相關(guān)關(guān)鍵字報(bào)錯(cuò)的可能性# 如果沒(méi)有 關(guān)鍵字”From“, 我們使用 msg["From"]會(huì)報(bào)錯(cuò)value = msg.get(header, '')if value:# Subject中的內(nèi)容直接解碼就可以,他是字符串類型if header == 'Subject':value = decodeStr(value)# 如果是From和To字段,則內(nèi)容大概是 "我的郵箱<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))# 下面代碼關(guān)注郵件內(nèi)容本身# 郵件內(nèi)容中,有可能是multipart類型,也有可能是普通郵件類型# 下面的解析使用遞歸方式if (msg.is_multipart()):# 如果是multipart類型,則調(diào)用遞歸解析# 得到多部分郵件的一個(gè)基礎(chǔ)郵件部分parts = msg.get_payload()# enumerate 函數(shù)是內(nèi)置函數(shù)# 作用是將一個(gè)列表,此處是parts,生成一個(gè)有索引和parts原內(nèi)容構(gòu)成的新的列表# 例如 enumerate(['a', 'b', 'c']) 結(jié)果是: [(1,'a'), (2, 'b'), (3, 'c')]for n,part in enumerate(parts):# 一個(gè)字符串乘以一個(gè)數(shù)字的意思是對(duì)這個(gè)字符串進(jìn)行n倍擴(kuò)展# 比如 ”aa" * 2 -> "aaaa"print("{0}spart: {1}".format(' '*indent, n))parseMsg(part, indent+1)else: # 基礎(chǔ)類型# get_content_type是系統(tǒng)提供函數(shù),得到內(nèi)容類型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: #不是文本內(nèi)容,則應(yīng)該是附件print('{0}Attachment: {1}'.format(indent, content_type))def decodeStr(s):'''s代表一封郵件中From,To,Subject中的任一項(xiàng)對(duì)s進(jìn)行解碼,解碼是編碼的逆過(guò)程:param s::return:'''value, charset = decode_header(s)[0]# charset完全可能為空if charset:# 如果指定編碼,則用指定編碼格式進(jìn)行解碼value = value.decode(charset)return valuedef guessCharset(msg):'''猜測(cè)郵件的編碼格式:param msg::return:'''# 調(diào)用現(xiàn)成的函數(shù)charset = msg.get_charset()if charset is None:# 找到內(nèi)容類型,并轉(zhuǎn)換成小寫content_type = msg.get("Content-Type", "").lower()pos = content_type.find("charset=")if pos >= 0:# 如果包含chraset,則內(nèi)容形如 charset=xxxxcharset = content_type[pos+8:].strip()return charsetif __name__ == "__main__":# 得到郵件的原始內(nèi)容msg = getMsg()print(msg)# 精確解析郵件內(nèi)容parseMsg(msg, 0)?
總結(jié)
以上是生活随笔為你收集整理的Python之Mail编程(电子邮件编程)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: vue3使用vant4-showToas
- 下一篇: 2019年8月计算机语言排行,2019程