Well, I had an epiphany over the US Thanksgiving holiday weekend (or
maybe it was a brain aneurism) so I've spent some late nights and some
time stolen from work and come up with a first pass at embedding
Python in Exim.
I imagine that embedding Python in Exim will be interesting to those
folks writing virus scanners or for VERY tight integration of Mailman
with Exim. You can also do all of those things that you can do with
the Perl string expansions.
Note: this code is VERY lightly tested. It compiles on my home
hacked-up RedHat Linux system and works on a couple of simple tests
that I've done, but no real e-mails have passed through this code yet.
I'm tossing this out for public comment on the design and
implementation... It's been a while since I've done a lot of C
Unfortunately, you must embed Python 2.0. This is because previous
versions of Python used a hacked copy of PCRE as it's regular
expression engine that conflicts with the copy of PCRE in Exim.
Starting in Python 2.0 the default regular expression is a completely
new one called SRE that supports Unicode. The PCRE-based regular
expression engine is still included in Python 2.0 but I get around
that by creating a private copy of the Python library and delete the
offending object modules. You could do that in versions of Python
prior to 2.0 but a lot of the standard library depends on regular
expressions I didn't think that there was much point in trying to make
the embedding work with 1.5.2 or 1.6.
Well, on to the patch itself. The patch is made against Exim v3.20.
After you've patched the source code, you need to set four variables
in the Local/Makefile:
PYTHON_EXTRA_LIBS=-lpthread -ldl -lutil
Then build Exim as usual.
There are three runtime directives that control the embedding, all of which
python_at_start boolean - force startup of Python interpreter
python_module_paths colon separated list of paths to append to sys.path
python_initial_import colon separated list of modules to import at
interpreter initialization time
There are also two new command line switches -ys and -yd that will
force an immediate startup of Python or delay startup, overriding
Then you use it:
You must specify the module name and the function name. The named
module will be imported automatically. And currently you must specify
a function that returns a string (I'll look into adding accessing
attributes, methods of classes, and converting non-strings into
strings). There can be up to eight arguments. Each argument will be
expanded by Exim before it's passed to the Python interpreter.
Your python code has access to a module called "exim", which currently
defines two things:
exim.expand_string(s) which calls back to Exim to expand a string and
exim.error which is an exception object used by expand_string
One simple example:
Error reporting isn't the best right now, I'm going to look into
formatting exceptions and tracebacks for more meaningful error
Well, I think that's the gist of it. I'll work on patches to the
documentation when this thing becomes more stable. As I said before
I've only lightly tested this... beware!
Comments, criticisms, suggestions, flames welcome...