]> code.delx.au - monosys/blob - mail/sendmail.py
Fixed the decorators import, so that sendmail.py still works on systems
[monosys] / mail / sendmail.py
1 #!/usr/bin/env python
2
3
4 import smtplib, email, urllib
5 import subprocess, sys, optparse
6 import logging
7
8 try:
9 # Attempt to load this debugging decorator function
10 from decorators import logCall
11 except ImportError:
12 def logCall(f):
13 '''This is a no-op decorator function'''
14 return f
15
16 #### USER CONFIG #####
17 def getUserConfig():
18 smtpServers = (
19 SMTPProxy(remoteServer='mail.internode.on.net', domainSuffix='.internode.on.net'),
20 SMTPProxy(remoteServer='smtp.usyd.edu.au', domainSuffix='.usyd.edu.au'),
21 SMTPProxy(remoteServer='mail.iinet.net.au', domainSuffix='.iinet.net.au'),
22 SMTPProxy(remoteServer='mail.netspace.net.au', domainSuffix='.netspace.net.au'),
23 SMTPProxy(remoteServer='mail.optusnet.com.au', domainSuffix='.optusnet.com.au'),
24 SMTPProxySSH(remoteServer='kagami.tsukasa.net.au'), # Fall back to sending the email via ssh if nothing else
25 )
26
27 return smtpServers
28
29 #### REAL CODE STARTS HERE ####
30
31 class SMTPProxyBase(object):
32 def __repr__(self):
33 return '%s(%s)' % (self.__class__.__name__,
34 ', '.join('%s=%r' % (k, getattr(self, k)) for k in self.__slots__)
35 )
36
37 class SMTPProxy(SMTPProxyBase):
38 __slots__ = (
39 'remoteServer',
40 'domainSuffix',
41 'username',
42 'password',
43 'useSSL',
44 )
45 @logCall
46 def __init__(self, remoteServer, domainSuffix, username=None, password=None, useSSL=False):
47 self.remoteServer = remoteServer
48 self.domainSuffix = domainSuffix
49
50 self.username = username
51 self.password = password
52 self.useSSL = useSSL
53
54 def doesHandle(self, localhostName):
55 '''Determines if this SMTPProxy can be used within this domain'''
56 if localhostName is None:
57 return False
58 else:
59 return localhostName.endswith(self.domainSuffix)
60
61 def sendmail(self, fromAddr, toAddrs, message):
62 '''
63 Actually send the mail.
64
65 Returns true if the mail was successfully send
66 '''
67
68 smtp = smtplib.SMTP(self.remoteServer)
69 if self.useSSL:
70 smtp.starttls()
71 if self.username is not None and self.password is not None:
72 smtp.login(self.username, self.password)
73 smtp.sendmail(fromAddr, toAddrs, message)
74 smtp.quit()
75 return True
76
77 class SMTPProxySSH(SMTPProxyBase):
78 __slots__ = ('remoteServer',)
79 @logCall
80 def __init__(self, remoteServer):
81 self.remoteServer = remoteServer
82
83 def doesHandle(self, *args, **kwargs):
84 '''
85 Determines if this SMTPProxySSH can be used within this domain.
86 Note: This method returns true for all values.
87 '''
88 return True
89
90 def sendmail(self, fromAddr, toAddrs, message):
91 '''
92 Actually send the mail.
93
94 Returns true if the mail was successfully send
95 '''
96 cmdline = ['ssh', self.remoteServer, '/usr/sbin/sendmail', '--']
97 cmdline.extend(toAddrs)
98 process = subprocess.Popen(cmdline, stdin=subprocess.PIPE)
99 process.communicate(message)
100 return not bool(process.wait())
101
102 def getOptionParser():
103 parser = optparse.OptionParser(usage="%prog [options] toAddress1 [toAddress2] ...")
104 parser.add_option('--debug',
105 action='store_const', dest='debugLevel', const=logging.DEBUG,
106 help='Sets the logging level to debug')
107 parser.add_option('--warn',
108 action='store_const', dest='debugLevel', const=logging.WARNING,
109 help='Sets the logging level to warn')
110 parser.set_default('debugLevel', logging.ERROR)
111
112 return parser
113
114 def main():
115 # Get the to addresses
116 parser = getOptionParser()
117 options, toAddrs = parser.parse_args()
118 logging.basicConfig(level=options.debugLevel)
119 if not toAddrs:
120 parser.error('No to addresses found')
121
122 # Pick a SMTP server
123 try:
124 host = urllib.urlopen("http://suits.ug.it.usyd.edu.au/myip.php").read().strip()
125 except:
126 host = None
127 logging.exception('Failed to grab our external domain name')
128
129 for smtpProxy in getUserConfig():
130 if smtpProxy.doesHandle(host):
131 # Got the correct smtpServer
132 logging.info('Using the Proxy %r to connect from %s', smtpProxy, host)
133 break
134 else:
135 logging.error('Did not find a proxy to connect from %s', host)
136 return False
137
138 # Get the from address
139 message = sys.stdin.read()
140 fromAddr = email.message_from_string(message)["from"]
141 _, fromAddr = email.utils.parseaddr(fromAddr)
142
143 return smtpProxy.sendmail(fromAddr, toAddrs, message)
144
145 if __name__ == "__main__":
146 # Specify SMTP servers here
147 sys.exit(not main())