python使用smtplib發送郵件


python要實現發送郵件的功能,需要使用smtplib庫。

1. 過程大致如下:

1. 建立和SMTP郵件服務器的連接

# 默認端口25
smtp = smtplib.SMTP(host, port)
# 或者
smtp = smtplib.SMTP()
smtp.connect(host, port)

# 帶SSL,默認端口465
smtp = smtp.SMTP_SSL()
smtp.connect(host, port)

2. 完成身份認證

# 對於163而言,第三方客戶端登陸使用的是授權碼而不是密碼
smtp.login(username, password)

3. 發送郵件(必須明確發件人、收件人、主題、內容,而抄送人、密送人、附件、內嵌式圖片等資源是可選的)

smtp.sendmail(from_addr, to_addrs, msg, mail_options=[], rcpt_options=[])

4. 結束會話

smtp.quit()

 

2. MIME相關知識介紹

MIME全稱Multipurpose Internet Mail Extensions(多用途互聯網郵件擴展)。是一個互聯網標准,它擴展了電子郵件標准,使其能夠支持:

  • 非ASCII字符文本;
  • 非文本格式附件(二進制、聲音、圖像等);
  • 由多部分(multiple parts)組成的消息體;
  • 包含非ASCII字符的頭信息(Header information)

此外,web中使用的HTTP協議也使用了MIMIE的框架,標准被擴展為互聯網媒體類型

 MIME頭部信息:

MIME版本: 目前版本1.0

MIME-Version: 1.0

內容類型(Content-Type),用於指定消息類型。 形式如下:

Content-Type: [type]/[subtype]; parameter

type有以下形式:

  • Text: 文本消息, 可以使用charset參數指定字符集;
  • Multipart: 用於連接消息體的多個部分構成一個消息,這些部分可以是不同類型的數據;
  • Application:用於傳輸應用程序數據或者二進制數據;
  • Message:用於包裝一個E-mail消息;
  • Image:用於傳輸靜態圖片數據;
  • Audio:用於傳輸音頻數據;
  • Video:用於傳輸動態影像數據,可以是與音頻編輯在一起的視頻數據格式

常見的文件擴展名與Content-Type對應關系如下:

文件擴展名 Content-Type
.txt text/plain
.html text/html
.xhtml application/xhtml+xml
.css text/css
.js application/javascript
.xml application/atom+xml
.json application/json
.jpg image/jpeg
.png image/png
.gif image/gif
.mp3 audio/mpeg3
.mp4 video/mp4
.wav audio/wav
.avi video/avi
.doc application/msword
.docx application/vnd.openxmlformats-officedocument.wordprocessingml.document
.xls application/vnd.ms-excel
.xlsx application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
.ppt application/vnd.ms-powerpoint
.pptx application/vnd.openxmlformats-officedocument.presentationml.presentation
.pdf application/pdf
.rar application/x-rar-compressed
.zip application/x-compressed
.tar application/x-tar
.gz application/x-compressed
.bz2 application/x-bzip2
表示任意二進制數據 application/octet-stream
使用HTTP的POST方法提交表單 application/x-www-form-urlencoded
主要用於表單提交時伴隨文件上傳的場合 multipart/form-data

 Text默認是text/plain,Application默認是application/octet-stream而Multipart默認情況下被看作multipart/mixed。

 

內容傳輸編碼(Content-Transfer-Encoding)

Content-Transfer-Encoding: [mechanism]

其中,mechanism的值可以指定為“7bit”,“8bit”,“binary”,“quoted-printable”,“base64”

 

MIME信息剖析

一封普通的文本郵件的信息包含一個頭部分(例如:From、To、Subject 等等)和一個體部分。體部分通常為單體類型(例如:text、image、audio、video、application 等等)或是復合類型(即:multipart)。頭部分和體部分之間用一個空行進行分隔,並且體部分的類型由信頭內容類型字段 Content-Type 描述。

信頭含義 (Headers)

域名 含義
Content-Type 內容的類型
MIME-Version MIME 版本
Content-Transfer-Encoding 內容的傳輸編碼方式
From 發件人地址
To 收件人地址
Cc 抄送地址
Bcc 暗送地址
Date 日期和時間
Subject 主題
Received 傳輸路徑
Return-Path 回復地址
Delivered-To 發送地址
Reply-To 回復地址
Message-ID 消息 ID

 

信體部分

  • 郵件中常見的簡單類型有 text/plain(純文本)和 text/html(超文本)。

  • 復雜的郵件內容格式采用 multipart 類型,可以包括純文本/超文本(alternative)、內嵌資源(圖片)(related)、附件類型(mixed)等等。

    multipart 類型的郵件體被分為多個段,每個段又包含段頭和段體兩部分,這兩部分之間也以空行分隔。

信體頭含義

域名 含義
Content-Type 段體的類型
Content-Transfer-Encoding 段體的傳輸編碼方式
Content-Disposition 段體的位置,內嵌(inline)或附件(attachment)
Content-ID 段體的 ID, 唯一標識
Content-Location 段體的位置(路徑)
Content-Base 段體的基位置

 

常見的 multipart 類型有三種:multipart/mixed, multipart/related 和 multipart/alternative。

復合類型層次關系示例圖:

multipart 諸類型的共同特征是,在段頭指定 boundary 參數字符串,段體內的每個子段以此字符串定界。

所有的子段都以 --boundary 行開始,父段則以 --boundary-- 行結束。段與段之間也以空行分隔。

例子:

1) 發送純文本文件:

Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: base64

aGVsbG8gd29ybGQK5L2g5aW95LiW55WM

2)發送包含富文本的郵件:

Content-Type: multipart/alternative;
  boundary="----=ALIBOUNDARY_14343_4f941940_5a9a0b10_90106"

------=ALIBOUNDARY_14343_4f941940_5a9a0b10_90106
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: base64

aGVsbG8gd29ybGTkvaDlpb3kuJbnlYw=
------=ALIBOUNDARY_14343_4f941940_5a9a0b10_90106
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: base64

PGRpdiBjbGFzcz0iX19hbGl5dW5fZW1haWxfYm9keV9ibG9jayI+PGRpdiAgc3R5bGU9ImNsZWFy
OmJvdGg7Ij48c3BhbiAgc3R5bGU9ImZvbnQtZmFtaWx5OlRhaG9tYSxBcmlhbCxTVEhlaXRpLFNp
bVN1bjtmb250LXNpemU6MTQuMHB4O2NvbG9yOiMwMDAwMDA7Ij5oZWxsbyB3b3JsZDwvc3Bhbj48
L2Rpdj48ZGl2ICBzdHlsZT0iY2xlYXI6Ym90aDsiPjxzcGFuICBzdHlsZT0iZm9udC1mYW1pbHk6
VGFob21hLEFyaWFsLFNUSGVpdGksU2ltU3VuO2NvbG9yOiMwMDAwMDA7YmFja2dyb3VuZC1jb2xv
cjojZmYwMDAwO2ZvbnQtc2l6ZTozMi4wcHg7Ij7kvaDlpb3kuJbnlYw8L3NwYW4+PC9kaXY+PC9k
aXY+
------=ALIBOUNDARY_14343_4f941940_5a9a0b10_90106--

”aGVsbG8gd29ybGTkvaDlpb3kuJbnlYw=" base64前明文:

hello world你好世界

"

PGRpdiBjbGFzcz0iX19hbGl5dW5fZW1haWxfYm9keV9ibG9jayI+PGRpdiAgc3R5bGU9ImNsZWFy OmJvdGg7Ij48c3BhbiAgc3R5bGU9ImZvbnQtZmFtaWx5OlRhaG9tYSxBcmlhbCxTVEhlaXRpLFNp bVN1bjtmb250LXNpemU6MTQuMHB4O2NvbG9yOiMwMDAwMDA7Ij5oZWxsbyB3b3JsZDwvc3Bhbj48 L2Rpdj48ZGl2ICBzdHlsZT0iY2xlYXI6Ym90aDsiPjxzcGFuICBzdHlsZT0iZm9udC1mYW1pbHk6 VGFob21hLEFyaWFsLFNUSGVpdGksU2ltU3VuO2NvbG9yOiMwMDAwMDA7YmFja2dyb3VuZC1jb2xv cjojZmYwMDAwO2ZvbnQtc2l6ZTozMi4wcHg7Ij7kvaDlpb3kuJbnlYw8L3NwYW4+PC9kaXY+PC9k aXY+" 明文:
<div class="__aliyun_email_body_block"><div  style="clear:both;"><span  style="font-family:Tahoma,Arial,STHeiti,SimSun;font-size:14.0px;color:#000000;">hello world</span></div>
<div style="clear:both;"><span style="font-family:Tahoma,Arial,STHeiti,SimSun;color:#000000;background-color:#ff0000;font-size:32.0px;">你好世界</span></div></div>
 
        

3) 將圖片內嵌:

Content-Type: multipart/related;
  boundary="----=ALIBOUNDARY_25467_4f851940_5a9a032e_8ff9d"


------=ALIBOUNDARY_25467_4f851940_5a9a032e_8ff9d
Content-Type: multipart/alternative;
  boundary="----=ALIBOUNDARY_25467_4f851940_5a9a032e_8ff9e"

------=ALIBOUNDARY_25467_4f851940_5a9a032e_8ff9e
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: base64 6L+Z5pivcHl0aG9u55qEbG9nb8KgCg==     
------=ALIBOUNDARY_25467_4f851940_5a9a032e_8ff9e
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: base64

PGRpdiBjbGFzcz0iX19hbGl5dW5fZW1haWxfYm9keV9ibG9jayI+PGRpdiAgc3R5bGU9ImNsZWFy
OmJvdGg7Ij48c3BhbiAgc3R5bGU9ImZvbnQtZmFtaWx5OlRhaG9tYSxBcmlhbCxTVEhlaXRpLFNp
bVN1bjtmb250LXNpemU6MTQuMHB4O2NvbG9yOiMwMDAwMDA7Ij7ov5nmmK9weXRob27nmoRsb2dv
PC9zcGFuPjwvZGl2PjxkaXYgIHN0eWxlPSJjbGVhcjpib3RoOyI+PHNwYW4gIHN0eWxlPSJmb250
LWZhbWlseTpUYWhvbWEsQXJpYWwsU1RIZWl0aSxTaW1TdW47Zm9udC1zaXplOjE0LjBweDtjb2xv
cjojMDAwMDAwOyI+PGltZyAgc3JjPSJjaWQ6X19hbGl5dW4xNTIwMDQyNzk4MjEzOTg3MjEiPiZu
YnNwOzxiciA+PC9zcGFuPjwvZGl2PjwvZGl2Pg==                                       
------=ALIBOUNDARY_25467_4f851940_5a9a032e_8ff9e--

------=ALIBOUNDARY_25467_4f851940_5a9a032e_8ff9d
Content-Type: application/octet-stream
Content-ID: <__aliyun152004279821398721>
Content-Disposition: inline; filename="=?UTF-8?B?cHl0aG9uLWxvZ28ucG5n?="
Content-Transfer-Encoding: base64

下面多行是圖片二進制數據base64編碼后的數據
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

------=ALIBOUNDARY_25467_4f851940_5a9a032e_8ff9d--

"6L+Z5pivcHl0aG9u55qEbG9nb8KgCg==" 是經過base64編碼后的數據,明文為:  

這是python的logo
"

PGRpdiBjbGFzcz0iX19hbGl5dW5fZW1haWxfYm9keV9ibG9jayI+PGRpdiAgc3R5bGU9ImNsZWFy
OmJvdGg7Ij48c3BhbiAgc3R5bGU9ImZvbnQtZmFtaWx5OlRhaG9tYSxBcmlhbCxTVEhlaXRpLFNp
bVN1bjtmb250LXNpemU6MTQuMHB4O2NvbG9yOiMwMDAwMDA7Ij7ov5nmmK9weXRob27nmoRsb2dv
PC9zcGFuPjwvZGl2PjxkaXYgIHN0eWxlPSJjbGVhcjpib3RoOyI+PHNwYW4gIHN0eWxlPSJmb250
LWZhbWlseTpUYWhvbWEsQXJpYWwsU1RIZWl0aSxTaW1TdW47Zm9udC1zaXplOjE0LjBweDtjb2xv
cjojMDAwMDAwOyI+PGltZyAgc3JjPSJjaWQ6X19hbGl5dW4xNTIwMDQyNzk4MjEzOTg3MjEiPiZu
YnNwOzxiciA+PC9zcGFuPjwvZGl2PjwvZGl2Pg==" 明文為:

<div class="__aliyun_email_body_block"><div  style="clear:both;"><span  style="font-family:Tahoma,Arial,STHeiti,SimSun;font-size:14.0px;color:#000000;">
這是python的logo</span></div><div style="clear:both;"><span style="font-family:Tahoma,Arial,STHeiti,SimSun;font-size:14.0px;color:#000000;">
<img src="cid:__aliyun152004279821398721">&nbsp;<br ></span></div></div>

 4) 發送帶附件的郵件

Content-Type: multipart/mixed;
  boundary="----=ALIBOUNDARY_68661_4cbc5940_5a9a0f2a_90709"

This is a multi-part message in MIME format.

------=ALIBOUNDARY_68661_4cbc5940_5a9a0f2a_90709
Content-Type: multipart/alternative;
  boundary="----=ALIBOUNDARY_68661_4cbc5940_5a9a0f2a_9070a"

------=ALIBOUNDARY_68661_4cbc5940_5a9a0f2a_9070a
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: base64

5Y+R6YCB6ZmE5Lu25rWL6K+V
------=ALIBOUNDARY_68661_4cbc5940_5a9a0f2a_9070a
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: base64

PGRpdiBjbGFzcz0iX19hbGl5dW5fZW1haWxfYm9keV9ibG9jayI+PGRpdiAgc3R5bGU9ImNsZWFy
OmJvdGg7Ij48c3BhbiAgc3R5bGU9ImZvbnQtZmFtaWx5OlRhaG9tYSxBcmlhbCxTVEhlaXRpLFNp
bVN1bjtmb250LXNpemU6MTQuMHB4O2NvbG9yOiMwMDAwMDA7Ij7lj5HpgIHpmYTku7Y8c3BhbiAg
c3R5bGU9ImNvbG9yOiMwMDAwMDA7Zm9udC1mYW1pbHk6VGFob21hLEFyaWFsLFNUSGVpdGksU2lt
U3VuO2ZvbnQtc2l6ZToxNC4wcHg7Zm9udC1zdHlsZTpub3JtYWw7Zm9udC12YXJpYW50LWxpZ2F0
dXJlczpub3JtYWw7Zm9udC12YXJpYW50LWNhcHM6bm9ybWFsO2ZvbnQtd2VpZ2h0OjQwMDt0ZXh0
LWFsaWduOnN0YXJ0O3RleHQtaW5kZW50Oi4wcHg7dGV4dC10cmFuc2Zvcm06bm9uZTt3aWRvd3M6
MjtiYWNrZ3JvdW5kLWNvbG9yOiNmZmZmZmY7dGV4dC1kZWNvcmF0aW9uLXN0eWxlOmluaXRpYWw7
dGV4dC1kZWNvcmF0aW9uLWNvbG9yOmluaXRpYWw7ZmxvYXQ6bm9uZTtkaXNwbGF5OmlubGluZTsi
Pua1i+ivlTwvc3Bhbj48L3NwYW4+PC9kaXY+PC9kaXY+
------=ALIBOUNDARY_68661_4cbc5940_5a9a0f2a_9070a--

------=ALIBOUNDARY_68661_4cbc5940_5a9a0f2a_90709
Content-Type: application/octet-stream
Content-Disposition: attachment; filename="=?UTF-8?B?5L2g5aW9d29ybGQudHh0?="
Content-Transfer-Encoding: base64

aGVsbG8gd29ybGQNCsTjusPKwL3n

------=ALIBOUNDARY_68661_4cbc5940_5a9a0f2a_90709--

 

multipart/alternative:

     在同時提供多種消息格式,這些消息格式間是相互可替換的,如提供同一消息的多語言版本。

multipart/related:

     添加內嵌資源時必須指定的Content-Type類型,通常配合Content-ID使用。

     Content-ID頭字段用於為“multipart/related” 組合消息中的內嵌資源指定一個唯一的標識符。在html格式的正文中使用這個唯一標識號來引用該內嵌資源。格式如下:

<img  src="cid:CONTENTID" />
# CONTENTID用具體的數值替換

multipart/mixed:

  添加附件時必須指定的Content-Type類型, 配合Content-Disposition來獲取上文文件的名稱。

Content-Disposition: attachment; filename=”上傳文件的文件名"
#  一般中文文件名都需要base64編碼
#  以python_logo.png為例,base64編碼后變為: cHl0aG9uX2xvZ28ucG5n
#  最后結果為:  =?UTF-8?B?cHl0aG9uLWxvZ28ucG5n?=

 

3. python中的MIME

參考:  email.mime

 

MIMENonMultipart 作為中間類,主要用途是防止調用attach()方法

MIMEMultipart 與Conent-Type中的multipart對應,默認類型為multipart/mixed

MIMEApplication與Content-Type中的application對應,默認類型為application/octed-stream,默認編碼類型為base64

MIMEText與Content-Type中的text對應,默認類型為text/plain。

 

身份認證發生錯誤:

smtplib.SMTPAuthenticationError: (535, 'Error: authentication failed')

原因分析:網易163郵箱需要啟用授權碼,並且使用授權碼登錄,而不是密碼登錄

 

1. 發送純文本

import smtplib
from email.mime.text import MIMEText
from email.header import Header

host = "smtp.aliyun.com"
username = "u1@aliyun.com"
# 對於163郵箱使用授權碼而不是密碼登錄
password = "xxxxxxxxxxxx"

# 接收人列表
receivers = ['q1@qq.com']
# 抄送人列表
cc_list = ['q2@qq.com']
# 密送人列表
bcc_list = ['q3@qq.com']
# 主題
subject = "阿里郵箱給qq郵箱發信"
# 正文
body = "Python 發送郵件測試"

sender = username
# 郵件正文
message = MIMEText(body, 'plain', 'utf-8')
# 發件人
message['From'] = sender
# 收件人
message['To'] = ",".join(receivers)   # 多個接收人之間要用逗號隔開
# 抄送人
message['Cc'] = ','.join(cc_list)
# 密送人
message['Bcc'] = ','.join(bcc_list)
# 主題
message['Subject'] = Header(subject, "utf-8")

try:
    smtp = smtplib.SMTP()
    smtp.set_debuglevel(1)  # 開啟調試,方便觀察和郵件服務器通信全過程
    smtp.connect(host)   # 默認端口是25
    # 登陸
    smtp.login(username, password)
    # 發送郵件
    # 郵件服務器在轉發郵件的過程中,省略了Bcc項
    # To: Cc: Bcc: 只是一種表現形式,歸根結底都是郵件的接收者,都需要服務器發送RCPT TO:來告知郵件服務器發送給誰。
    # 因此接收者列表應該是收件人、抄送人、密送人的集合。
    smtp.sendmail(sender, receivers + cc_list + bcc_list, message.as_string())
    smtp.quit()
except smtplib.SMTPException as e:
    print("error: ", e)

案例: 將磁盤使用情況以郵件的形式發送

# coding=utf-8
import smtplib
import subprocess


def send_email(smtp_server, sender, passwd, receiver_list, subject, content):
    receiver = receiver_list
    if isinstance(receiver_list, list):
        receiver = ",".join(receiver_list)  # 多個收件人之間用,隔開

    # 注意主題和正文中有一個空行
    msg = '\r\n'.join([
        'From: %s' % sender,
        'To: %s' % receiver,
        'Subject: %s' % subject,
        '',
        content
    ])

    try:
        s = smtplib.SMTP()
        # 連接smtp服務器
        s.connect(smtp_server)
        # 登陸 對於163郵箱,使用授權碼而不是密碼登陸第三方郵件客戶端
        s.login(sender, passwd)
        # 發送郵件
        s.sendmail(sender, receiver_list, msg)
        print 'success'
        s.quit()
    except Exception as e:
        print e

# 發送郵件測試


def send_email_test():
    smtp_server = 'smtp.163.com'
    sender = 'sender@163.com'  # 發件人
    password = 'authorized_code'  # 163郵箱的登陸授權碼

    # 收件人
    receiver = ['qq1@qq.com', 'qq2@qq.com']
    # 郵件主題
    subject = 'Disk Usage Report'

    p = subprocess.Popen('df -h', shell=True, stdout=subprocess.PIPE)
    content = p.stdout.read()  # 獲取磁盤使用情況

    send_email(smtp_server, sender, password, receiver, subject, content)

 

2. 發送富文本郵件

host = "smtp.aliyun.com"
username = "u1@aliyun.com"
password = “password"
receivers = ['q1@qq.com']
subject = "python發送html"

sender = username
# 類型為alternative
message = MIMEMultipart("alternative")
message['From'] = sender
message['To'] = ",".join(receivers)   # 多個接收人之間要用逗號隔開
message['Subject'] = Header(subject, "utf-8")

# 正文有兩部分
part1 = MIMEText("<h1>使用python發送郵件</h1>", "html", "utf-8")
part2 = MIMEText('<a href="http://www.python.org">python官網</a>', "html", "utf-8")
message.attach(part1)
message.attach(part2)

 3. 發送帶附件的郵件

import os
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.header import Header
from email.mime.application import MIMEApplication


def add_attchment(message, file):
    """添加附件
    :param message: MIMEMultipart對象
    :param file: file為文件的路徑
    :return: None
    """
    filename = os.path.basename(file)  # 獲取文件名
    with open(file, "rb") as f:
        attachment = MIMEApplication(f.read())
        attachment.add_header(
            "Content-Disposition",
            "attachment",
            filename=(
                "gbk",  # 指定編碼格式, qq郵箱對郵件使用gbk編碼,否則可能會出現文件名亂碼
                "",
                filename))
        message.attach(attachment)


host = "smtp.aliyun.com"
username = "u1@aliyun.com"
password = “password"
receivers = ['q1@qq.com']
subject = "python發送附件"

sender = username
# 發送附件,Content-Type必須為multipart/mixed
message = MIMEMultipart("mixed")
message['From'] = sender
message['To'] = ",".join(receivers)   # 多個接收人之間要用逗號隔開
message['Subject'] = Header(subject, "utf-8")
# 添加正文
body = MIMEText("測試發送附件", "html", "utf-8")
message.attach(body)
# 添加附件
add_attchment(message, "百度logo.jpg")
add_attchment(message, "測試.txt")
add_attchment(message, "測試.xlsx")

4. 發送帶內嵌圖片的郵件

def get_base64name(file):
    """
    :param file: 文件路徑
    :return: 返回base64編碼的文件名
    """
    filename = os.path.basename(file)
    base64name = base64.b64encode(filename.encode('utf-8'))
    filename = (str(base64name))[2:-1]
    return filename


def add_nested_picture(message, msgalternative, file):
    """
    向郵件中嵌入圖片
    """
    # 將base64編碼的文件名作為cid
    cid = get_base64name(file)
    link = MIMEText('<img src="cid:%s" />' % cid, "html", "utf-8")
    msgalternative.attach(link)

    with open(file, "rb") as f:
        nested_picture = MIMEApplication(f.read())
        nested_picture.add_header("Content-ID", cid)
 # 下面這一行可以省略 
        nested_picture.add_header("Content-Disposition", "inline", filename=("gbk", "", os.path.basename(file)))
        message.attach(nested_picture)


sender = username
# 指定類型為multipart/related message
= MIMEMultipart("related") message['From'] = sender message['To'] = ",".join(receivers) # 多個接收人之間要用逗號隔開 message['Subject'] = Header(subject, "utf-8") msgalternative = MIMEMultipart("alternative") message.attach(msgalternative) # 添加正文 body = MIMEText("測試發送含有內嵌圖片的郵件", "html", "utf-8") msgalternative.attach(body) add_nested_picture(message, msgalternative, "C:/users/hupeng/pictures/lena.jpg")

層次結果:

里層: 類型為multipart/alternative的MIMEMultipart對象attach 裝載html文本的MIMEText對象。

外層: 類型為multipart/related的MIMEMultipart對象 attach 表示內嵌資源的MIMEApplication對象和表示文本信息類型為mulitpart/alternative的MIMEMultipart對象。

當然也可以直接使用類型為multipart/mixed類型的對象attach 表示html文本的MIME對象和表示內嵌資源的MIMEApplication對象

代碼如下:

def get_base64name(file):
    """
    :param file: 文件路徑
    :return: 返回base64編碼的文件名
    """
    filename = os.path.basename(file)
    base64name = base64.b64encode(filename.encode('utf-8'))
    filename = (str(base64name))[2:-1]
    return filename


def add_nested_picture(message, file):
    """
    向郵件中嵌入圖片
    """
    # 將base64編碼的文件名作為cid
    cid = get_base64name(file)
    link = MIMEText('<img src="cid:%s" />' % cid, "html", "utf-8")
    message.attach(link)

    with open(file, "rb") as f:
        nested_picture = MIMEApplication(f.read())
        nested_picture.add_header("Content-ID", cid)
        message.attach(nested_picture)


sender = username
# 指定最外層信息段類型為multipart/mixed
message = MIMEMultipart("mixed")
message['From'] = sender
message['To'] = ",".join(receivers)   # 多個接收人之間要用逗號隔開
message['Subject'] = Header(subject, "utf-8")
# 添加正文
body = MIMEText("測試發送含有內嵌圖片的郵件", "html", "utf-8")
message.attach(body)
# 添加嵌入式圖片
add_nested_picture(message, "百度logo.jpg")

 備注:  郵件客戶端(web端)包含查看郵件原文的功能,使用該功能可以很好的幫助學習。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM