Requeuing failed messages

Mark Sapiro mark at msapiro.net
Wed Jan 4 00:09:09 UTC 2017


On 01/02/2017 05:05 PM, Mark Sapiro wrote:
> 
> On second thought, the above sendmail command is probably not a good
> idea. The issue is that -t will send the message to all To: and Cc:
> recipients in the message headers. This can include addresses which are
> in other domains and which probably already received the message and may
> not even include the intended recipient of the quarantined message
> (e.g., a Bcc:).
> 
> It is better to do
> 
> sendmail -i user at example.com < quarantined_message_file
> 
> where user at example.com is the intended local recipient. Note that if the
> MTA is Postfix, the quarantined message will have a topmost Received:
> header of the form
> 
> Received: from some server ...
> 	by your server ...
> 	for <user at example.com> ...
> 
> that will expose the recipient address.
> 


On third thought, there will be issues with even the above because
Postfix will have put a Delivered-To: header in the message so
re-injecting it will result in it being rejected for a mail loop.

I wrote a little Python 3 script to address this. It is attached. You
can run it with the path to the saved message as the argument and it
will read and parse the message, look for " for <user at example.com>;" in
the Received: headers, delete any Delivered-To: headers and pipe the
message to sendmail for user at example.com.

If necessary, it could be fairly easily converted to Python 2.

-- 
Mark Sapiro <mark at msapiro.net>        The highway is for gamblers,
San Francisco Bay Area, California    better use your sense - B. Dylan


-------------- next part --------------
#! /usr/bin/python3
"""Read a file containing an email message and the name of which is the
command argument. Find the recipient in a Received: header and pipe the
message to sendmail to resend it to the recipient.
"""
import os
import re
import sys
import email
import subprocess

def main():
    if len(sys.argv) != 2:
        print(
            'usage: {} input_file'.format(os.path.basename(sys.argv[0])),
            file=sys.stderr)
        sys.exit(1)
    try:
        fp = open(sys.argv[1], 'rb')
    except IOError as e:
        print(
            "Can't open {}: {}".format(sys.argv[1], e),
            file=sys.stderr)
        sys.exit(2)
    msg = email.message_from_binary_file(fp)
    for h in msg.get_all('received', []):
        mo = re.search('\sfor <([^>]*)>;', h)
        if mo:
            break
    if not mo:
        print("Can't find recipient in message.", file=sys.stderr)
        sys.exit(3)
    del msg['delivered-to']
    try:
        p = subprocess.Popen(
            ['sendmail', '-i', mo.group(1)],
            stdin=subprocess.PIPE,
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE
            )
    except OSError as e:
        print('error: {}'.format(e), file=sys.stderr)
        sys.exit(2)
    so, se = p.communicate(msg.as_bytes())
    if p.returncode:
        print('error: status={}: {}'.format(p.returncode, se), file=sys.stderr)
        sys.exit(3)
    if len(so) > 0:
        print(so)

if __name__ == '__main__':
    main()




More information about the MailScanner mailing list