起因
機器運行的越來慢型将,每天啟動模擬器需要十幾分鐘够挂,打個發(fā)布包也需要十分鐘左右钞速,實在受不了這個速度贷掖,一咬牙一跺腳就把機器格式化了(其實是作死行為,為后來半個月工作帶來了不小的麻煩)渴语。重裝部分軟件后發(fā)現(xiàn)我的打包腳本郵件有時候發(fā)送郵件到個別郵箱時苹威,郵件無法準時到達。當時是怎么配置發(fā)送環(huán)境的資料也隨電腦格式化煙消云散了驾凶。更不想再去重走回頭路牙甫,按照原來的方法一步步去配置。最近也是在學習Python狭郑,有這樣的一個機會學以致用使用Python發(fā)送郵件貌似不能夠錯過腹暖。
需求
- 1.發(fā)送郵件。能夠正常翰萨、準時脏答、穩(wěn)定發(fā)送有標題、正文并且?guī)в懈郊泥]件。
- 2.能夠在Mac終端使用命令行操作操作殖告。能與Shell打包腳本之間參數(shù)傳遞
- 3.發(fā)送郵件時候能夠直觀看到發(fā)送的進度阿蝶,上傳的網絡速率(目前尚未實現(xiàn))等等
實現(xiàn)過程
發(fā)送帶附件的郵件
python使用smtp發(fā)送郵件。關于這個我覺得沒有什么好說的黄绩,詳情見菜鳥教程和Python 2.7教程
獲取郵件發(fā)送進度和網速
有時候我希望看到郵件的發(fā)送進度羡洁,但smtp自身并不能直接顯示郵件發(fā)送的進度。我們可以通過每秒讀取文件數(shù)據(jù)占總量百分比來實現(xiàn)需求爽丹。閱讀其源碼找到如下代碼對其做一定拓展貌似能滿足我們的需求筑煮。
def data(self,msg):
"""SMTP 'DATA' command -- sends message data to server.
Automatically quotes lines beginning with a period per rfc821.
Raises SMTPDataError if there is an unexpected reply to the
DATA command; the return value from this method is the final
response code received when the all data is sent.
"""
self.putcmd("data")
(code,repl)=self.getreply()
if self.debugle vel >0 : print "data:", (code,repl)
if code != 354:
raise SMTPDataError(code,repl)
else:
q = quotedata(msg)
if q[-2:] != CRLF:
q = q + CRLF
q = q + "." + CRLF
self.send(q)
(code,msg)=self.getreply()
if self.debuglevel >0 : print "data:", (code,msg)
return (code,msg)
我們可以在其發(fā)送過程中獲取每秒鐘監(jiān)測到發(fā)送的字節(jié)數(shù),并將其輸出出來粤蝎,這樣就能獲取其發(fā)送進度和網速了.
global starttime,sendByteBySec
endtime = datetime.datetime.now()
percent = 100. * progress / total
stdout.write('\r')
starttime = endtime;
speedNum = (progress - sendByteBySec)/1024
if (endtime - starttime).seconds >=1:
# starttime = endtime;
# speedNum = (progress - sendByteBySec)/1024
stdout.write("%s bytes sent of %s [%2.0f%%]|Speed: [%2.0f%%]" % (progress, total, percent,speedNum))
# sendByteBySec = progress
else:
# starttime = endtime;
# speedNum = (progress - sendByteBySec)/1024
stdout.write("%s bytes sent of %s [%2.0f%%]|Speed: [%2.0f%%]" % (progress, total, percent,speedNum))
sendByteBySec = progress
stdout.flush()
# print (endtime - starttime).seconds
if percent >= 100: stdout.write('\n')
完整代碼如下
# !/usr/bin/python
# -*- coding: utf-8 -*-
# import smtplib
from smtplib import SMTP, quotedata, CRLF, SMTPDataError
from email import encoders
from email.header import Header
from email.mime.text import MIMEText
from email.utils import parseaddr, formataddr
from email.MIMEMultipart import MIMEMultipart
from email.mime.base import MIMEBase
from sys import stderr, stdout
import os,sys, time
class ExtendedSMTP(SMTP):
def data(self, msg):
self.putcmd("data")
(code,repl)=self.getreply()
if self.debuglevel > 0 : print >> stderr, "data:", (code, repl)
if code != 354:
raise SMTPDataError(code,repl)
else:
q = quotedata(msg)
if q[-2:] != CRLF:
q = q + CRLF
q = q + "." + CRLF
# begin modified send code
chunk_size = 2048
bytes_sent = 0
while bytes_sent != len(q):
chunk = q[bytes_sent:bytes_sent+chunk_size]
self.send(chunk)
bytes_sent += len(chunk)
if hasattr(self, "callback"):
self.callback(bytes_sent, len(q))
# end modified send code
(code,msg)=self.getreply()
if self.debuglevel >0 : print>>stderr, "data:", (code,msg)
return (code,msg)
def sendMail(filePath,fileName,appName):
def _format_addr(s):
name, addr = parseaddr(s)
return formataddr(( \
Header(name, 'utf-8').encode(), \
addr.encode('utf-8') if isinstance(addr, unicode) else addr))
def callback(progress, total):
percent = 100. * progress / total
stdout.write('\r')
stdout.write("%s bytes sent of %s [%2.0f%%]" % (progress, total, percent))
stdout.flush()
if percent >= 100: stdout.write('\n')
#參數(shù)配置
from_addr = "xyhuangjia@yeah.net"
password = "HJ19930112"
to_addr = ["dengq@ywsoftware.com","huangj@ywsoftware.com"]
smtp_server = "smtp.yeah.net"
#郵件信息配置
#正文
content = u'%s新版本(版本號)的安裝包已發(fā)送真仲,請將本版本的需要變更之處用文本記錄下來發(fā)送給本人,謝謝??'% sys.argv[3]
#標題(使用傳輸過來的數(shù)據(jù))
subject = u'%s的安裝包' % sys.argv[3]
emailFrom = "鶸開發(fā)黃小佳"
msg = MIMEMultipart()
msg['From'] = _format_addr('%s<%s>' % (emailFrom,from_addr))
msg['To'] = _format_addr(u'接受者 <%s>' % to_addr)
msg['Subject'] = Header('%s' % subject, 'utf-8').encode()
msg.attach(MIMEText('%s'%content, 'plain', 'utf-8'))
mime = MIMEBase('application', 'octet-stream', filename=fileName)
with open(filePath, 'rb') as f:
# 加上必要的頭信息:
mime.add_header('Content-Disposition', 'attachment', filename=fileName)
mime.add_header('Content-ID', '<0>')
mime.add_header('X-Attachment-Id', '0')
mime.set_payload(f.read())
# 用Base64編碼:
encoders.encode_base64(mime)
# 添加到MIMEMultipart:
msg.attach(mime)
try:
server = ExtendedSMTP()
server.callback = callback
server.connect(smtp_server, 25)
# server.set_debuglevel(1)#坑爹的調試模式初澎,打開輸出一萬行坑了我四天
server.login(from_addr, password)
server.sendmail(from_addr, to_addr, msg.as_string())
server.quit()
return True
except Exception as e:
raise e
return False
if __name__ == '__main__':
# print sys.argv
if sendMail(sys.argv[1], sys.argv[2], sys.argv[3]):
print "\033[32;1m 郵件已發(fā)送!\033[0m"
else:
print "郵件發(fā)送失敗!"
注意:
沒事不要開什么調試模式server.set_debuglevel(1)
打開后會輸出代碼執(zhí)行過程秸应,在含有大附件的郵件在發(fā)送時會嚴重的拖慢進度,要注意這個