Title: Python Milter FAQ
A. Even though libmilter is officially supported in sendmail-8.12, you need to build and install it in separate steps. Take a look at the RPM spec file for sendmail-8.12. The %prep section shows you how to create a site.config.m4 that enables MILTER. The %build section shows you how to build libmilter in a separate invocation of make. The %install section shows you how to install libmilter with a separate invocation of make.
A. RedHat forgot to include the header in the RPM. See the RedHat 7.2 requirements.
ImportError: /usr/lib/python2.4/site-packages/milter.so: undefined symbol: smfi_setmlreply
A. Your libmilter.a is from sendmail-8.12 or earlier. You need sendmail-8.13 or later to support setmlreply. You can disable setmlreply by changing setup.py. Change:
define_macros = [ ('MAX_ML_REPLY',32) ]
in setup.py to
define_macros = [ ('MAX_ML_REPLY',1) ]
To use this with sendmail, add the following to sendmail.cf: O InputMailFilters=pythonfilter Xpythonfilter, S=local:inet:1030@localhost See the sendmail README for libmilter. sample milter startup
A. You need to tell sendmail to connect to your milter. The sample milter tells you what to add to your sendmail.cf to tell sendmail to use the milter. You can also add an INPUT_MAIL_FILTER macro to your sendmail.mc file and rebuild sendmail.cf - see the sendmail README for milters.
A. Sendmail only milters SMTP mail. Local mail is not miltered. You can pipe a raw message through sendmail to test your milter:
$ cat rawtextmsg | sendmail myname@my.full.domainNow check your milter log.
File "mime.py", line 370, in ?
from sgmllib import declstringlit, declname
ImportError: cannot import name declstringlit
A. declstringlit is not provided by sgmllib in all versions
of python. For instance, python-2.2 does not have it. Upgrade to
milter-0.4.5 or later to remove this dependency.
milter.error: cannot add recipient?
A. You must tell libmilter how you might mutate the message with
set_flags() before calling runmilter(). For
instance, Milter.set_flags(Milter.ADDRCPT). You must add together
all of ADDHDRS, CHGBODY, ADDRCPT, DELRCPT, CHGHDRS that apply.
NOTE - recent versions default flags to enabling all features. You
must now call set_flags() if you wish to disable features for
efficiency.
A. Libmilter expects "rcpt to" shortly after getting "mail from".
"Shortly" is defined by the timeout parameter you passed to
Milter.runmilter()
or milter.settimeout(). If the timeout is 10 seconds,
and looking up the first recipient in DNS takes more than
10 seconds, libmilter will give up and break the connection.
Milter.runmilter() defaulted to 10 seconds in 0.3.4. In 0.3.5
it will keep the libmilter default of 2 hours.
A. sample.py is a sample. It is supposed to be easily modified for your specific needs. We will of course continue to move generic code out of the sample as the project evolves. Think of sample.py as an active config file.
If you are running bms.py, then the block_chinese option in
/etc/mail/pymilter.cfg controls this feature.
A. Sendmail has a problem with unix sockets on old versions of OpenBSD.
OpenBSD users report that this problem has been fixed, so upgrading
OpenBSD will fix this. Otherwise, you can
use an internet domain socket instead. For example, in
sendmail.cf use
Xpythonfilter, S=inet:1234@localhostand change sample.py accordingly.
A. Configure sendmail to use virtusertable, and send all unknown addresses to /dev/null. For example,
@mycorp.com dev-null dan@mycorp.com dan sally@mycorp.com sally
dev-null: /dev/nullNow your milter will get to the eom callback, and can change the envelope recipient at will. Thanks to Dredd at milter.org for this solution.
A. Check the sendmail log for errors. If sendmail is getting milter timeouts, then your milter is taking too long and sendmail gave up waiting. You can adjust the timeouts in your sendmail config. Here is a milter declaration for sendmail.cf with all timeouts specified:
Xpythonfilter, S=local:/var/log/milter/pythonsock, F=T, T=C:5m;S:20s;R:60s;E:5m
A. By default, when the milter fails with an untrapped exception, a
TEMPFAIL result (451) is returned to the sender. The sender will then retry
every hour or so for several days. Hopefully, someone will notice the
traceback, and workaround or fix the problem. Beginning with milter-0.8.2,
you can call milter.set_exception_policy(milter.CONTINUE)
to cause an untrapped exception to continue processing with the
next callback or milter instead. For
completeness, you can also set the exception policy to
milter.REJECT.
A. The internal_domains configuration specifies which
MAIL FROM domains are used by internal connections. If an internal
PC tries to use some other domain, it is assumed to be a "Zombie".
Here is a sample log line:
2005Jun22 12:01:04 [12430] REJECT: zombie PC at 192.168.100.171 sending MAIL FROM debby@fedex.comNo, fedex.com does not use pymilter, and there is no one named debby at my client. But the idiot using the PC at 192.168.100.171 has downloaded and installed some stupid weatherbar/hotbar/aquariumscreensaver that is actually a spam bot.
The internal_domains option is simplistic, it assumes all
valid senders of the domains are internal. SPF provides a much more general
check of IP and MAIL FROM for external email. Pymilter should soon
have a local policy feature for more general checking of internal mail.
mail_archive isn't working. Or I don't understand how
it's suppose to work. I have
mail_archive = /var/mail/mail_archive
in pymilter.cfg but nothing ever gets dumped into
/var/mail/mail_archive.
A. The 'mail' user needs to have write access. Permission failures should be logged as a traceback in milter.log if it doesn't.
A. The bms.py milter supports spf. The RedHat RPMs will set almost everything up for you. For other systems:
tempdir. The RedHat RPM uses logrotate for
logfiles and a simple cron script using find to clean
tempdir.
spfmilter.py. Run that as a service,
and it does just SPF. It uses the sendmail access
file to configure SPF responses just like bms.py, but
supports only REJECT and OK.
A. The SPF response is controlled by /etc/mail/access
(actually the file you specify with access_file in
the [spf] section of pymilter.cfg. Responses
are OK, CBV, and REJECT. CBV sends the DSN.
You can change the defaults. For instance, I have:
SPF-None: REJECT SPF-Neutral: CBV SPF-Softfail: CBV SPF-Permerror: CBVI have best_guess = 1, so SPF none is converted to PASS/NEUTRAL for policy lookup, and 3 strikes (no PTR, no HELO, no SPF) becomes "SPF NONE" for local policy purposes (the Received-SPF header always shows the official SPF result.)
You can change the default for specific domains:
# these guys aren't going to pay attention to CBVs anyway... SPF-None:cia.gov REJECT SPF-None:fbi.gov REJECT SPF-Neutral:aol.com REJECT SPF-Softfail:ebay.com REJECT
/etc/init.d/pysrs, I get this in
/var/log/milter/pysrs.log:
ConfigParser.NoOptionError: No option 'fwdomain' in section: 'srs'
A. You need to specify the forward domain - i.e. the domain you want SRS to rewrite stuff too.
For instance, I have:
# sample SRS configuration [srs] secret = don't you wish maxage = 8 hashlength = 5 ;database=/var/log/milter/srs.db fwdomain = bmsi.com sign=bmsi.com,mail.bmsi.com,gathman.org srs=bmsaix.bmsi.com,bmsred.bmsi.com,stl.gathman.org,bampa.gathman.orgThe
sign is for local domains which are signed.
The srs list is for other domains which you are relaying,
and which need to have SRS checked/undone for bounces.