最近在搞把nagios报警邮箱换到163、sina这种免费邮箱上边,之前用过msmtp搞过也可以发送邮件,现在估计是他们系统都升级了,只能使用TSL加密连接,而msmtp怎么配置都配不通,无奈只能转移战术,正好最近在学习Python,也不知道从哪瞄到过有个email的模块,所以准备试试自己搞个脚本。

  (新手,无编程基础,希望多多指教)

-----2016.1.4 修改----

前提:

更改nagios/etc/object/command.cfg里发送邮件的command配置,例如我这样:

# 'notify-host-by-email' command definitiondefine command{        command_name    notify-host-by-email        command_line    /usr/bin/printf "%b" "Host: $HOSTNAME$\nState: $HOSTSTATE$\nAddress: $HOSTADDRESS$\nInfo: $HOSTOUTPUT$\n\nDate/Time: $LONGDATETIME$\n" | /usr/local/nagios/shell/sendemail.py -s "$HOSTADDRESS$ is $HOSTSTATE$" -R $CONTACTEMAIL$        } # 'notify-service-by-email' command definition       define command{        command_name    notify-service-by-email        command_line    /usr/bin/printf "%b" "Service: $SERVICEDESC$\nHost: $HOSTALIAS$\nAddress: $HOSTADDRESS$\nState: $SERVICESTATE$\nAdditional Info: $SERVICEOUTPUT$\n\nDate/Time: $LONGDATETIME$\n" | /usr/local/nagios/shell/sendemail.py -s "$HOSTADDRESS$/$SERVICEDESC$ is $SERVICESTATE$" -R $CONTACTEMAIL$        }

sendemail脚本

#!/usr/bin/env python# -*- coding: utf-8 -*-# --2016.01.04-- v2.0# 脚本用来替换nagios监控发报警邮件# sendemail.py # 方法:# printf "邮件内容" | sendemail.py -s "邮件主题" -R 收件人1,收件人2import smtplib,sys,random,getoptfrom email.mime.text import MIMETextdef sendemail(host, sender, SSL=True):    subject = ''    receivers = []    host = host    sender = sender    copyto = ['10001@qq.com', '10002@qq.com', '10003@qq.com', '10004@qq.com', '10005@qq.com']    passwd = 'password'    #参数获取收件人    try:        opts, args = getopt.getopt(sys.argv[1:], 's:R:')        for i in opts:            if '-s' in i:                subject = i[1]            elif '-R' in i:                receivers.append(i[1])    except getopt.GetoptError, e:        print e    #以下代码段使用的MIMEText函数会生成邮件头格式,方便后边发送邮件时提供一些选项配置(object.sendmail方法)    body = ''.join(sys.stdin.readlines())    msg = MIMEText(body)    msg['subject'] = subject    msg['from'] = sender    msg['to'] = ','.join(receivers)    msg['cc'] = ','.join(copyto)    receivers = receivers + copyto    if SSL :        port = 465        s = smtplib.SMTP_SSL(host, port)    else :        port = 25        s = smtplib.SMTP(host, port)    s.login(sender, passwd)    s.sendmail(sender, receivers, msg.as_string())def someone():    backuplist = [('smtp.yourdomain.com', 'yourmail@yourdomain.com'),  ('smtp.yourdomain.cn', 'yourmail@yourdomain.cn')]    some_one = random.choice(backuplist)    return some_one    def main():    count = 0    while count <5 :        try:            sendemail('mail.cipnet.cn', 'nagios@cipnet.cn', False)         except:            host,sender = someone()            try:                sendemail(host,sender)            except:                continue            else:                break        else:             break            if __name__ == '__main__':    main()

 脚本略乱,我是大致分为三部分

第一部分,用于设置发件人收件人主题等变量

第二部分,使用MIMEText函数把邮件内容主题等格式化为邮件头格式

第三部分,登录邮箱,发送邮件代码

   如果不嫌弃,想拿去用的话,可以改下发件人(sender变量)、发件smtp(Host变量)、发件人密码(pass变量)、抄送人(copyto变量,我们公司就固定几个人所以我直接把邮箱写脚本,你也可以写成参数指定)

列出几个遇到问题

1、不明白MIMEText到底是个什么东西,它生成是什么样一个邮件头?

然后我把命令挨个敲了一遍

>>> from email.mime.text import MIMEText>>> body = '123456'>>> subject = 'test mail'>>> sender = 'from@qq.com'      >>> receivers = 'to@qq.com'>>> copyto = 'cc@qq.com'>>> msg = MIMEText(body)>>> msg['subject'] = subject>>> msg['from'] = sender>>> msg['to'] = receivers>>> msg['cc'] = copyto>>> print msgFrom nobody Tue Aug 11 10:54:59 2015Content-Type: text/plain; charset="us-ascii"MIME-Version: 1.0Content-Transfer-Encoding: 7bitsubject: test mailfrom: from@qq.comto: to@qq.comcc: cc@qq.com123456

就是这样,就是一个纯文本格式,对了,MIMEText函数还可以指定第二个参数为格式,例如html格式,具体可以参考这里:

2、收件人可以收到、抄送人和暗送人怎么都收不到?

这个确实纠结了不少时间,而且关键是收件人收到的邮件下边是有抄送人的!

这让我一度怀疑smtplib模块并不支持抄送的!

后来我查到有一个模糊回答说,你要把cc和bcc加入list!我就觉得肯定可以解决,然后我继续查了下去,果然你只需要以下这行代码就可以!

receivers = receivers + copyto

.sendmail方法的第二个参数也就是收件人参数指定的是所有可以收到这封邮件的人,所以我们要把收件人、抄送人、暗送合并到一起

而具体谁是收件人和抄送人已经在MIMEText函数格式化过了,并且会赋给.sendmail的第三个参数

可以参考这里:

3、python标准输入readline与readlines区别

#!/usr/bin/env python# -*- coding: utf-8 -*-# name: 1.pyimport syswhile True:    line = sys.stdin.readline()    if not line: break    sys.stdout.write(line) ------------------------------------------------------------------------------------[root@xfwy tmp]# printf "1\n2\n3" | ./1.py 123
#!/usr/bin/env python# -*- coding: utf-8 -*-# name: 2.pyimport sysfor i in sys.stdin.readlines():    sys.stdout.write(i)-------------------------------------------------------------------------------------[root@xfwy tmp]# printf "1\n2\n3\n" | ./2.py  123

.readline()方法和.readlines()方法区别(两个方法均不属于sys.stdin下的方法)

所以,python标准输入输出问题不讨论。

⑴、readline是以行读取,直到遇到换行符结束。

#!/usr/bin/env python# -*- coding: utf-8 -*-# name: 1.pyimport sysprint sys.stdin.readline()------------------------------------------------------------------------------------[root@xfwy tmp]# printf "1" | ./1.py   1[root@xfwy tmp]# printf "1\n" | ./1.py 1[root@xfwy tmp]# printf "1\n2" | ./1.py 1[root@xfwy tmp]# printf "1\n\n" | ./1.py  1

⑵、readlines则是读取所有内容,把他们保存为列表

#!/usr/bin/env python# -*- coding: utf-8 -*-# name: 2.pyimport sysprint sys.stdin.readlines()------------------------------------------------------------------------------------[root@xfwy tmp]# printf "1\n2" | ./2.py    ['1\n', '2'][root@xfwy tmp]# printf "1\n2\n" | ./2.py ['1\n', '2\n']

4、getopt函数返回了两个表,这两个表分别保存是什么

# -*- coding: utf-8 -*-# name: test.pyimport sys,getoptopts, args = getopt.getopt(sys.argv[1:], 's:R:', ['help', 'text='])print optsprint args------------------------------------------------------------------------------------[root@xfwy tmp]# ./test.py -s sss -R rrr --help --text abc[('-s', 'sss'), ('-R', 'rrr'), ('--help', ''), ('--text', 'abc')][][root@xfwy tmp]# ./test.py -s sss -R rrr --help --text abc other -h[('-s', 'sss'), ('-R', 'rrr'), ('--help', ''), ('--text', 'abc')]['other', '-h']  #这样看来第二个表格用来寸未定义的参数

参数怎么写参考这里:

https://docs.python.org/2/library/getopt.html#getopt.getopt