ETRN client utility
This is a small utility that uses Python's SMTP module to send RFC1985 ETRN requests to one or more mail servers. This would normally be used to tell the backup mail servers for a domain to attempt delivery after the primary MX comes back online.
I wrote it, because after much searching, the best I could find were scripts using telnet or nc, and with no error handling. This program should speak SMTP correctly, and will return error codes and messages in the case of failure.
1 #!/usr/bin/python
2
3 # Andrew Baumann <andrewb@cse.unsw.edu.au>, 2007/04/29
4
5 import sys, smtplib, socket
6 from optparse import OptionParser
7
8 def parse_args():
9 mydomain = socket.getfqdn()
10 p = OptionParser(usage='%prog [option] host...',
11 description="sends an ETRN request (RFC1985) to one or more mail servers")
12 p.add_option('-d', dest='domain',
13 help='domain to request mail for, default: %s' % mydomain)
14 p.add_option('-v', action='store_const', dest='verbose', const=True,
15 help='verbose/debug output')
16 p.set_defaults(domain=mydomain, verbose=False)
17 options, args = p.parse_args()
18 if len(args) == 0:
19 p.error('no host specified')
20 return options, args
21
22 def do_etrn(host, domain, smtpobj=None):
23 if smtpobj is None:
24 smtpobj = smtplib.SMTP()
25 smtpobj.connect(host)
26 smtpobj.ehlo()
27 (retcode, retmsg) = smtpobj.docmd('ETRN', domain)
28 if retcode / 10 != 25:
29 raise smtplib.SMTPResponseException(retcode, retmsg)
30 smtpobj.quit()
31
32 def main():
33 options, hosts = parse_args()
34 errorflag = False
35 smtpobj = smtplib.SMTP()
36 smtpobj.set_debuglevel(options.verbose)
37
38 for host in hosts:
39 def error(msg):
40 sys.stderr.write('Error: %s: %s\n' % (host, msg))
41
42 try:
43 do_etrn(host, options.domain, smtpobj)
44 except socket.error, (errnum, errmsg):
45 error(errmsg)
46 errorflag = True
47 except smtplib.SMTPResponseException, e:
48 error('%d %s' % (e.smtp_code, e.smtp_error))
49 errorflag = True
50 except smtplib.SMTPException:
51 error('Generic SMTP error')
52 errorflag = True
53
54 return errorflag
55
56 if __name__ == "__main__":
57 if main():
58 sys.exit(1)
59