smtplib 發送
流程
- 連接配接伺服器 連接配接 SMTP 伺服器,并使用使用者名、密碼登入伺服器
- 建立郵件 建立
對象,該對象代表郵件本身EmailMessage
- 發送郵件 調用代表與 SMTP 伺服器連接配接的對象的
方法發送郵件sendmail()
子產品
-
子產品smtplib
-
得到郵件連接配接對象smtplib.SMTP
-
-
建構複雜郵件内容email.message.EmailMessage
-
set_content()
-
add_attachment(maintype,subtype,filename,cid=img)
-
發送經驗
- 早期SMTP 伺服器都采用普通的網絡連接配接,是以預設端口是 25
- 現在絕大部分 SMTP 都是基于
, 預設端口是465SSL(Secure Socket Layer)
- 有些公司的免費郵箱(比如 QQ 郵箱)預設是關閉了 SMTP
- 郵件太簡單,比如沒主題,郵箱服務商可能會被當成垃圾郵件攔截
- java成員變量有初始值,而局部變量沒有初始值得,否則會導緻編譯不通過
發送示例
# py -3.7
import smtplib
import email.utils
from email.message import EmailMessage
smtp_server = 'smtp.qq.com'
from_addr = '[email protected]'
# qq授權碼
password = 'xxxxxxxx'
to_addr = '[email protected]'
# 建立連接配接
# conn = smtplib.SMTP(smtp_server, 25)
conn = smtplib.SMTP_SSL(smtp_server, 465)
conn.set_debuglevel(1)
conn.login(from_addr, password)
# 建立郵件對象
msg = EmailMessage()
# 随機生成兩個圖檔id
first_id, second_id = email.utils.make_msgid(), email.utils.make_msgid()
msg.set_content('<h2>郵件内容</h2><p>您好,這是一封來自Python的郵件' +
'<img src="cid:' + second_id[1:-1]+'"><p>')
msg['subject'] = '一封html郵件'
msg['from'] = '李剛<%s>' % from_addr
msg['to'] = '新使用者<%s>' % to_addr
# 添加附件
with open('C:/Users/Public/Pictures/logo/coffee.png', 'rb') as f:
# 添加第一個附件
msg.add_attachment(f.read(), maintype='image',
subtype='jpeg', filename='coffee.png', cid=first_id)
with open('C:/Users/Public/Pictures/lyn/s009.jpg', 'rb') as f:
# 添加第二個附件
msg.add_attachment(f.read(), maintype='image',
subtype='jpeg', filename='test.jpeg', cid=second_id)
with open('E:/Manual/pdf/laravel-source-analysis.pdf', 'rb') as f:
# 添加第三個附件,郵件正文不需引用該附件,是以不指定cid
msg.add_attachment(f.read(), maintype='application',
subtype='pdf', filename='test.pdf',)
# 發送郵件
conn.sendmail(from_addr, [to_addr], msg.as_string())
conn.quit()
poplib 收件
子產品類
-
poplib.POP3
-
poplib.POP3_SSL
pop3協定
- 請求,響應式互動協定
- POP3 的指令和響應資料都是基于 ASCII 文本的,并以 CR 和 LF(/r/n) 作為行結束符
- pop3協定指令
-
user name,pass string,stat,quit,list[msg_no],retr_msg_no,dele_msg_no,noop,rset
-
poplib收取流程
- 使用
或poplib.POP3
L 按 POP3 協定從伺服器端下載下傳郵件poplib.POP3_SS
- 使用
或email.parser.Parser
解析郵件内容,得到email.parser.BytesParser
對象EmailMessage
小結
- 預設端口110,ssl端口995
-
解析位元組串格式的郵件資料email.parser.BytesParser
-
解析字元串格式的郵件資料email.parser.Parser
- 若讀取
的各部分,則需要調用該對象的EmailMessage
方法,該方法傳回一個可疊代對象walk()
- 建立解析器時,*需要指定解析政策
*否則,解析出來的對象就是policy=default
,而不是新的Message
EmailMessage
- 讀取 EmailMessage 的各部分,則需要調用該對象的 walk() 方法,該方法傳回一個可疊代對象
收件示例
import poplib
import os.path
import mimetypes
from email.parser import BytesParser, Parser
from email.policy import default
# 輸入郵件位址, 密碼和POP3伺服器位址
email = '[email protected]'
# 授權碼
password = 'pkvxxxxxxec'
pop3_server = 'pop.qq.com'
# 連接配接pop3伺服器
# conn = poplib.POP3(pop3_server, 110)
conn = poplib.POP3_SSL(pop3_server, 995)
# 打開調試資訊
conn.set_debuglevel(1)
# 可選:列印POP 3伺服器的歡迎文字
print(conn.getwelcome().decode('utf-8'))
# 輸入使用者密碼
conn.user(email)
conn.pass_(password)
# 擷取郵件的統計資訊,相當于發送pop3的stat指令
message_num, total_size = conn.stat()
print('郵件數:%s, 總大小:%s' % (message_num, total_size))
# 擷取伺服器上的郵件清單,相當于發送POP 3的list指令
# resp儲存伺服器的響應碼
# mails清單儲存每封郵件的編号、大小
resp, mails, octets = conn.list()
print(resp, mails)
# 擷取指定郵件的内容(此處傳入總長度,也就是擷取最後一封郵件)
# 相當于發送POP 3的retr指令
# resp儲存伺服器的響應碼
# data儲存該郵件的内容
resp, data, octets = conn.retr(len(mails))
# 将data的所有資料(原本是一個位元組清單)拼接在一起
msg_data = b'\r\n'.join(data)
# 将字元串内容解析成郵件,需指定解析政策
msg = BytesParser(policy=default).parsebytes(msg_data)
print(type(msg))
print('發件人:' + msg['from'])
print('收件人:' + msg['to'])
print('主題:' + msg['subject'])
print('第一個收件人名字:' + msg['to'].addresses[0].username)
print('第一個發件人名字:' + msg['from'].addresses[0].username)
for part in msg.walk():
counter = 1
# 如果maintype是multipart,說明是容器(用于包含正文、附件等)
if part.get_content_maintype() == 'multipart':
continue
elif part.get_content_maintype() == 'text':
print(part.get_content())
# 處理附件
else:
filename = part.get_filename()
if not filename:
# 根據附件的contnet_type來推測它的字尾名
ext = mimetypes.guess_extension(part.get_content_type())
if not ext:
ext = '.bin'
# 程式為附件來生成檔案名
filename = 'part-%03d%s' % (counter, ext)
counter += 1
# 将附件寫入本地檔案
with open(os.path.join('.', filename), 'wb') as fp:
fp.write(part.get_payload(decode=True))
# 退出伺服器,相當于發送POP 3的quit指令
conn.quit()