如何将Python脚本作为定时任务格式化为带附件的邮件输出?

1 投票
1 回答
924 浏览
提问于 2025-04-18 12:51

因为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"]

撰写回答