使用Python发送邮件,从文本文件中读取收件人列表

0 投票
3 回答
3620 浏览
提问于 2025-04-16 17:44

我写了一段代码,现在可以用它在OSX10.6上发送电子邮件。不过,我想在这个脚本中增加一个功能,就是直接从和这个Python文件在同一个文件夹里的文本文件中获取收件人列表。

我还想把发件人的信息写死,因为这个是固定不变的。请帮帮我。

#!/usr/bin/env python

"""Send the contents of a directory as a MIME message."""

import os
import sys
import smtplib
# For guessing MIME type based on file name extension
import mimetypes

from optparse import OptionParser

from email import encoders
from email.message import Message
from email.mime.audio import MIMEAudio
from email.mime.base import MIMEBase
from email.mime.image import MIMEImage
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText

COMMASPACE = ', '

def main():
parser = OptionParser(usage="""\
Send the contents of a directory as a MIME message.

Usage: %prog [options]

Unless the -o option is given, the email is sent by forwarding to your local
SMTP server, which then does the normal delivery process. Your local machine
must be running an SMTP server.
""")
parser.add_option('-d','--directory',
type='string', action='store')
parser.add_option('-o', '--output',
type='string', action='store', metavar='FILE',
help="""Print the composed message to FILE instead of
sending the message to the SMTP server.""")
parser.add_option('-s', '--sender',
type='string', action='store', metavar='SENDER',
help='The value of the From: header (required)')
parser.add_option('-r', '--recipients',
type='string', action='store', metavar='RECIPIENT',
default="recipient.txt", dest='recipients',
help='A file containing email addresses of recipients. One recipient per line')
opts, args = parser.parse_args()
if not opts.sender or not opts.recipients:
    parser.print_help()
    sys.exit(1)
directory = opts.directory
if not directory:
    directory = '.'
# Create the enclosing (outer) message
outer = MIMEMultipart()
outer['Subject'] = 'Malware submission'

# Variable to hold the recipients string
rec = ""
# Open recipients file
f = open(opts.recipients)
# Loop through each line of the file
for line in f:
    # Remove whitespace from line and add COMMASPACE
    rec += line.rstrip() + COMMASPACE
f.close()

outer['To'] = rec[:-2]; #Remove last COMMASPACE
outer['From'] = opts.sender
outer.preamble = 'You will not see this in a MIME-aware mail reader.\n'

for filename in os.listdir(directory):
    path = os.path.join(directory, filename)
    if not os.path.isfile(path):
        continue
    # Guess the content type based on the file's extension. Encoding
    # will be ignored, although we should check for simple things like
    # gzip'd or compressed files.
    ctype, encoding = mimetypes.guess_type(path)
    if ctype is None or encoding is not None:
    # No guess could be made, or the file is encoded (compressed), so
    # use a generic bag-of-bits type.
        ctype = 'application/octet-stream'
        maintype, subtype = ctype.split('/', 1)
    if maintype == 'text':
        fp = open(path)
    # Note: we should handle calculating the charset
        msg = MIMEText(fp.read(), _subtype=subtype)
        fp.close()
    elif maintype == 'image':
        fp = open(path, 'rb')
        msg = MIMEImage(fp.read(), _subtype=subtype)
        fp.close()
    elif maintype == 'audio':
        fp = open(path, 'rb')
        msg = MIMEAudio(fp.read(), _subtype=subtype)
        fp.close()
    else:
        fp = open(path, 'rb')
        msg = MIMEBase(maintype, subtype)
        msg.set_payload(fp.read())
        fp.close()
    # Encode the payload using Base64
    encoders.encode_base64(msg)
# Set the filename parameter
msg.add_header('Content-Disposition', 'attachment', filename=filename)
outer.attach(msg)
# Now send or store the message
composed = outer.as_string()
if opts.output:
    fp = open(opts.output, 'w')
    fp.write(composed)
    fp.close()
else:
    s = smtplib.SMTP('localhost')
    s.sendmail(opts.sender, opts.recipients, composed)
    s.quit()

if __name__ == '__main__':
main()

非常感谢。

3 个回答

0

要获取接收者,你可以试试这个:

# add a new parameter 'recipientfile'
parser.add_option('-f', '--recipientfile',
              type='string', action='store', metavar='RECIPIENT_FILE',
              default=None, dest='recipient_file',
              help='A To: header value (a file containing this)')

opts, args = parser.parse_args()
if not opts.sender or (not opts.recipients or not opts.recipient_file):
    parser.print_help()
    sys.exit(1)
directory = opts.directory
if not directory:
    directory = '.'
try:                      # load the text file containing recipient1, recipient2, ....
    rec_file = open(opts.recipient_file)
    recipients = rec_file.read()
    rec_file.close()
except OSError:
    print "/!\ Bad file %s"%opts.recipient_file
    recipients = COMMASPACE.join(opts.recipients)
# Create the enclosing (outer) message
outer = MIMEMultipart()
outer['Subject'] = 'Malware submission'
outer['To'] = recipients
outer['From'] = opts.sender
outer.preamble = 'You will not see this in a MIME-aware mail reader.\n'
1

你可能想把这段代码:

# Variable to hold the recipients string
rec = ""
# Open recipients file
f = open(opts.recipients)
# Loop through each line of the file
for line in f:
    # Remove whitespace from line and add COMMASPACE
    rec += line.rstrip() + COMMASPACE
f.close()

换成这一行:

rec = ', '.join([line.strip() for line in file(opts.recipients) if line.strip()])
0

好的,我这边(或者更准确地说,是我的同事)解决了这个问题。代码如下,非常感谢Paul Littlefair提供的解决方案。

#!/usr/bin/env python

"""Send the contents of a directory as a MIME message."""

import os
import sys
import smtplib
# For guessing MIME type based on file name extension
import mimetypes

from optparse import OptionParser

from email import encoders
from email.message import Message
from email.mime.audio import MIMEAudio
from email.mime.base import MIMEBase
from email.mime.image import MIMEImage
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText

COMMASPACE = ', '


def main():
parser = OptionParser(usage="""\
Send the contents of a directory as a MIME message.

Usage: %prog [options]

Unless the -o option is given, the email is sent by forwarding to your local
SMTP server, which then does the normal delivery process. Your local machine
must be running an SMTP server.
""")
parser.add_option('-d','--directory',
type='string', action='store')
parser.add_option('-o', '--output',
type='string', action='store', metavar='FILE',
help="""Print the composed message to FILE instead of
sending the message to the SMTP server.""")
parser.add_option('-s', '--sender',
type='string', action='store', metavar='SENDER',
help='The value of the From: header (required)')
parser.add_option('-r', '--recipient',
type='string', action='append', metavar='RECIPIENT',
default=[], dest='recipients'),
parser.add_option('-f', '--recipientfile',
type='string', action='store', metavar='RECIPIENT_FILE',
dest='recipient_file', default="",
help='A To: header value (a file containing this)')

opts, args = parser.parse_args()
if not opts.sender or not (opts.recipient_file or opts.recipients):
    parser.print_help()
    sys.exit(1)
directory = opts.directory
if not directory:
    directory = '.'
# Create the enclosing (outer) message

try:
    rec_file = open(opts.recipient_file)
    recipients = rec_file.read()
    rec_file.close()
except IOError:
    print "/!\ Bad file. Falling back to recipent option"
    recipients = COMMASPACE.join(opts.recipients)

outer = MIMEMultipart()
outer['Subject'] = 'Malware submission'
outer['To'] = recipients
outer['From'] = opts.sender
outer.preamble = 'You will not see this in a MIME-aware mail reader.\n'

for filename in os.listdir(directory):
    path = os.path.join(directory, filename)
    if not os.path.isfile(path):
        continue
    # Guess the content type based on the file's extension. Encoding
    # will be ignored, although we should check for simple things like
    # gzip'd or compressed files.
    ctype, encoding = mimetypes.guess_type(path)
    if ctype is None or encoding is not None:
    # No guess could be made, or the file is encoded (compressed), so
    # use a generic bag-of-bits type.
        ctype = 'application/octet-stream'
        maintype, subtype = ctype.split('/', 1)
    if maintype == 'text':
        fp = open(path)
    # Note: we should handle calculating the charset
        msg = MIMEText(fp.read(), _subtype=subtype)
        fp.close()
    elif maintype == 'image':
        fp = open(path, 'rb')
        msg = MIMEImage(fp.read(), _subtype=subtype)
        fp.close()
    elif maintype == 'audio':
        fp = open(path, 'rb')
        msg = MIMEAudio(fp.read(), _subtype=subtype)
        fp.close()
    else:
        fp = open(path, 'rb')
        msg = MIMEBase(maintype, subtype)
        msg.set_payload(fp.read())
        fp.close()
    # Encode the payload using Base64
    encoders.encode_base64(msg)
# Set the filename parameter
msg.add_header('Content-Disposition', 'attachment', filename=filename)
outer.attach(msg)
# Now send or store the message
composed = outer.as_string()
if opts.output:
    fp = open(opts.output, 'w')
    fp.write(composed)
    fp.close()
else:
    s = smtplib.SMTP('localhost')
    s.sendmail(opts.sender, recipients, composed)
    s.quit()

if __name__ == '__main__':
main()

输入格式是 -d [目录] -s [发件地址] -f [收件人源文件]

撰写回答