自动化打包续(Python发送邮件)

起因

机器运行的越来慢,每天启动模拟器需要十几分钟,打个发布包也需要十分钟左右,实在受不了这个速度,一咬牙一跺脚就把机器格式化了(其实是作死行为,为后来半个月工作带来了不小的麻烦)。重装部分软件后发现我的打包脚本邮件有时候发送邮件到个别邮箱时,邮件无法准时到达。当时是怎么配置发送环境的资料也随电脑格式化烟消云散了。更不想再去重走回头路,按照原来的方法一步步去配置。最近也是在学习Python,有这样的一个机会学以致用使用Python发送邮件貌似不能够错过。

需求

  • 1.发送邮件。能够正常、准时、稳定发送有标题、正文并且带有附件的邮件。
  • 2.能够在Mac终端使用命令行操作操作。能与Shell打包脚本之间参数传递
  • 3.发送邮件时候能够直观看到发送的进度,上传的网络速率(目前尚未实现)等等

实现过程

发送带附件的邮件

python使用smtp发送邮件。关于这个我觉得没有什么好说的,详情见菜鸟教程Python 2.7教程

获取邮件发送进度和网速

有时候我希望看到邮件的发送进度,但smtp自身并不能直接显示邮件发送的进度。我们可以通过每秒读取文件数据占总量百分比来实现需求。阅读其源码找到如下代码对其做一定拓展貌似能满足我们的需求。

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)

我们可以在其发送过程中获取每秒钟监测到发送的字节数,并将其输出出来,这样就能获取其发送进度和网速了.

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

    #参数配置
    from_addr = "xyhuangjia@yeah.net"
    password = "HJ19930112"
    to_addr = ["dengq@ywsoftware.com","huangj@ywsoftware.com"]
    smtp_server = "smtp.yeah.net"

    #邮件信息配置
    #正文
    content = u'%s新版本(版本号)的安装包已发送,请将本版本的需要变更之处用文本记录下来发送给本人,谢谢🙏'% sys.argv[3]
    #标题(使用传输过来的数据)
    subject = u'%s的安装包' % sys.argv[3]
    emailFrom = "鶸开发黄小佳"
    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 邮件已发送!\033[0m"
    else:
        print "邮件发送失败!"

注意:

没事不要开什么调试模式server.set_debuglevel(1)打开后会输出代码执行过程,在含有大附件的邮件在发送时会严重的拖慢进度,要注意这个

参考文章链接

Python发送以整个文件夹的内容为附件的邮件的教程

smtplib

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,242评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,769评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,484评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,133评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,007评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,080评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,496评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,190评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,464评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,549评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,330评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,205评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,567评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,889评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,160评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,475评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,650评论 2 335

推荐阅读更多精彩内容