自動化發送郵件

自動化發送郵件

背景

室友選修的《機器學習》,結課做業是對8萬+的數據進行分析。他向我抱怨,說這麼多數據至少得運算半個多小時,還得語法邏輯不出錯,否則得重來。
「總不能守着電腦吧,想出去玩,又拿不許程序準確結束時間。」
我想python做爲編程界的萬金油,幾乎不存在它不能染指的地方。因此有了如下基於smtp協議、利用python自帶模塊email,smtplib實現自動化發送郵件的代碼。python

SMTP瞭解一下

有必要簡單瞭解一下SMTP的概念,能夠加深對代碼的理解。git

因此什麼是SMTP呢?
SMTP是簡單郵件傳輸協議,不過只能傳送可打印的7位ASCII碼郵件,這樣存在過大的侷限性。因而後來有了MIME,即通用互聯網郵件擴充。MIME在郵件首部中說明了郵件的數據類型(如文本,聲音,圖像,視像等),且經過MIME郵件能夠同時傳送多種類型的數據(附件)。github

郵件系統

一個郵件系統應該具備三個主要組成構建。用戶代理、郵件服務器,郵件發送協議(SMTP)和郵件讀取協議(POP3,又:郵局協議)
這裏寫圖片描述編程

實現過程

1.鏈接創建

SMTP客戶端(發送方的郵件服務器)每隔必定時間對郵件緩存掃描,若是發現有郵件,就用25端口與接收方的SMTP服務器創建TCP鏈接。鏈接創建後,接收方服務器發出「服務就緒」,SMTP客戶端向SMTP服務器發送HELO命令,附上發送方的主機名。SMTP服務器若是有能力接受郵件,就回復「250」(OK),若是服務不可用回覆「421」。緩存

2.郵件傳輸

服務器

3.鏈接釋放

郵件發送完畢後,SMTP客戶發送QUIT命令。SMTP服務器返回「221」(服務關閉),表示贊成釋放TCP鏈接。郵件傳輸過程結果。app

4.注意項目

1. SMTP不使用中間郵件服務器,必定是發送方服務器到接收方服務器
2. 爲何要經過郵件服務器而不是直接發送方用戶代理–>接收方用戶代理呢?緣由很簡單,被人給你發送郵件的時候你並不必定在機器學習

信息格式

一個郵件分爲信封內容兩大部分,內容包含首部主體
1. 首部(header),有規定格式,比較重要有如下:
「To」 接收方郵件地址
「Subject」 郵件主題
「From」 發送方郵件地址
2. 主體(body),容許用戶自由撰寫學習

MIME新增關鍵字

  1. MIME-Version:標誌MIME的版本
  2. Content-Description:可讀字符串,說明郵件主體是不是圖像、音頻或視頻
  3. Content-Id:郵件的惟一標識符
  4. Content-Transfer-Encoding:傳送郵件時郵件的主體是如何編碼的(經常使用三種編碼:ASCII,quoted-printable,base64)
  5. Content-Type:說明郵件主體的數據類型和子類型。MIME規定Content-Type必須含有兩個標識符,即類型子類型,中間中「/」分開(舉例:text/plain)
  6. Content-Disposition:disposition-type;disposition-parm 參數意義:disposition-type表示以什麼方式下載(一般值爲attachment,即以附件形式下載);disposition-parm表示文件保存的默認名

multipart

  1. 郵件主體的數據類型之一,表示多種類型的組合(只介紹這一個數據類型是由於,後面會基於這個類型用python實現)
  2. 經常使用子類型:mixed,表示容許單個報文含有多個相互獨立的子報文(理解郵件中的「附件」概念)
  3. boundary關鍵字,定義分隔報文各部分所用的字符串(郵件系統定義,用戶不用關心)

自動發郵件

有了以上對SMTP知識簡單的梳理以後,就能夠很容易理解後面的代碼。而這裏我是經過登錄本身的郵箱來實現發送郵件,這樣作的目的是:若是不登錄本身的郵箱,發送出去的郵件很容易被誤認爲垃圾郵件,或是被屏蔽,或是在垃圾箱,接收方不能及時收取。ui

python內置兩個模塊,email和smtplib,前者負責構建一封郵件,後者實現發送

構建過程

基於python建立一封郵件,使用的是email模塊,我會用不嚴謹、但儘量生動的語言來解釋對象的內置方法

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


aLetter = MIMEMultipart() #實例化「一個包裹」
# attach(),往包裹裏面放東西
# MIMEText()能夠看作一封信,第一個參數表示內容,第二個表示類型,第三個表示編碼格式
aLetter.attach(MIMEText("hello,what are you doing?", "plain", "utf-8")) 
# 在「包裹」上寫上發給誰(to),發的什麼(subject),誰發的(from)
aLetter["To"] = "xxxxx@qq.com"
aLetter["Subject"] = "Make A Friend"
aLetter["From"] = "myemail@qq.com"

# 實例化一封附加信
attachment = MIMEText("i miss you,and you?", "plain", "utf-8")
# 說明郵件數據的主題類型和子類型
attachment["Content-Type"] = "text/plain"
# 以附件形式下載,默認文件名爲happy.txt
attachment["Content-Disposition"] = "attachment;filename=happy.txt"
# 將附加信丟入包裹中
aLetter.attach(attachment)

print(aLetter) # 打印輸出效果

因而有了下面一個「包裹」
這裏寫圖片描述


有了包裹,就須要郵寄出去,這裏須要用到smtplib模塊來發送郵件,流程以下:
這裏寫圖片描述

# 實例化一個smtp對象
smtp = smtplib.SMTP_SSL()
# 鏈接郵件服務器
smtp.connect("smtp.qq.com")
# 登錄本身的郵箱
smtp.login("578******@qq.com", "htn******cga")
# 發送郵件
smtp.sendmail("578******@qq.com", "gu******995@163.com", aLetter.as_string())
# 退出鏈接
smtp.quit()

如此就是一個完整的發送郵件的過程
這裏寫圖片描述

封裝代碼

爲了更高效的利用代碼,爲了使代碼具備更好的擴展性,利用面向對象的思想來封裝代碼天然是不可少的。

這裏寫圖片描述
首先我寫了一個AutoEmail的父類,其下有6個方法,依次對應:登錄信息,發送信息,生成郵件,生成附件,發送郵件,選擇服務器。
因爲網易163郵箱和QQ郵箱鏈接的服務器不一樣,前者「smtp.163.com」,後者「smtp.qq.com」,且網易針對smtplib.SMTP()實例化對象,而QQ郵箱須要針對smtp.SMTP_SSL()

固然,爲了對用戶更友好,這裏我寫了兩個派生類來繼承AutoEmail。
這裏寫圖片描述

父類的choose_server()方法,經過區分實例化對象的類名,來提供相對應的方法
這裏寫圖片描述

獲取實例化對象的類名:__class__.__name__
這裏寫圖片描述

必要的設置

  1. 若是是網易郵箱
    這裏寫圖片描述

  2. 若是是QQ郵箱
    這裏寫圖片描述
    這裏寫圖片描述

代碼中的郵箱密碼,不是郵箱的真實代碼,而是受權密碼。

完整代碼請查看GitHub

相關文章
相關標籤/搜索