如何将Python脚本作为定时任务格式化为带附件的邮件输出?
因为Cron可以把它执行的命令的输出通过邮件发给用户,所以我决定在我的项目中使用它。我很快意识到,我真的需要一种方法来把文件附加到生成的邮件中。我在Cron的文档中看到,可以把邮件的内容类型改成multipart/mixed,这样才能发送附件。那么,我该如何写一个Python脚本,让它在作为Cron任务运行时,开启邮件通知,把标准输出发到邮件正文里,并附上我觉得合适的文件呢?
1 个回答
1
在你的定时任务设置中添加以下内容:
CONTENT_TYPE='multipart/mixed; boundary="------------040907050602020300000601"'
现在,这个脚本会在消息正文中打印“Hello world”,并附上 /etc/redhat-release 文件,内容如下:
#!/usr/bin/python
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.base import MIMEBase
from email import encoders
import sys
import StringIO
import atexit
# Back up stdout and stderr. We'll overwrite them by StringIO to save the
# output to a string.
stdout_copy = sys.stdout
stderr_copy = sys.stderr
f = StringIO.StringIO()
sys.stdout = f
sys.stderr = f
# The MIME message we're going to wrap the program's output in.
msg = MIMEMultipart()
# This is the boundary I set in my crontab file. Kludgy, but I knew no other
# way to send multipart files from cron. To reproduce it, add the following
# to your crontab:
#
# CONTENT_TYPE='multipart/mixed; boundary="------------040907050602020300000601"'
msg.set_boundary('------------040907050602020300000601')
# At exit, print f's contents as a MIME message.
def flush_f():
# Rewind the f StringIO so that f.read() will read all the data.
f.seek(0)
# Restore stdout and stderr - this will let us print to the program's
# standard output. Note that we overwrite stderr with the stdout - this
# will let us see the error messages in crontab e-mails.
sys.stdout = stdout_copy
sys.stderr = stdout_copy
# Add the stdout contents to the message body.
stdout_contents = MIMEText(f.read(), "plain")
msg.attach(stdout_contents)
# Attach the attachments. We use "unknown" to trick Thunderbird into
# thinking that the file is binary.
for filename in filenames:
if filename.endswith(".png"):
attachment = MIMEBase("image", "png")
else:
attachment = MIMEBase("application", "unknown")
attachment.set_payload(open(filename).read())
attachment.add_header('Content-Disposition', 'attachment',
filename=filename)
encoders.encode_base64(attachment)
msg.attach(attachment)
# Print the final message.
print(msg.as_string())
atexit.register(flush_f)
print("Hello, world!")
filenames = ["/etc/redhat-release"]