1. 程式人生 > >Python學習之旅(三十五)

Python學習之旅(三十五)

Python基礎知識(34):電子郵件(Ⅰ)

幾乎所有的程式語言都支援傳送和接收電子郵件

在使用Python收發郵件前,請先準備好至少兩個電子郵件,如[email protected][email protected][email protected]等,注意兩個郵箱不要用同一家郵件服務商

電子郵件傳送過程:

發件人email->MUA(mail user agent:郵件使用者代理)->MTA(mail transfer agent:郵件傳輸代理)->MDA(mail delivery agent:郵件投遞代理,即伺服器)<-MUA<-收件人

使用SMTP傳送郵件

SMTP是傳送郵件的協議,Python內建對SMTP的支援,可以傳送純文字郵件、HTML郵件以及帶附件的郵件

Python對SMTP支援有smtplibemail兩個模組,email負責構造郵件,smtplib負責傳送郵件

注:以下所有程式碼本人未進行測試,故無法確定是否能夠正常執行

一、傳送郵件

1、構造郵件

from email.mime.text import MIMEText

msg = MIMEText('Hello, world', 'plain', 'utf-8')

到構造MIMEText物件時,第一個引數就是郵件正文,第二個引數是MIME的subtype,傳入'plain'

表示純文字,最終的MIME就是'text/plain',最後一定要用utf-8編碼保證多語言相容性

2、通過SMTP傳送郵件

SMTP.sendmail(from_addr, [to_addr], msg.as_string())

sendmail()方法就是發郵件,由於可以一次發給多個人,所以傳入一個list,郵件正文是一個stras_string()MIMEText物件變成str

必須把FromToSubject新增到MIMEText中,才是一封完整的郵件

from email import encoders
from email.header import
Header from email.mime.text import MIMEText from email.utils import parseaddr, formataddr import smtplib # 考慮到編碼的原因,這裡統一將name屬性值改成utf-8,地址的話一定是統一的郵箱地址結構,所以不考慮 def __format_addr(s): name, addr = parseaddr(s) return formataddr((Header(name, 'utf-8').encode(), addr)) # 一些基本資訊的定義 from_addr = input('From:') password = input('Password:') to_addr = input('To: ') smtp_server = input('SMTP server: ') # 純文字郵件定義 msg = MIMEText('Hello world!', 'plain', 'utf-8') # 定義傳送人,接收人,以及描述資訊(主題) msg['From'] = __format_addr('發件人 <%s>' % from_addr) msg['To'] = __format_addr('收件人: <%s>' % to_addr) msg['Subject'] = Header('SMTP......', 'utf-8').encode() print(msg)

結果如下

From:[email protected].com
Password:1234
To: [email protected]
SMTP server: smtp.163.com
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: base64
From: =?utf-8?b?5Y+R5Lu25Lq6?= <[email protected]>
To: [email protected]
Subject: =?utf-8?b?U01UUC4uLi4uLg==?=

SGVsbG8gd29ybGQh

 

二、傳送HTML郵件

在構造MIMEText物件時,把HTML字串傳進去,再把第二個引數由plain變為html

msg = MIMEText('<html><body><h1>Hello</h1>' +
    '<p>send by <a href="http://www.python.org">Python</a>...</p>' +
    '</body></html>', 'html', 'utf-8')

三、傳送附件

帶附件的郵件可以看做包含若干部分的郵件:文字和各個附件本身,所以,可以構造一個MIMEMultipart物件代表郵件本身,然後往裡面加上一個MIMEText作為郵件正文,再繼續往裡面加上表示附件的MIMEBase物件即可

 

# 郵件物件:
msg = MIMEMultipart()
msg['From'] = _format_addr('Python愛好者 <%s>' % from_addr)
msg['To'] = _format_addr('管理員 <%s>' % to_addr)
msg['Subject'] = Header('來自SMTP的問候……', 'utf-8').encode()

# 郵件正文是MIMEText:
msg.attach(MIMEText('send with file...', 'plain', 'utf-8'))

# 新增附件就是加上一個MIMEBase,從本地讀取一個圖片:
with open('/Users/michael/Downloads/test.png', 'rb') as f:
    # 設定附件的MIME和檔名,這裡是png型別:
    mime = MIMEBase('image', 'png', filename='test.png')
    # 加上必要的頭資訊:
    mime.add_header('Content-Disposition', 'attachment', filename='test.png')
    mime.add_header('Content-ID', '<0>')
    mime.add_header('X-Attachment-Id', '0')
    # 把附件的內容讀進來:
    mime.set_payload(f.read())
    # 用Base64編碼:
    encoders.encode_base64(mime)
    # 新增到MIMEMultipart:
    msg.attach(mime)

按正常傳送流程把msg(注意型別已變為MIMEMultipart)傳送出去 

四、傳送圖片

不能直接在HTML郵件中連結圖片地址,因為大部分郵件服務商都會自動遮蔽帶有外鏈的圖片,因為不知道這些連結是否指向惡意網站

要把圖片嵌入到郵件正文中,只需按照發送附件的方式,先把郵件作為附件新增進去,然後,在HTML中通過引用src="cid:0"就可以把附件作為圖片嵌入了。如果有多個圖片,給它們依次編號,然後引用不同的cid:x即可

把上面程式碼加入MIMEMultipartMIMETextplain改為html,然後在適當的位置引用圖片

msg.attach(MIMEText('<html><body><h1>Hello</h1>' +
    '<p><img src="cid:0"></p>' +
    '</body></html>', 'html', 'utf-8'))

五、同時支援HTML和Plain格式

如果收件人使用的裝置太古老,檢視不了HTML郵件,必須在傳送HTML的同時再附加一個純文字,如果收件人無法檢視HTML格式的郵件,就可以自動降級檢視純文字郵件

利用MIMEMultipart就可以組合一個HTML和Plain,要注意指定subtype是alternative 

msg = MIMEMultipart('alternative')
msg['From'] = ...
msg['To'] = ...
msg['Subject'] = ...

msg.attach(MIMEText('hello', 'plain', 'utf-8'))
msg.attach(MIMEText('<html><body><h1>Hello</h1></body></html>', 'html', 'utf-8'))
# 正常傳送msg物件...

六、加密SMTP

想要更安全地傳送郵件,防止傳送的郵件被竊聽,可以加密SMTP會話,實際上就是先建立SSL安全連線,然後再使用SMTP協議傳送郵件

只需要在建立SMTP物件後,立刻呼叫starttls()方法,就建立了安全連線

smtp_server = 'smtp.gmail.com'
smtp_port = 587
server = smtplib.SMTP(smtp_server, smtp_port)
server.starttls()
# 剩下的程式碼和前面的一模一樣:
server.set_debuglevel(1)