第十四章 Python發送郵件(常見四種郵件內容)

在寫腳本時,放到後臺運行,想知道執行狀況,會經過郵件、SMS(短信)、飛信、微信等方式通知管理員,用的最多的是郵件。在linux下,Shell腳本發送郵件告警是件很簡單的事,有現成的郵件服務軟件或者調用運營商郵箱服務器。html

對於Python來講,須要編寫腳本調用郵件服務器來發送郵件,使用的協議是SMTP。接收郵件,使用的協議是POP3和IMAP。我想有必要說明下 ,POP3和IMAP的區別:POP3在客戶端郵箱中所作的操做不會反饋到郵箱服務器,好比刪除一封郵件,郵箱服務器並不會刪除。IMAP則會反饋到郵箱服務器,會作相應的操做。python

Python分別提供了收發郵件的庫,smtplib、poplib和imaplib。linux

本章主要講解若是使用smtplib庫實現發送各類形式的郵件內容。在smtplib庫中,主要主要用smtplib.SMTP()類,用於鏈接SMTP服務器,發送郵件。服務器

這個類有幾個經常使用的方法:微信

方法運維

描述ide

SMTP.set_debuglevel(level) 設置輸出debug調試信息,默認不輸出
SMTP.docmd(cmd[, argstring]) 發送一個命令到SMTP服務器
SMTP.connect([host[, port]]) 鏈接到指定的SMTP服務器
SMTP.helo([hostname]) 使用helo指令向SMTP服務器確認你的身份
SMTP.ehlo(hostname) 使用ehlo指令像ESMTP(SMTP擴展)確認你的身份
SMTP.ehlo_or_helo_if_needed() 若是在之前的會話鏈接中沒有提供ehlo或者helo指令,這個方法會調用ehlo()或helo()
SMTP.has_extn(name) 判斷指定名稱是否在SMTP服務器上
SMTP.verify(address) 判斷郵件地址是否在SMTP服務器上
SMTP.starttls([keyfile[, certfile]]) 使SMTP鏈接運行在TLS模式,全部的SMTP指令都會被加密
SMTP.login(user, password) 登陸SMTP服務器
SMTP.sendmail(from_addr, to_addrs, msg, mail_options=[], rcpt_options=[])

發送郵件post

from_addr:郵件發件人測試

to_addrs:郵件收件人ui

msg:發送消息

SMTP.quit() 關閉SMTP會話
SMTP.close() 關閉SMTP服務器鏈接

看下官方給的示例:

>>> import smtplib
>>> s=smtplib.SMTP("localhost")
>>> tolist=["one@one.org","two@two.org","three@three.org","four@four.org"]
>>> msg = '''\
     ... From: Me@my.org
     ... Subject: testin'...
     ...
     ... This is a test '''
>>> s.sendmail("me@my.org",tolist,msg)
     { "three@three.org" : ( 550 ,"User unknown" ) }
>>> s.quit()

咱們根據示例給本身發一個郵件測試下:

我這裏測試使用本地的SMTP服務器,也就是要裝一個支持SMTP協議的服務,好比sendmail、postfix等。

CentOS安裝sendmail:yum install sendmail

>>> import smtplib
>>> s = smtplib.SMTP("localhost")
>>> tolist = ["xxx@qq.com", "xxx@163.com"]
>>> msg = '''\
... From: Me@my.org
... Subject: test
... This is a test '''
>>> s.sendmail("me@my.org", tolist, msg)
{}

進入騰訊和網易收件人郵箱,就能看到剛發的測試郵件,通常都被郵箱服務器過濾成垃圾郵件,因此收件箱沒有,你要去垃圾箱看看。

wKioL1gzo3ry0nxHAABIwiKIKIM250.png

能夠看到,多個收件人能夠放到一個列表中進行羣發。msg對象裏From表示發件人,Subject是郵件標題,換行後輸入的是郵件內容。

上面是使用本地SMTP服務器發送的郵件,測試下用163服務器發送郵件看看效果:

>>> import smtplib
>>> s = smtplib.SMTP("smtp.163.com")
>>> s.login("baojingtongzhi@163.com", "xxx")
(235, 'Authentication successful')
>>> tolist = ["xxx@qq.com", "xxx@163.com"]
>>> msg = '''\
... From: baojingtongzhi@163.com
... Subject: test
... This is a test '''
>>> s.sendmail("baojingtongzhi@163.com", tolist, msg)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib64/python2.6/smtplib.py", line 725, in sendmail
    raise SMTPDataError(code, resp)
smtplib.SMTPDataError: (554, 'DT:SPM 163 smtp10,DsCowAAXIdDIJAtYkZiTAA--.65425S2 1477125592,please see http://mail.163.com/help/help_spam_16.htm?ip=119.57.73.67&hostid=smtp10&time=1477125592')

訪問給出的163網址,SMTP554錯誤是: "554 DT:SUM 信封發件人和信頭髮件人不匹配;"

大概已經明白啥意思,看上面再使用本地SMTP服務器時候,收件人位置是「undisclosed-recipients」,看這樣163的SMTP服務器不給咱們服務的緣由就是這裏收件人沒指定。

從新修改下msg對象,添加上收件人:

>>> msg = '''\           
... From: baojingtongzhi@163.com
... To: xxxx@qq.com ,xxx@163.com
... Subject: test
...
... This is a test '''
>>> s.sendmail("baojingtongzhi@163.com", tolist, msg)
{}

wKiom1gzo_2j6KkgAABXJfMQ1Kg062.png

好了,能夠正常發送郵件了。msg這個格式是SMTP規定的,必定要遵照。

14.1 Python發送郵件並抄送

#!/usr/bin/python
# -*- coding: utf-8 -*-
import smtplib
def sendMail(body):
    smtp_server = 'smtp.163.com'
    from_mail = 'baojingtongzhi@163.com'
    mail_pass = 'xxx'
    to_mail = ['xxx@qq.com', 'xxx@163.com']
    cc_mail = ['lizhenliang@xxx.com']
    from_name = 'monitor' 
    subject = u'監控'.encode('gbk')   # 以gbk編碼發送,通常郵件客戶端都能識別
#     msg = '''\
# From: %s <%s>
# To: %s
# Subject: %s
# %s''' %(from_name, from_mail, to_mail_str, subject, body)  # 這種方式必須將郵件頭信息靠左,也就是每行開頭不能用空格,不然報SMTP 554
    mail = [
        "From: %s <%s>" % (from_name, from_mail),
        "To: %s" % ','.join(to_mail),   # 轉成字符串,以逗號分隔元素
        "Subject: %s" % subject,
        "Cc: %s" % ','.join(cc_mail),
        "",
        body
        ]
    msg = '\n'.join(mail)  # 這種方式先將頭信息放到列表中,而後用join拼接,並以換行符分隔元素,結果就是和上面註釋同樣了
    try:
        s = smtplib.SMTP()
        s.connect(smtp_server, '25')
        s.login(from_mail, mail_pass)
        s.sendmail(from_mail, to_mail+cc_mail, msg)   
        s.quit()
    except smtplib.SMTPException as e:
        print "Error: %s" %e
if __name__ == "__main__":
    sendMail("This is a test!")

wKioL1gzpD_DOmxOAABXFj0zUKE200.png

s.sendmail(from_mail, to_mail+cc_mail, msg) 在這裏注意下,收件人和抄送人爲何放一塊兒發送呢?其實不管是收件人仍是抄送人,它們收到的郵件都是同樣的,SMTP都是認爲收件人這樣一封一封的發出。因此實際上並無抄送這個概念,只是在郵件頭加了抄送人的信息罷了!另外,若是不須要抄送人,直接把上面cc的信息去掉便可。

14.2 Python發送郵件帶附件

因爲SMTP.sendmail()方法不支持添加附件,因此可使用email模塊來知足需求。email模塊是一個構造郵件和解析郵件的模塊。

先看下如何用email庫構造一個簡單的郵件:

message = Message()
message['Subject'] = '郵件主題'
message['From'] = from_mail
message['To'] = to_mail
message['Cc'] = cc_mail
message.set_payload('郵件內容')

基本的格式就是這樣的!

繼續回到主題,發送郵件帶附件:

#!/usr/bin/python
# -*- coding: utf-8 -*-
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.header import Header
from email import encoders
from email.mime.base import MIMEBase
from email.utils import parseaddr, formataddr
# 格式化郵件地址
def formatAddr(s):
    name, addr = parseaddr(s)
    return formataddr((Header(name, 'utf-8').encode(), addr))
def sendMail(body, attachment):
    smtp_server = 'smtp.163.com'
    from_mail = 'baojingtongzhi@163.com'
    mail_pass = 'xxx'
    to_mail = ['xxx@qq.com', 'xxx@163.com']
    # 構造一個MIMEMultipart對象表明郵件自己
    msg = MIMEMultipart()
    # Header對中文進行轉碼
    msg['From'] = formatAddr('管理員 <%s>' % from_mail).encode()
    msg['To'] = ','.join(to_mail)
    msg['Subject'] = Header('監控', 'utf-8').encode()
    # plain表明純文本
    msg.attach(MIMEText(body, 'plain', 'utf-8'))
    # 二進制方式模式文件
    with open(attachment, 'rb') as f:
        # MIMEBase表示附件的對象
        mime = MIMEBase('text', 'txt', filename=attachment)
        # filename是顯示附件名字
        mime.add_header('Content-Disposition', 'attachment', filename=attachment)
        # 獲取附件內容
        mime.set_payload(f.read())
        encoders.encode_base64(mime)
        # 做爲附件添加到郵件
        msg.attach(mime)
    try:
        s = smtplib.SMTP()
        s.connect(smtp_server, "25")
        s.login(from_mail, mail_pass)
        s.sendmail(from_mail, to_mail, msg.as_string())  # as_string()把MIMEText對象變成str
        s.quit()
    except smtplib.SMTPException as e:
        print "Error: %s" % e
if __name__ == "__main__":
    sendMail('附件是測試數據, 請查收!', 'test.txt')

wKioL1gzpLrwrjscAAB4kh5xWwY921.png-wh_50

博客地址:http://lizhenliang.blog.51cto.com

QQ羣:323779636(Shell/Python運維開發羣


14.3 Python發送HTML郵件

#!/usr/bin/python
# -*- coding: utf-8 -*-
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.header import Header
from email.utils import parseaddr, formataddr
# 格式化郵件地址
def formatAddr(s):
    name, addr = parseaddr(s)
    return formataddr((Header(name, 'utf-8').encode(), addr))
def sendMail(body):
    smtp_server = 'smtp.163.com'
    from_mail = 'baojingtongzhi@163.com'
    mail_pass = 'xxx'
    to_mail = ['xxx@qq.com', 'xxx@163.com']
    # 構造一個MIMEMultipart對象表明郵件自己
    msg = MIMEMultipart() 
    # Header對中文進行轉碼
    msg['From'] = formatAddr('管理員 <%s>' % from_mail).encode()
    msg['To'] = ','.join(to_mail)
    msg['Subject'] = Header('監控', 'utf-8').encode()
    msg.attach(MIMEText(body, 'html', 'utf-8'))
    try:
        s = smtplib.SMTP()     
        s.connect(smtp_server, "25")   
        s.login(from_mail, mail_pass)
        s.sendmail(from_mail, to_mail, msg.as_string())  # as_string()把MIMEText對象變成str     
        s.quit()
    except smtplib.SMTPException as e:
        print "Error: %s" % e
if __name__ == "__main__":
    body = """
    <h1>測試郵件</h1>
    <h2 style="color:red">This is a test</h1>
    """
    sendMail(body)

wKioL1gzpUHyqoafAABa04eLS1A073.png

14.4 Python發送圖片郵件

#!/usr/bin/python
# -*- coding: utf-8 -*-
import smtplib
from email.mime.text import MIMEText
from email.mime.image import MIMEImage
from email.mime.multipart import MIMEMultipart
from email.header import Header
from email.utils import parseaddr, formataddr
# 格式化郵件地址
def formatAddr(s):
    name, addr = parseaddr(s)
    return formataddr((Header(name, 'utf-8').encode(), addr))
def sendMail(body, image):
    smtp_server = 'smtp.163.com'
    from_mail = 'baojingtongzhi@163.com'
    mail_pass = 'xxx'
    to_mail = ['xxx@qq.com', 'xxx@163.com']
    # 構造一個MIMEMultipart對象表明郵件自己
    msg = MIMEMultipart() 
    # Header對中文進行轉碼
    msg['From'] = formatAddr('管理員 <%s>' % from_mail).encode()
    msg['To'] = ','.join(to_mail)
    msg['Subject'] = Header('監控', 'utf-8').encode()
    msg.attach(MIMEText(body, 'html', 'utf-8'))
    # 二進制模式讀取圖片
    with open(image, 'rb') as f:
        msgImage = MIMEImage(f.read())
    # 定義圖片ID
    msgImage.add_header('Content-ID', '<image1>')
    msg.attach(msgImage)
    try:
        s = smtplib.SMTP()     
        s.connect(smtp_server, "25")   
        s.login(from_mail, mail_pass)
        s.sendmail(from_mail, to_mail, msg.as_string())  # as_string()把MIMEText對象變成str     
        s.quit()
    except smtplib.SMTPException as e:
        print "Error: %s" % e
if __name__ == "__main__":
    body = """
    <h1>測試圖片</h1>
    <img src="cid:image1"/>    # 引用圖片
    """
    sendMail(body, 'test.png')

wKiom1gzpXOjnJQEAAKvLRjLBhw508.png

上面發郵件的幾種常見的發郵件方法基本知足平常需求了。

相關文章
相關標籤/搜索