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