[This mail is intentionally hand wrapped..]

On Freitag, 10. Juni 2016 17:54:34 Hans-Peter Jansen wrote:
> On Donnerstag, 9. Juni 2016 18:37:54 Hans-Peter Jansen wrote:
> > 
> > Let's see, how this goes.
> 
> Hmm, compat32 and Python3 start to get in my way in no funny ways.

Okay, got it working now. It turned out to be a problem in the logging module. 
Unfortunately, it's not reproducible outside postfix mail filter setup.
        
        http://www.postfix.org/FILTER_README.html

I will try to explain this in short words, but you will not believe me, as I 
have a hard time to believe this myself..

When a python3 process is used in a simple mail filter setup, as described in 
the FILTER_README.html document, it is executed in a stripped down environment. 
As relevant parts, just LANG=C and PATH=/bin;/usr/bin is set.

The filter reads the mail from stdin, and calls sendmail for passing it on, 
again, with the mail on stdin..

Now, it takes a mail with some "higher" encoding (I'm using a utf-8 encoded 
subject containing german umlauts), and an attempt to log the subject line 
(which has to be a log file for obvious reasons). Now take a save seat, this 
attempt of unicode logging results in a manipulation of the execution frame, 
the execution precedes a few instructions "below". Yes, I'm not kidding, no 
escaped surrogates output, no error message, just no logging of the offending 
line, and this "esoteric" behavior. Be assured, that if I would still have 
enough hair on my head, I would have teared it off completely by now.

This is reproducible for Python 3.4.4 on openSUSE 13.2/x86_64 here. 

For the brave, who want to reproduce/investigate this issue, I'm attaching 
everything necessary. All others should stop reading now. Thank you.

Still with me, here we go: [$: root prompt]

A working postfix setup is implied. Stop all usual processing (fetchmail, ...)

$ useradd --gid mail mfilter
$ cat >> /etc/postfix/master.cf << EOF
mfilter   unix  -       n       n       -       1       pipe
  flags=Rq user=mfilter argv=/path/to/mail_filter_test.py -f ${sender} -- 
${recipient}
EOF

$ systemctl restart postfix
$ sendmail -f your@email.address your@email.address < umlaut-subject-2.mail
$ less +F /tmp/mail_filter_test.log

Defective output:
2016-06-12 15:36:28,540 [mail_filter_test] DEBUG: parse message
2016-06-12 15:36:28,543 [mail_filter_test] DEBUG: call ['/usr/sbin/sendmail', 
'-G', '-i', '-f', 'your@email.address', '--', 'your@email.address']

Output with SILLY_BEHAVIOR = 0:
2016-06-12 15:37:50,887 [mail_filter_test] DEBUG: parse message
2016-06-12 15:37:50,889 [mail_filter_test] DEBUG: subject: Wie deaktiviere oder 
lösche ich meine SprachBox IP der Telekom?
2016-06-12 15:37:50,890 [mail_filter_test] DEBUG: call ['/usr/sbin/sendmail', 
'-G', '-i', '-f', 'your@email.address', '--', 'your@email.address']

Note, that the subject line is missing. In my real filter, it left the 
current execution frame, and execution continued one or two level up the
stack.

This reminds me at my assembler times (680x0 power, long ago!), where I used
such tricks like modifying the program counter in "very special arrangements".

I don't think, this is an adequate outcome of the attached code, do you?

I'm directing this here, while I know, this is quite off-topic in the result.
OTOH, Stephen and David discussed the LANG=C issues with Victor, and this 
is one example, where this is very relevant to Python3 fitness to act as 
such a filter. Apart from fixing the logging, I'm encoding all paths and file 
names with a configurable encoding before calling the OS. Butt ugly, but 
feasible.

I hope, that at least one of you is able to reproduce this, before we decide,
how to precede. I hope, I don't offend anybody here with that approach.

Please speak up, if I should go away and search for another tree to bark at.

Thanks,
Pete
#!/usr/bin/env python3

import sys
import getopt
import logging
import subprocess

import email
import email.policy
import email.header
import email.generator

logfile = '/tmp/mail_filter_test.log'
logformat = '%(asctime)s [%(name)s] %(levelname)5s: %(message)s'
encoding = 'utf-8'

# setup logging
log = logging.getLogger('mail_filter_test')

EX_TEMPFAIL = 75        # queue and retry
SILLY_BEHAVIOR = 1

if SILLY_BEHAVIOR:
    logging.basicConfig(
        level = logging.DEBUG,
        format = logformat,
        filename = logfile,
    )
else:
    log.setLevel(logging.DEBUG)
    filelog = logging.FileHandler(logfile, encoding = encoding)
    filelog.setLevel(logging.DEBUG)
    filelog.setFormatter(logging.Formatter(logformat))
    log.addHandler(filelog)


def decode_header(value):
    if value is not None:
        value = str(email.header.make_header(email.header.decode_header(value)))
    return value


def mail_filter(sender, recipients):
    log.debug('parse message')
    msg = email.message_from_binary_file(sys.stdin.buffer, policy = email.policy.compat32)
    if not sender:
        sender = msg.get('from')
    if not recipients:
        recipients = msg.get_all('to')
    subject = decode_header(msg.get('subject'))
    log.debug('subject: %s', subject)
    sendmail = ['/usr/sbin/sendmail', '-G', '-i', '-f', sender, '--'] + recipients
    log.debug('call %s', sendmail)
    p = subprocess.Popen(sendmail, stdin = subprocess.PIPE)
    email.generator.BytesGenerator(p.stdin).flatten(msg)
    p.stdin.close()
    return p.wait()


if __name__ == '__main__':
    try:
        optlist, recipients = getopt.getopt(sys.argv[1:], 'f:')
    except getopt.error as msg:
        print(msg, file = sys.stderr, flush = True)
        sys.exit(EX_TEMPFAIL)

    sender = None
    for opt, par in optlist:
        if opt in ('-f', '--from'):
            sender = par

    sys.exit(mail_filter(sender, recipients))

https://www.telekom.de/hilfe/festnetz-internet-tv/telefonieren-einstellungen/sprachbox/sprachbox-ip/sprachbox-ip-deaktivieren-oder-loeschen?samChecked=true
_______________________________________________
Email-SIG mailing list
Email-SIG@python.org
Your options: 
https://mail.python.org/mailman/options/email-sig/archive%40mail-archive.com

Reply via email to