oops
[tests.git] / qaapi / qa / sendmail.py
1 import os
2 import sys
3 import pprint
4 from types import StringTypes
5 from email.MIMEText import MIMEText
6 from email.Header import Header
7 from smtplib import SMTP
8
9
10 def sendmail(To, Subject, Body, From = None, Cc = None, Bcc = None):
11     """
12     Uses sendmail (must be installed and running locally) to send a
13     message to the specified recipients. If the API is running under
14     mod_python, the apache user must be listed in e.g.,
15     /etc/mail/trusted-users.
16
17     To, Cc, and Bcc may be addresses or lists of addresses. Each
18     address may be either a plain text address or a tuple of (name,
19     address).
20     """
21
22     # Fix up defaults
23     if not isinstance(To, list):
24         To = [To]
25     if Cc is not None and not isinstance(Cc, list):
26         Cc = [Cc]
27     if Bcc is not None and not isinstance(Bcc, list):
28         Bcc = [Bcc]
29     if From is None:
30         From = ("Quality Assurance <qa@planet-lab.org>")
31
32     # Create a MIME-encoded UTF-8 message
33     msg = MIMEText(Body.encode("utf-8"), _charset = "utf-8")
34
35     # Unicode subject headers are automatically encoded correctly
36     msg['Subject'] = Subject
37
38     def encode_addresses(addresses, header_name = None):
39         """
40         Unicode address headers are automatically encoded by
41         email.Header, but not correctly. The correct way is to put the
42         textual name inside quotes and the address inside brackets:
43
44         To: "=?utf-8?b?encoded" <recipient@domain>
45
46         Each address in addrs may be a tuple of (name, address) or
47         just an address. Returns a tuple of (header, addrlist)
48         representing the encoded header text and the list of plain
49         text addresses.
50         """
51
52         header = []
53         addrs = []
54
55         for addr in addresses:
56             if isinstance(addr, tuple):
57                 (name, addr) = addr
58                 try:
59                     name = name.encode('ascii')
60                     header.append('%s <%s>' % (name, addr))
61                 except:
62                     h = Header(name, charset = "utf-8", header_name = header_name)
63                     header.append('"%s" <%s>' % (h.encode(), addr))
64             else:
65                 header.append(addr)
66             addrs.append(addr)
67
68         return (", ".join(header), addrs)
69
70     (msg['From'], from_addrs) = encode_addresses([From], 'From')
71     (msg['To'], to_addrs) = encode_addresses(To, 'To')
72
73     if Cc is not None:
74         (msg['Cc'], cc_addrs) = encode_addresses(Cc, 'Cc')
75         to_addrs += cc_addrs
76
77     if Bcc is not None:
78         (unused, bcc_addrs) = encode_addresses(Bcc, 'Bcc')
79         to_addrs += bcc_addrs
80
81     # Needed to pass some spam filters
82     msg['Reply-To'] = msg['From']
83     msg['X-Mailer'] = "Python/" + sys.version.split(" ")[0]
84
85     s = SMTP()
86     s.connect()
87     rejected = s.sendmail(from_addrs[0], to_addrs, msg.as_string(), rcpt_options = ["NOTIFY=NEVER"])
88     s.close()
89
90     if rejected:
91         raise Exception, "Error sending message to " + ", ".join(rejected.keys())