#!/usr/bin/env python3 from email import message, message_from_binary_file, policy from email.generator import BytesGenerator from inspect import getsourcefile from os.path import abspath, dirname, exists, join, realpath import re from subprocess import Popen, PIPE from sys import argv, stdin # Hack to determine the directory this script resides in, # regardless of symlinks or other weirdness. basedir = dirname(realpath(abspath(getsourcefile(lambda:0)))) # Set a sane email policy. mypolicy = policy.default # Read the incoming message. inmsg = message_from_binary_file(stdin.buffer, policy=mypolicy) # Bail if the incoming message was automatically generated auto = inmsg['Auto-Submitted'] if auto and auto.lower() != 'no': exit() # Build the outgoing reply. msg = message.EmailMessage(policy=mypolicy) ## Basic headers. msg['To'] = inmsg['From'] msg['From'] = inmsg['To'] ## Only add "re" to the subject if it's not already there. if inmsg['Subject'].startswith(('re: ', 'Re: ', 'Re ', 're ')): msg['Subject'] = inmsg['Subject'] else: msg['Subject'] = 'Re: ' + inmsg['Subject'] ## Set up correct threading identifiers. if inmsg['Message-ID']: msg['In-Reply-To'] = inmsg['Message-ID'] if inmsg['References']: msg['References'] = inmsg['References'] +' '+ inmsg.get('Message-ID', '') elif inmsg['In-Reply-To'] or inmsg['Message-ID']: msg['References'] = inmsg.get('In-Reply-To', '') +' '+ inmsg.get('Message-ID', '') ## Add loop avoidance header (RFC3834) msg['Auto-Submitted'] = 'auto-generated' ## Also add the exchange-specific anti-loop header ## https://docs.microsoft.com/en-us/openspecs/exchange_server_protocols/ms-oxcmail/ced68690-498a-4567-9d14-5c01f974d8b1 msg['X-Auto-Response-Suppress'] = 'All' ## Set the template directory. templatedir = join(basedir, 'templates') ## Pick an autoreply template. ### Start with a sane default. mytemplate = 'default' ### Try a template based on the recipient address. #### Extract the address part from the To: header. #### The regex handles: "name"
#### #### address@domain matches = re.match(r'("[^"]+" +)?([^>]+)>?', inmsg['To']) address = matches.group(2) #### If there was a match, use the name part to look for a template and use #### it if it exists. if address: trytemplate = address.split('@')[0] if exists(join(templatedir, trytemplate)): mytemplate = trytemplate ### If a template was specified on the commandline, use that instead. ### Will cause an error if the template doesn't exist. This is intentional. if len(argv) > 1: mytemplate = argv[1] ## Set response body. with open(join(templatedir, mytemplate)) as f: msg.set_content(f.read()) ## Include the original email msg.add_related(inmsg) ## Include html version if one exists htmlpath = join(templatedir, mytemplate + '.html') if exists(htmlpath): with open(htmlpath) as f: msg.add_alternative(f.read(), subtype='html') # Post the reply p = Popen(['/usr/sbin/sendmail', '-t'], stdin=PIPE) g = BytesGenerator(p.stdin, policy=msg.policy.clone(linesep='\r\n')) g.flatten(msg) p.stdin.close() p.wait()