1. 程式人生 > >Python發送郵件(常見四種郵件內容)

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

t對象 3.6 idt serve ttl dddd python tdi tls

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

轉載 2017年03月03日 17:17:04

轉自:http://lizhenliang.blog.51cto.com/7876557/1875330

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

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

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

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

這個類有幾個常用的方法:

方法

描述

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=[])

發送郵件

from_addr:郵件發件人

to_addrs:郵件收件人

msg:發送消息

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

看下官方給的示例:

[python] view plain copy
  1. >>> import smtplib
  2. >>> s=smtplib.SMTP("localhost")
  3. >>> tolist=["[email protected]","[email protected]","[email protected]","[email protected]"]
  4. >>> msg = ‘‘‘‘‘\
  5. ... From: [email protected]
  6. ... Subject: testin‘...
  7. ...
  8. ... This is a test ‘‘‘
  9. >>> s.sendmail("[email protected]",tolist,msg)
  10. { "[email protected]" : ( 550 ,"User unknown" ) }
  11. >>> s.quit()

我們根據示例給自己發一個郵件測試下:

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

CentOS安裝sendmail:yum install sendmail

[python] view plain copy
  1. >>> import smtplib
  2. >>> s = smtplib.SMTP("localhost")
  3. >>> tolist = ["[email protected]", "[email protected]"]
  4. >>> msg = ‘‘‘‘‘\
  5. ... From: [email protected]
  6. ... Subject: test
  7. ... This is a test ‘‘‘
  8. >>> s.sendmail("[email protected]", tolist, msg)
  9. {}


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

技術分享圖片

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

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

[python] view plain copy
  1. >>> import smtplib
  2. >>> s = smtplib.SMTP("smtp.163.com")
  3. >>> s.login("[email protected]", "xxx")
  4. (235, ‘Authentication successful‘)
  5. >>> tolist = ["[email protected]", "[email protected]"]
  6. >>> msg = ‘‘‘‘‘\
  7. ... From: [email protected]
  8. ... Subject: test
  9. ... This is a test ‘‘‘
  10. >>> s.sendmail("[email protected]", tolist, msg)
  11. Traceback (most recent call last):
  12. File "<stdin>", line 1, in <module>
  13. File "/usr/lib64/python2.6/smtplib.py", line 725, in sendmail
  14. raise SMTPDataError(code, resp)
  15. 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對象,添加上收件人:

[python] view plain copy
  1. >>> msg = ‘‘‘‘‘\
  2. ... From: [email protected]
  3. ... To: [email protected] ,[email protected]
  4. ... Subject: test
  5. ...
  6. ... This is a test ‘‘‘
  7. >>> s.sendmail("[email protected]", tolist, msg)
  8. {}

技術分享圖片

好了,可以正常發送郵件了。msg這個格式是SMTP規定的,一定要遵守。

1、Python發送郵件並抄送

[python] view plain copy
  1. #!/usr/bin/python
  2. # -*- coding: utf-8 -*-
  3. import smtplib
  4. def sendMail(body):
  5. smtp_server = ‘smtp.163.com‘
  6. from_mail = [email protected]
  7. mail_pass = ‘xxx‘
  8. to_mail = [[email protected]‘, [email protected]‘]
  9. cc_mail = [[email protected]‘]
  10. from_name = ‘monitor‘
  11. subject = u‘監控‘.encode(‘gbk‘) # 以gbk編碼發送,一般郵件客戶端都能識別
  12. # msg = ‘‘‘\
  13. # From: %s <%s>
  14. # To: %s
  15. # Subject: %s
  16. # %s‘‘‘ %(from_name, from_mail, to_mail_str, subject, body) # 這種方式必須將郵件頭信息靠左,也就是每行開頭不能用空格,否則報SMTP 554
  17. mail = [
  18. "From: %s <%s>" % (from_name, from_mail),
  19. "To: %s" % ‘,‘.join(to_mail), # 轉成字符串,以逗號分隔元素
  20. "Subject: %s" % subject,
  21. "Cc: %s" % ‘,‘.join(cc_mail),
  22. "",
  23. body
  24. ]
  25. msg = ‘\n‘.join(mail) # 這種方式先將頭信息放到列表中,然後用join拼接,並以換行符分隔元素,結果就是和上面註釋一樣了
  26. try:
  27. s = smtplib.SMTP()
  28. s.connect(smtp_server, ‘25‘)
  29. s.login(from_mail, mail_pass)
  30. s.sendmail(from_mail, to_mail+cc_mail, msg)
  31. s.quit()
  32. except smtplib.SMTPException as e:
  33. print "Error: %s" %e
  34. if __name__ == "__main__":
  35. sendMail("This is a test!")

技術分享圖片

s.sendmail(from_mail, to_mail+cc_mail, msg) 在這裏註意下,收件人和抄送人為什麽放一起發送呢?其實無論是收件人還是抄送人,它們收到的郵件都是一樣的,SMTP都是認為收件人這樣一封一封的發出。所以實際上並沒有抄送這個概念,只是在郵件頭加了抄送人的信息罷了!另外,如果不需要抄送人,直接把上面cc的信息去掉即可。

2 Python發送郵件帶附件

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

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

[python] view plain copy
  1. message = Message()
  2. message[‘Subject‘] = ‘郵件主題‘
  3. message[‘From‘] = from_mail
  4. message[‘To‘] = to_mail
  5. message[‘Cc‘] = cc_mail
  6. message.set_payload(‘郵件內容‘)

基本的格式就是這樣的!

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

[python] view plain copy
  1. #!/usr/bin/python
  2. # -*- coding: utf-8 -*-
  3. import smtplib
  4. from email.mime.text import MIMEText
  5. from email.mime.multipart import MIMEMultipart
  6. from email.header import Header
  7. from email import encoders
  8. from email.mime.base import MIMEBase
  9. from email.utils import parseaddr, formataddr
  10. # 格式化郵件地址
  11. def formatAddr(s):
  12. name, addr = parseaddr(s)
  13. return formataddr((Header(name, ‘utf-8‘).encode(), addr))
  14. def sendMail(body, attachment):
  15. smtp_server = ‘smtp.163.com‘
  16. from_mail = [email protected]
  17. mail_pass = ‘xxx‘
  18. to_mail = [[email protected]‘, [email protected]‘]
  19. # 構造一個MIMEMultipart對象代表郵件本身
  20. msg = MIMEMultipart()
  21. # Header對中文進行轉碼
  22. msg[‘From‘] = formatAddr(‘管理員 <%s>‘ % from_mail).encode()
  23. msg[‘To‘] = ‘,‘.join(to_mail)
  24. msg[‘Subject‘] = Header(‘監控‘, ‘utf-8‘).encode()
  25. # plain代表純文本
  26. msg.attach(MIMEText(body, ‘plain‘, ‘utf-8‘))
  27. # 二進制方式模式文件
  28. with open(attachment, ‘rb‘) as f:
  29. # MIMEBase表示附件的對象
  30. mime = MIMEBase(‘text‘, ‘txt‘, filename=attachment)
  31. # filename是顯示附件名字
  32. mime.add_header(‘Content-Disposition‘, ‘attachment‘, filename=attachment)
  33. # 獲取附件內容
  34. mime.set_payload(f.read())
  35. encoders.encode_base64(mime)
  36. # 作為附件添加到郵件
  37. msg.attach(mime)
  38. try:
  39. s = smtplib.SMTP()
  40. s.connect(smtp_server, "25")
  41. s.login(from_mail, mail_pass)
  42. s.sendmail(from_mail, to_mail, msg.as_string()) # as_string()把MIMEText對象變成str
  43. s.quit()
  44. except smtplib.SMTPException as e:
  45. print "Error: %s" % e
  46. if __name__ == "__main__":
  47. sendMail(‘附件是測試數據, 請查收!‘, ‘test.txt‘)

技術分享圖片
3 Python發送HTML郵件

[python] view plain copy
  1. #!/usr/bin/python
  2. # -*- coding: utf-8 -*-
  3. import smtplib
  4. from email.mime.text import MIMEText
  5. from email.mime.multipart import MIMEMultipart
  6. from email.header import Header
  7. from email.utils import parseaddr, formataddr
  8. # 格式化郵件地址
  9. def formatAddr(s):
  10. name, addr = parseaddr(s)
  11. return formataddr((Header(name, ‘utf-8‘).encode(), addr))
  12. def sendMail(body):
  13. smtp_server = ‘smtp.163.com‘
  14. from_mail = [email protected]
  15. mail_pass = ‘xxx‘
  16. to_mail = [[email protected]‘, [email protected]‘]
  17. # 構造一個MIMEMultipart對象代表郵件本身
  18. msg = MIMEMultipart()
  19. # Header對中文進行轉碼
  20. msg[‘From‘] = formatAddr(‘管理員 <%s>‘ % from_mail).encode()
  21. msg[‘To‘] = ‘,‘.join(to_mail)
  22. msg[‘Subject‘] = Header(‘監控‘, ‘utf-8‘).encode()
  23. msg.attach(MIMEText(body, ‘html‘, ‘utf-8‘))
  24. try:
  25. s = smtplib.SMTP()
  26. s.connect(smtp_server, "25")
  27. s.login(from_mail, mail_pass)
  28. s.sendmail(from_mail, to_mail, msg.as_string()) # as_string()把MIMEText對象變成str
  29. s.quit()
  30. except smtplib.SMTPException as e:
  31. print "Error: %s" % e
  32. if __name__ == "__main__":
  33. body = """
  34. <h1>測試郵件</h1>
  35. <h2 style="color:red">This is a test</h1>
  36. """
  37. sendMail(body)

技術分享圖片
4 Python發送圖片郵件

[python] view plain copy
  1. #!/usr/bin/python
  2. # -*- coding: utf-8 -*-
  3. import smtplib
  4. from email.mime.text import MIMEText
  5. from email.mime.image import MIMEImage
  6. from email.mime.multipart import MIMEMultipart
  7. from email.header import Header
  8. from email.utils import parseaddr, formataddr
  9. # 格式化郵件地址
  10. def formatAddr(s):
  11. name, addr = parseaddr(s)
  12. return formataddr((Header(name, ‘utf-8‘).encode(), addr))
  13. def sendMail(body, image):
  14. smtp_server = ‘smtp.163.com‘
  15. from_mail = [email protected]
  16. mail_pass = ‘xxx‘
  17. to_mail = [[email protected]‘, [email protected]‘]
  18. # 構造一個MIMEMultipart對象代表郵件本身
  19. msg = MIMEMultipart()
  20. # Header對中文進行轉碼
  21. msg[‘From‘] = formatAddr(‘管理員 <%s>‘ % from_mail).encode()
  22. msg[‘To‘] = ‘,‘.join(to_mail)
  23. msg[‘Subject‘] = Header(‘監控‘, ‘utf-8‘).encode()
  24. msg.attach(MIMEText(body, ‘html‘, ‘utf-8‘))
  25. # 二進制模式讀取圖片
  26. with open(image, ‘rb‘) as f:
  27. msgImage = MIMEImage(f.read())
  28. # 定義圖片ID
  29. msgImage.add_header(‘Content-ID‘, ‘<image1>‘)
  30. msg.attach(msgImage)
  31. try:
  32. s = smtplib.SMTP()
  33. s.connect(smtp_server, "25")
  34. s.login(from_mail, mail_pass)
  35. s.sendmail(from_mail, to_mail, msg.as_string()) # as_string()把MIMEText對象變成str
  36. s.quit()
  37. except smtplib.SMTPException as e:
  38. print "Error: %s" % e
  39. if __name__ == "__main__":
  40. body = """
  41. <h1>測試圖片</h1>
  42. <img src="cid:image1"/> # 引用圖片
  43. """
  44. sendMail(body, ‘test.png‘)

技術分享圖片
上面發郵件的幾種常見的發郵件方法基本滿足日常需求了。

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