天天看點

python最全郵件收發pop3與smtp

smtplib 發送

流程
  1. 連接配接伺服器 連接配接 SMTP 伺服器,并使用使用者名、密碼登入伺服器
  2. 建立郵件 建立

    EmailMessage

    對象,該對象代表郵件本身
  3. 發送郵件 調用代表與 SMTP 伺服器連接配接的對象的

    sendmail()

    方法發送郵件
子產品
  • smtplib

    子產品
    • smtplib.SMTP

      得到郵件連接配接對象
  • email.message.EmailMessage

    建構複雜郵件内容
    • set_content()

    • add_attachment(maintype,subtype,filename,cid=img)

發送經驗
  • 早期SMTP 伺服器都采用普通的網絡連接配接,是以預設端口是 25
  • 現在絕大部分 SMTP 都是基于

    SSL(Secure Socket Layer)

    , 預設端口是465
  • 有些公司的免費郵箱(比如 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收取流程
  1. 使用

    poplib.POP3

    poplib.POP3_SS

    L 按 POP3 協定從伺服器端下載下傳郵件
  2. 使用

    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()