|
1 #!/usr/bin/env python |
|
2 |
|
3 """Send the contents of a directory as a MIME message.""" |
|
4 |
|
5 import os |
|
6 import sys |
|
7 import smtplib |
|
8 # For guessing MIME type based on file name extension |
|
9 import mimetypes |
|
10 |
|
11 from optparse import OptionParser |
|
12 |
|
13 from email import encoders |
|
14 from email.message import Message |
|
15 from email.mime.audio import MIMEAudio |
|
16 from email.mime.base import MIMEBase |
|
17 from email.mime.image import MIMEImage |
|
18 from email.mime.multipart import MIMEMultipart |
|
19 from email.mime.text import MIMEText |
|
20 |
|
21 COMMASPACE = ', ' |
|
22 |
|
23 |
|
24 def main(): |
|
25 parser = OptionParser(usage="""\ |
|
26 Send the contents of a directory as a MIME message. |
|
27 |
|
28 Usage: %prog [options] |
|
29 |
|
30 Unless the -o option is given, the email is sent by forwarding to your local |
|
31 SMTP server, which then does the normal delivery process. Your local machine |
|
32 must be running an SMTP server. |
|
33 """) |
|
34 parser.add_option('-d', '--directory', |
|
35 type='string', action='store', |
|
36 help="""Mail the contents of the specified directory, |
|
37 otherwise use the current directory. Only the regular |
|
38 files in the directory are sent, and we don't recurse to |
|
39 subdirectories.""") |
|
40 parser.add_option('-o', '--output', |
|
41 type='string', action='store', metavar='FILE', |
|
42 help="""Print the composed message to FILE instead of |
|
43 sending the message to the SMTP server.""") |
|
44 parser.add_option('-s', '--sender', |
|
45 type='string', action='store', metavar='SENDER', |
|
46 help='The value of the From: header (required)') |
|
47 parser.add_option('-r', '--recipient', |
|
48 type='string', action='append', metavar='RECIPIENT', |
|
49 default=[], dest='recipients', |
|
50 help='A To: header value (at least one required)') |
|
51 opts, args = parser.parse_args() |
|
52 if not opts.sender or not opts.recipients: |
|
53 parser.print_help() |
|
54 sys.exit(1) |
|
55 directory = opts.directory |
|
56 if not directory: |
|
57 directory = '.' |
|
58 # Create the enclosing (outer) message |
|
59 outer = MIMEMultipart() |
|
60 outer['Subject'] = 'Contents of directory %s' % os.path.abspath(directory) |
|
61 outer['To'] = COMMASPACE.join(opts.recipients) |
|
62 outer['From'] = opts.sender |
|
63 outer.preamble = 'You will not see this in a MIME-aware mail reader.\n' |
|
64 |
|
65 for filename in os.listdir(directory): |
|
66 path = os.path.join(directory, filename) |
|
67 if not os.path.isfile(path): |
|
68 continue |
|
69 # Guess the content type based on the file's extension. Encoding |
|
70 # will be ignored, although we should check for simple things like |
|
71 # gzip'd or compressed files. |
|
72 ctype, encoding = mimetypes.guess_type(path) |
|
73 if ctype is None or encoding is not None: |
|
74 # No guess could be made, or the file is encoded (compressed), so |
|
75 # use a generic bag-of-bits type. |
|
76 ctype = 'application/octet-stream' |
|
77 maintype, subtype = ctype.split('/', 1) |
|
78 if maintype == 'text': |
|
79 fp = open(path) |
|
80 # Note: we should handle calculating the charset |
|
81 msg = MIMEText(fp.read(), _subtype=subtype) |
|
82 fp.close() |
|
83 elif maintype == 'image': |
|
84 fp = open(path, 'rb') |
|
85 msg = MIMEImage(fp.read(), _subtype=subtype) |
|
86 fp.close() |
|
87 elif maintype == 'audio': |
|
88 fp = open(path, 'rb') |
|
89 msg = MIMEAudio(fp.read(), _subtype=subtype) |
|
90 fp.close() |
|
91 else: |
|
92 fp = open(path, 'rb') |
|
93 msg = MIMEBase(maintype, subtype) |
|
94 msg.set_payload(fp.read()) |
|
95 fp.close() |
|
96 # Encode the payload using Base64 |
|
97 encoders.encode_base64(msg) |
|
98 # Set the filename parameter |
|
99 msg.add_header('Content-Disposition', 'attachment', filename=filename) |
|
100 outer.attach(msg) |
|
101 # Now send or store the message |
|
102 composed = outer.as_string() |
|
103 if opts.output: |
|
104 fp = open(opts.output, 'w') |
|
105 fp.write(composed) |
|
106 fp.close() |
|
107 else: |
|
108 s = smtplib.SMTP() |
|
109 s.connect() |
|
110 s.sendmail(opts.sender, opts.recipients, composed) |
|
111 s.close() |
|
112 |
|
113 |
|
114 if __name__ == '__main__': |
|
115 main() |