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

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

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# --2015.09.07--
# 脚本用来替换nagios监控发报警邮件
# sendemail.py 
# 方法:
# printf "邮件内容" | sendemail.py -s "邮件主题" -R 收件人1,收件人2
import smtplib,sys,random,getopt
from email.mime.text import MIMEText
def sendemail():
    subject = ''
    receivers = []
    sendlist = [('smtp.aliyun.com', 'mail@aliyun.com'), ('smtp.sina.com', 'mail@sina.com'),  ('smtp.sina.cn', 'mail@sina.cn'), ('smtp.qq.com', 'mail@foxmail.com')]
    rannum = random.randint(0, 3)
    host = sendlist[rannum][0]
    sender = sendlist[rannum][1]
    port = 465
    copyto = ['10000@qq.com', '10001@qq.com', '10002@qq.com', '10003@qq.com', '10004@qq.com']
    passwd = 'xxxx'
    #参数获取收件人
    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
    s = smtplib.SMTP_SSL(host, port)
    s.login(sender, passwd)
    s.sendemail(sender, receivers, msg.as_string())

count = 1
while count < 10:
    try:
        sendemail()
    except smtplib.SMTPSenderRefused:
        count += 1
    else:
        break

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

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

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

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

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

#9.7更新:改为多个发件邮箱随机发送,所以要用的话可以改sendlist,和pass就可以(所以发件邮箱密码要一致)

列出几个遇到问题

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 msg
From nobody Tue Aug 11 10:54:59 2015
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
subject: test mail
from: from@qq.com
to: to@qq.com
cc: cc@qq.com

123456

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

https://docs.python.org/2/library/email.mime.html#email.mime.text.MIMEText

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

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

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

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

receivers = receivers + copyto

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

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

可以参考这里:

https://docs.python.org/2/library/smtplib.html#smtplib.SMTP.sendmail

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

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

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

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

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

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# name: 1.py
import sys
print 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.py
import sys
print 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.py
import sys,getopt

opts, args = getopt.getopt(sys.argv[1:], 's:R:', ['help', 'text='])
print opts
print 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

5、部署nagios后,printf错误及脚本权限拒绝错误

[1439344817] wproc:   stderr line 01: /usr/bin/printf: %):无效的转换声明
[1439344817] wproc:   stderr line 02: python: can't open file '/usr/local/nagios/shell/sendemail.py': [Errno 13] Permission denied

⑴printf错误,这个是忘记加“%b”格式化指示符了

%b 相对应的参数被视为含有要被处理的转义序列之字符串。

⑵脚本权限拒绝错误解决方法

第一,不要放到/root目录下,这样给任何权限都没有用的,因为nagios访问不到/root

第二,不光要给他执行权限还要给读权限(chmod o+rx sendemail.py)