diff --git a/doc/Maxwells.gif b/doc/Maxwells.gif deleted file mode 100644 index 3175fe9..0000000 Binary files a/doc/Maxwells.gif and /dev/null differ diff --git a/doc/SPF.gif b/doc/SPF.gif deleted file mode 100644 index 8810647..0000000 Binary files a/doc/SPF.gif and /dev/null differ diff --git a/doc/changes.ht b/doc/changes.ht deleted file mode 100644 index 719d09b..0000000 --- a/doc/changes.ht +++ /dev/null @@ -1,222 +0,0 @@ -Title: Recent Changes - -

Recent Changes

- -

0.8.10

- -SRS rejections now log the recipient. -I have finally implemented plain CBV (no DSN). The CBV policy -will do a plain CBV from now on, and the DSN policy is required -if you want to send a DSN. -I started checking the MAIL FROM fullname (human readable part -of an email) for porn keywords. There is now a banned IP database. -IPs are banned for too many bad MAIL FROMs or RCPT TOs, and remain banned -for 7 days. - -

0.8.9

- -I use the %ifarch hack to build milter and milter-spf -packages as noarch, while pymilter is built as native. - -I removed the spf dependency from dsn.py, so pymilter can be used without -installing pyspf, and added a Milter.dns module to let python milters do -general DNS lookups without loading pyspf. - -

0.8.8

- -Programs do not belong in the /var/log directory. I moved the -milter apps to /usr/lib/pymilter. Since having the programs and -data in the same directory is convenient for debugging, it will -still use an executable present in the datadir. - -Several general utility classes and functions are now in the Milter package -for possible use by other python milters. In addition to the trivial example -milter, a simple SPF only milter is included as a realistic example. - -The spec file now build 3 RPMs: - - - -

0.8.7

- -The spf module has been moved to the -pyspf package. -Download here. - -

0.8.6

- -Python milter has been moved to -pymilter Sourceforge -project for development and release downloads. - -

0.8.5

- -Release 0.8.5 fixes some build bugs reported by Stephen Figgins. It -fixes many small things, like not auto-whitelisting recipients of -outgoing mail when the subject contains "autoreply:". There is a -simple trusted forwarder implementation. If you have more than -2 or so forwarders, we will need a way to "compile" SPF records into an -IP set and TTL for it to be efficient (like libspf2 does). - -

GOSSiP

-An alpha release of pygossip has been commited to -CVS, module pygossip. A version of the bms.py milter has been commited to CVS -which supports calling GOSSiP to track domain reputation in a local database. - -

New website design

- -Hey, I'm no artist, so I just used the -ht2html package -by Barry Warsaw. The mascot -is by Christian Hafner, -or maybe his wife. I chose Maxwell's daemon because it tirelessly -and invisibly sorts molecules, just as milters sort mail. -Christian has also provided a fun - -simulation that lets you try your hand at sorting molecules. - -

0.8.4

- -Release 0.8.4 makes configuring SPF policy via access.db actually work. -The honeypot idea is enhanced by auto-whitelisting recipients of -email sent from selected domains. Whitelisted messages are then used -to train the honeypot. This makes the honeypot screener entirely self -training. The smfi_progress() API is now automatically supported when present. -An optional idx parameter to milter.addheader() invokes smfi_insheader(). - -

0.8.3

- -Release 0.8.3 uses the standard logging module, and supports configuring -more detailed SPF policy via the sendmail access map. SMTP AUTH connections -are considered INTERNAL. Preventing forgery between internal domains is -just a matter of specifying the user-domain map - I'll define something -for the next version. We now send DSNs when mail is quarantined (rejecting -if DSN fails) and for SPF syntax errors (PermError). There is an -experimental option to add a Sender header when it is missing and the From -domain doesn't match the MAIL FROM domain. Next release, we may start -renaming and replacing an existing Sender header when neither it nor the -From domain matches MAIL FROM. Since bogus MAIL FROMs are rejected -(to varying degrees depending on the configured SPF policy), and -both Sender and From and displayed by default in many email clients, -this provides some phishing protection without rejecting mail based -on headers. - -

0.8.2

- -Release 0.8.2 has changes to SPF to bring it -in line with the newly official RFC. It adds -SES -support (the original SES without body hash) for pysrs-0.30.10, and honeypot -support for pydspam-1.1.9. There is a new method in the base milter module. -milter.set_exception_policy(i) lets you choose a policy of CONTINUE, REJECT, or -TEMPFAIL (default) for untrapped exceptions encountered in a milter callback. - -

0.8.0

- -Release 0.8.0 is the first Sourceforge -release. It supports Python-2.4, and provides an option to accept mail -that gets an SPF softfail or fails the 3 strikes rule, provided the -alleged sender accepts a DSN explaining the problem. Python-2.3 is -no longer supported by the reworked mime.py module, although API changes -could be backported. There are too many incompatible changes to the -python email package. - -

Older Releases

- -Release 0.7.2 tightens the authentication screws with a "3 strikes and -you're out" policy. A sender must have a valid PTR, HELO, or SPF record -to send email. Specific senders can be whitelisted using the -"delegate" option in the spf configuration section by adding a -default SPF record for them. The PTR and HELO are required -by RFC anyway, so this is not an unreasonable requirement. -There is now a coherent policy for an SPF softfail result. A softfail -is accepted if there is a valid PTR or HELO, or if the domain -is listed in the "accept_softfail" option of the spf configuration section. -A neutral result is accepted by default if there is a valid PTR or -HELO, (and the SPF record was not guessed), unless the domain is listed in the -"reject_neutral" option. Common forms of PTR records for dynamic IPs are -recognized, and do not count as a valid PTR. This does not prevent anyone -from sending mail from a dynamic IP - they just need to configure a -valid HELO name or publish an SPF record. -

-As SPF adoption continues to rise, forged spam is not getting through. So -spammers are publishing their SPF records as predicted. The 0.7.2 RPM -now provides the rhsbl sendmail hack so that spammer domains -can be blacklisted. With the RPM installed, add a line like the following -to your sendmail.mc. -

-HACK(rhsbl,`blackholes.example.com',"550 Rejected: " $&{RHS} " has been spamming our customers.")dnl
-
-

-Of course, spammers are now starting to register -throwaway domains. The next thing we need is a custom DNS server, -in Python, that -can recognize patterns. For instance, one spammer registers ded304.com, -ded305.com, ded306.com, etc. We also need the custom DNS server to -let SPF classic clients check SES (which will be part of pysrs). -The Twisted Python -framework provides a custom DNS server - but I -would like a smaller implementation for our use. -

-The RPM for release 0.7.0 moves the config file and socket locations to -/etc/mail and /var/run/milter respectively. We now parse Microsoft CID records -- but only hotmail.com uses them. They seem to have applied for a patent on -the brilliant idea of examining the mail headers to see who the message is -from. We aren't doing that here, so not to worry - but I am not a lawyer, so -if you are worried, change spf.py around line 626 to return None instead of -calling CIDParser(). There is a new option to reject mail with no PTR -and no SPF. -

-Microsoft is pushing an anti-opensource license for their pending patent -along with their sender-ID proposal before the IETF. -It is royalty free - but requires anyone distributing a binary they've -compiled from source to sign a license agreement. The Apache Software -Foundation explains -the problem with sender-ID, and Debian concurs. Since -the Microsoft license is -incompatible with free -software in general and the GPL in -particular, Python milter will not be able to implement sender-ID in its -current form. This was, no doubt, Microsoft's intent all along. -

-Sender-ID attempts to do for RFC2822 headers what SPF does for RFC2821 headers. -Unlike SPF, it has never been tried, and is encumbered by a stupid patent. I -recommend ignoring it and continuing to implement and improve SPF until a -working and unencumbered proposal for RFC2822 headers surfaces. - -

- -SPF logo -Release 0.6.6 adds support for SPF, -a protocol to prevent forging of the envelope from address. -SPF support requires pydns. -The included spf.py module is an updated version of the original 1.6 -version at wayforward.net. -The updated version tracks the draft RFC and test suite. -

-The FAQ addresses how to get started with SPF. -

-Release 0.6.1 adds a full milter based dspam application. -

-I have selected the -dspam bayes filter project and -packaged it for python. -Release 0.6.0 offers a simple application of dspam I call "header triage", -which rejects messages with spammy headers. -To use header triage, you must have DSPAM installed, -and select a dictionary that is well moderated by someone who gets -lots of spam. That dictionary can be used to block spam that is -obvious from the headers (e.g. X-Mailer and Subject) before it ties -up any more resources. I have yet to see any false positives from this -approach (check the milter log), but if there are, the sender will -get a REJECT with the message "Your message looks spammy." - diff --git a/doc/credits.ht b/doc/credits.ht deleted file mode 100644 index 9973a4d..0000000 --- a/doc/credits.ht +++ /dev/null @@ -1,55 +0,0 @@ -Title: Credits - -

CREDITS

- -Jim Niemira -wrote the original C module and some quick -and dirty python to use it. -Stuart D. Gathman -took that kludge and added threading and context objects to it, wrote a proper -OO wrapper (Milter.py) that handles attachments, did lots of testing, packaged -it with distutils, and generally transformed it from a quick hack to a -real, usable Python extension. - -

Other contributors (in random order):

- -
-
Christian Hafner -
for the pymilter mascot image of - - Maxwell's daemon -
Stephen Figgins -
for reporting problems building with sendmail-8.12, and when - building milter.so for the first time. -
Dave MacQuigg -
for noticing that smfi_insheader wasn't supported, and creating - a template to help first time pymilter users create their own milter. -
Terence Way -
for providing a Python port of SPF -
Scott Kitterman -
for doing lots of testing and debugging of SPF against draft standard, - and for putting up a - web page that validates SPF records using spf.py -
Alexander Kourakos -
for plugging several memory leaks -
George Graf at Vienna University of Economics and Business Administration -
for handling None passed to setreply and chgheader. -
Deron Meranda -
for IPv6 patches -
Jason Erikson -
for handling NULL hostaddr in connect callback. -
John Draper -
for porting Python milter to OpenBSD, and starting to work on tutorials - then pointing out that it would be easier to just write the MTA in Python. -
Eric S. Johansson -
for helpful design discussions while working on camram -
Alex Savguira -
for finding bugs with international headers and - suggesting the scan_zip option. -
Business Management Systems -
for hosting the website, and providing paying clients who need milter - service so I can work on it as part of my day job. -
- -If I have left anybody out, send me a reminder: -stuart@bmsi.com diff --git a/doc/faq.ht b/doc/faq.ht deleted file mode 100644 index a40f774..0000000 --- a/doc/faq.ht +++ /dev/null @@ -1,293 +0,0 @@ -Title: Python Milter FAQ - -

Python Milter FAQ

- - -
  • Compiling Python Milter -
  • Running Python Milter -
  • Using SPF -
  • Using SRS -
  • - -
      - -

      Compiling Python Milter

      - -
    1. Q. I have tried to download the current milter code and my virus scan -traps several viruses in the download. -

      A. The milter source includes a number of deactivated viruses in -the test directory. All but the first and last lines of the base64 -encoded virus data has been removed. I suppose I should randomize -the first and last lines as well, since pymilter just deletes executables, -and doesn't look for signatures. -

    2. Q. I have installed sendmail from source, but Python milter won't -compile. -

      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. -

      - -

    3. Q. Why is mfapi.h not found when I try to compile Python milter on -RedHat 7.2? -

      A. RedHat forgot to include the header in the RPM. See the -RedHat 7.2 requirements. -

      -

    4. Q. Python milter compiles ok, but I get an error like this when - I try to import the milter module: -
      -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) ]
      -
      - -

      Running Python Milter

      - -
    5. Q. The sample.py milter prints a message, then just sits there. -
      -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. -

      - -

    6. Q. I've configured sendmail properly, but still nothing happens -when I send myself mail! -

      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.domain
      -
      -Now check your milter log. -

      - -

    7. Q. Why do I get this ImportError exception? -
      -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. -

      - -

    8. Q. Why do I get 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. -

      - -

    9. Q. Why does sendmail sometimes print something like: -"...write(D) returned -1, expected 5: Broken pipe" -in the sendmail log? -

      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. -

      - -

    10. Q. Why does milter block messages with big5 encoding? What if I -want to receive them? -

      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. -

      - -

    11. Q. Why does sendmail coredump with milters on OpenBSD? -

      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@localhost
      -
      -and change sample.py accordingly. -

      - -

    12. Q. How can I change the bounce message for an invalid recipient? -I can only change the recipient in the eom callback, but the eom callback -is never called when the recipient is invalid! -

      A. Configure sendmail to use virtusertable, and send all unknown -addresses to /dev/null. For example, -

      /etc/mail/virtusertable

      -
      -@mycorp.com	dev-null
      -dan@mycorp.com	dan
      -sally@mycorp.com	sally
      -
      -

      /etc/aliases

      -
      -dev-null:	/dev/null
      -
      -Now 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. -

      - -

    13. Q. I am having trouble with the setreply method. It always outputs - "milter.error: cannot set reply". -

      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
      -
      -
    14. Q. There is a Python traceback in the log file! What happened to - my email? -

      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. - -

    15. Q. I read some notes such as "Check valid domains allowed by internal - senders to detect PCs infected with spam trojans." but could not - understand the idea. Could you clarify the content ? - -

      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.com
      -
      -No, 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. -

    16. Q. 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. - -

      Using SPF

      - -
    17. Q. So how do I use the SPF support? The sample.py milter doesn't seem - to use it. -

      A. The bms.py milter supports spf. The RedHat RPMs will set almost -everything up for you. For other systems: -

        -
      1. Arrange to run bms.py in the background (as a service perhaps) and - redirect output and errors to a logfile. For instance, on AIX you'll want - to use SRC (System Resource Controller). -
      2. Copy pymilter.cfg to the /etc/mail or the directory you run bms.py in, - and edit it. The comments should explain the options. -
      3. Start bms.py in the background as arranged. -
      4. Add Xpythonfilter to sendmail.cf or add an INPUT_MAIL_FILTER to - sendmail.mc. Regen sendmail.cf if you use sendmail.mc and restart - sendmail. -
      5. Arrange to rotate log files and remove old defang files in - tempdir. The RedHat RPM uses logrotate for - logfiles and a simple cron script using find to clean - tempdir. -
      - In CVS, there is 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. -
    18. Q. The SPF DSN is sent at least once for domains that don't publish a SPF. - How do I stop this behavior? -

      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:	CBV
      -
      -I 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
      -
      - -

      Using SRS

      - -
    19. Q. The SRS part doesn't seem to work as whenever I try to start - /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.org
      -
      -The 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. - -
    diff --git a/doc/links.h b/doc/links.h deleted file mode 100644 index fdd8323..0000000 --- a/doc/links.h +++ /dev/null @@ -1,24 +0,0 @@ - -

    Subsections

    -
  • Introduction -
  • Changes -
  • Requirements -
  • Download -
  • GPG-KEY -
  • FAQ -
  • Policies -
  • Log Messages -
  • Mailing List -
  • CREDITS -
  • SourceForge.net Logo -

    Links

    -
  • C API -
  • Milter.Org -
  • Python.Org -
  • Sendmail.Org -
  • SPF -
  • pysrs -
  • pyspf -
  • pygossip -
  • pydspam -
  • libdspam diff --git a/doc/logmsgs.ht b/doc/logmsgs.ht deleted file mode 100644 index aa3863b..0000000 --- a/doc/logmsgs.ht +++ /dev/null @@ -1,91 +0,0 @@ -Title: Python Milter Log Documentation - - -

    Milter Log Documentation

    - -The milter log from the bms.py application has a variety of "tags" in it that -indicate what it did. - -
    -
    DSPAM: honeypot SCREENED -
    message was quarantined to the honeypot quarantine - -
    REJECT: hello SPF: fail 550 access denied -
    REJECT: hello SPF: softfail 550 domain in transition -
    REJECT: hello SPF: neutral 550 access neither permitted nor denied -
    message was rejected because there was an SPF policy for the -HELO name, and it did not pass. - -
    CBV: sender-17-44662668-643@bluepenmagic.com -
    we performed a call back verification - -
    dspam -
    dspam identifier was added to the message - -
    REJECT: spam from self: jsconnor.com -
    message was reject because HELO was us (jsconnor.com) - -
    INNOC: richh -
    message was used to update richh's dspam dictionary - -
    HONEYPOT: pooh@bwicorp.com -
    message was sent to a honeypot address (pooh@bwicorp.com), the -message was added to the honeypot dspam dictionary as spam - -
    REJECT: numeric hello name: 63.217.19.146 -
    message was rejected because helo name was invalid (numeric) - -
    eom -
    message was successfully received - -
    TEMPFAIL: CBV: 450 No MX servers available -
    we tried to do a call back verification but could not look up -MX record, we told the sender to try again later - -
    CBV: info@emailpizzahut.com (cached) -
    call back verification was needed, we had already done it recently - -
    abort after 0 body chars -
    sender hung up on us - -
    REJECT: SPF fail 550 SPF fail: see - http://openspf.com/why.html?sender=m.hendersonxk@163.net&ip=213.47.161.100 -
    message was reject because its sender's spf policy said to - -
    REJECT: Subject: Cialis - No prescription needed! -
    message was rejected because its subject contained a bad expression - -
    REJECT: zombie PC at 192.168.3.37 sending MAIL FROM seajdr@amritind.com -
    message was rejected because the connect ip was internal, but the -sender was not. This is usually because a Windows PC is infected with -malware. - -
    X-Guessed-SPF: pass -
    When the SPF result is NONE, we guess a result based on the generic -SPF policy "v=spf1 a/24 mx/24 ptr". - -
    DSPAM: tonyc tonyc@example.com -
    message was sent to tonyc@example.com and it was identified as spam -and placed in the tonyc dspam quarantine - -
    REJECT: CBV: 550 calvinalstonis@ix.netcom.com...User unknown -
    REJECT: CBV: 553 sorry, that domain isn't in my list -
    REJECT: CBV: 554 delivery error: dd This user doesn't have an account -
    message was rejected because call back verification gave us a fatal -error -
    Auto-Whitelist: user@example.com -
    recipient has been added to auto_whitelist.log because the message -was sent from an internal IP and the recipient is not internal. -
    WHITELIST user@example.com -
    message is whitelisted because sender appears in auto_whitelist.log -
    BLACKLIST user@example.com -
    message is blacklisted because sender appears in blacklist.log or - failed a CBV test. -
    TRAINSPAM: honeypot X-Dspam-Score: 0.002278 -
    message was used to train screener dictionary as spam -
    TRAIN: honeypot X-Dspam-Score: 0.980203 -
    message was used to train screener dictionary as ham -
    -
    diff --git a/doc/milter.ht b/doc/milter.ht deleted file mode 100644 index 844d662..0000000 --- a/doc/milter.ht +++ /dev/null @@ -1,264 +0,0 @@ -Title: Python Milters - -

    - - -Your vote? - - I Disagree - I Agree - -

    - - - - -
    -Maxwell's Daemon: pymilter mascot -Mascot by Christian Hafner - -

    Sendmail Milters in Python

    -

    by Jim Niemira - and - Stuart D. Gathman
    -This web page is written by Stuart D. Gathman
    and
    sponsored by -Business Management Systems, Inc.
    -Last updated Aug 26, 2008

    - -See the FAQ | Download now | -Subscribe to mailing list | -Overview | -pydspam | -libdspam -

    - -A Python -Sendmail introduced a - new API beginning with version 8.10 - -libmilter. The milter module for Python -provides a python interface to libmilter that exploits all its features. -

    -Sendmail 8.12 officially releases libmilter. -Version 8.12 seems to be more robust, and includes new privilege -separation features to enhance security. Even better, sendmail 8.13 -supports socket maps, which makes pysrs much more -efficient and secure. Sendmail 8.14 finally supports modifying -MAIL FROM via the milter API. Unfortunately, I haven't gotten around -to supporting that yet in python milter. -

    - -

    Overview

    - -This package provides a robust toolkit for Python milters, and the beginnings of a general purpose mail -filtering system written in Python. -

    -At the lowest level, the 'milter' module provides a thin wrapper around the - -sendmail libmilter API. This API lets you register callbacks for -a number of events in the -process of sendmail receiving a message via SMTP. -These events include the initial connection from a MTA, -the envelope sender and recipients, the top level mail headers, and -the message body. There are options to mangle all of these components -of the message as it passes through the milter. -

    -At the next level, the 'Milter' module (note the case difference) provides a -Python friendly object oriented wrapper for the low level API. To use the -Milter module, an application registers a 'factory' to create an object -for each connection from a MTA to sendmail. These connection objects -must provide methods corresponding to the libmilter callback events. -

    -Each event method returns a code to tell sendmail whether to proceed -with processing the message. This is a big advantage of milters over -other mail filtering systems. Unwanted mail can be stopped in its -tracks at the earliest possible point. -

    -The Milter.Milter class provides default implementations for event -methods that -do nothing, and also provides wrappers for the libmilter methods to mutate -the message. -

    -The 'spf' module provides an implementation of -SPF useful for detecting email forgery. -

    -The 'mime' module provides a wrapper for the Python email package that -fixes some bugs, and simplifies modifying selected parts of a MIME message. -

    -Finally, the bms.py application is both a sample of how to use the -Milter and spf modules, and the beginnings of a general purpose SPAM filtering, -wiretapping, SPF checking, and Win32 virus protecting milter. It can -make use of the pysrs package when available for -SRS/SES checking and the pydspam package for Bayesian -content filtering. SPF checking -requires -pydns. Configuration documentation is currently included as comments -in the sample config file for the bms.py milter. -See also the HOWTO and -Milter Log Message Tags. -

    -Python milter is under GPL. The authors can probably be convinced to -change this to LGPL if needed. - -

    What is a milter?

    - -Milters can run on the same machine as sendmail, or another machine. The -milter can even run with a different operating system or processor than -sendmail. -Sendmail talks to the milter via a local or internet socket. -Sendmail keeps the -milter informed of events as it processes a mail connection. At any -point, the milter can cut the conversation short by telling sendmail -to ACCEPT, REJECT, or DISCARD the message. After receiving a complete -message from sendmail, the milter can again REJECT or DISCARD it, but it -can also ACCEPT it with changes to the headers or body. - -

    What can you do with a milter?

    - - -
  • A milter can DISCARD or REJECT spam based based on algorithms scripted -in python rather than sendmail's cryptic "cf" language. -
  • A milter can alter or remove attachments from mail that are poisonous to -Windows. -
  • A milter can scan for viruses and clean them when detected. -
  • A milter scans outgoing as well as incoming mail. -
  • A milter can add and delete recipients to forward or secretly -copy mail. -
  • For more ideas, check the Milter Web Page. -
  • - - -Documentation for the C API is provided with sendmail. Miltermodule -provides a thin python wrapper for the C API. Milter.py provides a simple -OO wrapper on top of that. -

    -The Python milter package includes a sample milter that replaces dangerous -attachments with a warning message, discards mail addressed to -MAILER-DAEMON, and demonstrates several SPAM abatement strategies. -The MimeMessage class to do this used to be based on the -mimetools and multifile standard python packages. -As of milter version 0.6.0, it is based on the email standard -python packages, which were derived from the -mimelib project. -The MimeMessage class patches several bugs in the email package, -and provides some backward compatibility. - -

    -The "defang" function of the sample milter was inspired by -MIMEDefang, -a Perl milter with flexible attachment processing options. The latest -version of MIMEDefang uses an apache style process pool to avoid reloading -the Perl interpreter for each message. This makes it fast enough for -production without using Perl threading. -

    -mailchecker is -a Python project to provide flexible attachment processing for mail. I -will be looking at plugging mailchecker into a milter. -

    -TMDA is a Python project -to require confirmation the first time someone tries to send to your -mailbox. This would be a nice feature to have in a milter. -

    -There is also a Milter community website -where milter software and gory details of the API are discussed. - -

    Is a milter written in python efficient?

    - -The python milter process is multi-threaded and startup cost is incurred -only once. This is much more efficient than some implementations that -start a new interpreter for each connection. Testing in a production -environment did not use a significant percentage of the CPU. Furthermore, -python is easily extended in C for any step requiring expensive CPU -processing. -

    -For example, the HTML parsing feature to remove scripts from HTML attachments -is rather CPU intensive in pure python. Using the C replacement for sgmllib -greatly speeds things up. - -

    Goals

    - - -
  • Implement RRS - a backdoor for non-SRS forwarders. User lists non-SRS - forwarder accounts (perhaps in ~/.forwarders), and a util - provides a special local alias for the user to give to the forwarder. - Alias only works for mail from that forwarder. Milter gets forwarder - domain from alias and uses it to SPF check forwarder. Requires - milter to have read access to ~/.forwarders or else - a way for user to submit entries to milter database. -
  • The bms.py milter has too many features. Create a framework where - numerous small feature modules can be plugged together in the - configuration. -
  • Create a pure python substitute for miltermodule and libmilter that - implements the - libmilter protocol in python. -
  • Find or write a faster implementation of sgmllib. The - sgmlop package - is not very compatible with - - Python-2.1 sgmllib, but it is a start, and is supported in - milter-0.4.5 or later. -
  • Implement all or most of the features of - MIMEDefang. -
  • Follow the official - Python coding standards more closely. -
  • Make unit test code more like other python modules. -
  • - -

    Confirmed Installations

    - -Please email -me if you do not successfully install milter. The confirmed -installations are too numerous to list at this point. - -

    Enough Already!

    - -Nearly a dozen people have emailed me begging for a feature to copy -outgoing and/or incoming mail to a backup directory by user. Ok, it -looks like this is a most requested feature for 0.5.6. In the meantime, -here are some things to consider: - -

    -To Bcc a message, call self.add_recipient(rcpt) in envfrom after -determining whether you want to copy (e.g. whether the sender is local). For -example, -

    -  def envfrom(...
    -    ...
    -    if len(t) == 2:
    -      self.rejectvirus = t[1] in reject_virus_from
    -      if t[0] in wiretap_users.get(t[1],()):
    -	self.add_recipient(wiretap_dest)
    -      if t[1] == 'mydomain.com':
    -        self.add_recipient('<copy-%s>' % t[0])
    -      ...
    -
    -

    -To make this a generic feature requires thinking about how the configuration -would look. Feel free to make specific suggestions about config file -entries. Be sure to handle both Bcc and file copies, and designating what -mail should be copied. How should "outgoing" be defined? Implementing it is -easy once the configuration is designed. - - -


    -

    - - [ Valid HTML 3.2! ] - - [ Powered By Red Hat Linux ] -

    diff --git a/doc/policy.ht b/doc/policy.ht deleted file mode 100644 index 3e57bc6..0000000 --- a/doc/policy.ht +++ /dev/null @@ -1,249 +0,0 @@ -Title: Python Milter Mail Policy - -

    Python Milter Mail Policy

    - -These are the policies implemented by the bms.py milter -application. The milter and Milter modules do not implement any policies -by themselves. - -

    Classify connection

    - -When the SMTP client connects, the connection IP address is -saved for later verification, and the connection -is classified as INTERNAL or EXTERNAL by matching the ip -address against the internal_connect configuration. -IP addresses with no PTR, and PTR names that look like -the kind assigned to dynamic IPs (as determined by a heuristic -algorithm) are flagged as DYNAMIC. IPs that match the -trusted_relay configuration are flagged as TRUSTED. -

    -Examples from the log file (not the SMTP error message returned): -

    -2005Jul29 13:56:53 [71207] connect from p50863492.dip0.t-ipconnect.de at ('80.134.52.146', 1858) EXTERNAL DYN
    -2005Jul29 18:10:15 [74511] connect from foopub at ('1.2.3.4', 46513) EXTERNAL TRUSTED
    -2005Jul29 14:41:00 [71805] connect from foobar at ('192.168.0.1', 41205) INTERNAL
    -2005Jul29 14:41:15 [71806] connect from cncln.online.ln.cn at ('218.25.240.137', 35992) EXTERNAL
    -
    -

    -Certain obviously evil PTR names are blocked at this point: -"localhost" (when IP is not 127.*) and ".". -

    -2005Jul29 14:49:50 [71918] connect from localhost at ('221.132.0.6', 50507) EXTERNAL
    -2005Jul29 14:49:50 [71918] REJECT: PTR is localhost
    -
    - -

    HELO Check

    - -The HELO name provided by the client is saved for later verification -(for example by SPF). We could validate the HELO at this point -by verifying that an A record for the HELO name matches the connect ip. -However, currently we only block certain obvious problems. -HELO names that look like an IP4 address -and ones that match the hello_blacklist configuration -are immediately rejected. The hello_blacklist typically contains -the current MTAs own HELO name or email domains. -Clients that attempt to skip HELO are immediately rejected. -
    -2005Jul29 18:10:15 [74512] hello from example.com
    -2005Jul29 18:10:15 [74512] REJECT: spam from self: example.com
    -2005Jul29 18:17:09 [74581] hello from 80.191.244.69
    -2005Jul29 18:17:09 [74581] REJECT: numeric hello name: 80.191.244.69
    -
    - -

    MAIL FROM Check

    - -Before calling our milter, sendmail checks a DNS blacklist to -block banned sender domains. We never see a blocked domain. -

    -The MAIL FROM address is saved for possible use by the smart-alias -feature. First, the internal_domains is used for -a simple screening if defined. If the MAIL FROM for an INTERNAL connection -is NOT in internal_domains, then it is rejected (the -PC is most likely infected and attempting to send out spam). -If the MAIL FROM for an EXTERNAL connection IS in -internal_domains, then the message is immediately rejected. -This is quick and effective for most small company MTAs. For more -complex mail networks, it is too simplistic, and should not be defined. -SPF will handle the complex cases. - -

    wiretap

    - -The wiretap feature can screen and/or monitor mail to/from certain -users. If the MAIL FROM is being wiretapped, the recipients are -altered accordingly. - - - -

    SPF check

    - -The MAIL FROM, connect IP, and HELO name are checked against -any SPF records published via DNS for the alleged sender (MAIL FROM) -to determine the official SPF policy result. -The offical SPF result is then logged in the Received-SPF header field, -but certain results are subjected to further processing to create -an effective result for policy purposes. -

    -If the official result is 'none', we try to turn it into an effective result of -'pass' or 'fail'. First, we check for a local substitute SPF record -under the domain defined in the [spf]delegate configuration. -It is often useful to add local SPF records for correspondents that are -too clueless to add their own. If there is no local substitute, we use a "best -guess" SPF record of "v=spf1 a/24 mx/24 ptr" for MAIL FROM or "v=spf1 a/24 -mx/24" for HELO. In addition, a HELO that is a subdomain of MAIL FROM and -resolves to the connect IP results in an effective result of 'pass'. -

    -If there is no local SPF record, and the effective result is still not -'pass', we check for either a valid HELO name or a valid PTR record for -the connect IP. A valid HELO or PTR cannot look like a dynamic name -as determined by the heuristic in Milter.dynip. -

    -If HELO has an SPF record, and the result is anything but pass, we reject -the connection: -

    -2005Jul30 19:45:16 [93991] connect from [221.200.41.54] at ('221.200.41.54', 3581) EXTERNAL DYN
    -2005Jul30 19:45:18 [93991] hello from adelphia.net
    -2005Jul30 19:45:19 [93991] mail from  ()
    -2005Jul30 19:45:19 [93991] REJECT: hello SPF: fail 550 access denied
    -
    -Note that HELO does not have any forwarding issues like MAIL FROM, and so -any result other than 'pass' or 'none' should be treated like 'fail'. -

    -Only if nothing about the SMTP envelope can be validated does the effective -result remain 'none. I call this the "3 strikes" rule. -

    -If the official result is 'permerror' (a syntax error in the sender's -policy), we use the 'lax' option in pyspf to try various heuristics to guess -what they really meant. For instance, the invalid mechanism "ip:1.2.3.4" is -treated as "ip4:1.2.3.4". The result of lax processing is then used -as the effective result for policy purposes. -

    -With an effective SPF result in hand, we consult the sendmail access -database to find our receiver policy for the sender. - - - - - - -
    REJECT -Reject the sender with a 550 5.7.1 SMTP code. The SMTP rejection -includes a detailed description of the problem. -
    CBV -Do a Call Back Validation by connecting to an MX of the sender -and checking that using the sender as the RCPT TO is not rejected. -We quit the CBV connection before actualling sending a message. -If the CBV is rejected, our SMTP connection is rejected with the -same error code and message. CBV results are cached. -
    DSN -Do a Call Back Validation by connecting to an MX of the sender -and checking that using the sender as the RCPT TO is not rejected. -Unlike a CBV, we continue on to data and send a detailed message -explaining the problem. This can be useful for reporting PermError -or SoftFail to the sender. Keep in mind that for any result other -than 'pass', the sender could be forged, and your DSN could annoy the -wrong person. However, a SoftFail result is requesting such feedback -for debugging and a PermError result needs to be fixed by the sender ASAP -whether forged or not. DSN results are cached so that senders are -annoyed only weekly. -
    OK -Accept the sender. The message may still be rejected via reputation -or content filtering. -
    - -

    SPF policy syntax

    - -First, the full sender is checked: -
    -SPF-Fail:abeb@adelphia.net     DSN
    -
    -This says to accept mail from that adelphia.net user despite the -SPF fail, but only after annoying them with a DSN about their ISP's broken -policy. -

    -If there is no match on the full sender, the domain is checked: -

    -SPF-Neutral:aol.com     REJECT
    -
    -This says to reject mail from AOL with an SPF result of neutral. -This means AOL users can't use their AOL address with another mail service -to send us mail. This is good because the other mail service is -likely a badly configured greeting card site or a virus. -

    -Finally, a default policy for the result is checked. While there are program -defaults, you should have defaults in the access database for SPF results: -

    -SPF-Neutral:            CBV
    -SPF-Softfail:           DSN
    -SPF-PermError:          DSN
    -SPF-TempError:          REJECT
    -SPF-None:               REJECT
    -SPF-Fail:               REJECT
    -SPF-Pass:               OK
    -
    - -

    Reputation

    - -If the sender has not been rejected by this point, and if a GOSSiP server is -configured, we consult GOSSiP for the reputation score of the sender and -SPF result. The score is a number from -100 to 100 with a confidence -percentage from 0 to 100. A really bad reputation (less than -50 with -confidence greater than 3) is rejected. Note that the reputation is tracked -independently for each SPF result and sender combination. So aol.com:neutral -might have a really bad reputation, while aol.com:pass would be ok. -Furthermore, when a sender finally publishes an SPF policy and starts -getting SPF pass, their reputation is effectively reset. - -

    Whitelists and Blacklists

    - -The administrator can whitelist or blacklist senders and sending domains by -appending them to ${datadir}/auto_whitelist.log or -${datadir}/blacklist.log respectively. In addition, -recipients of internal senders (except for automatic replies like vacation -messages and return receipts) are automatically whitelisted for 60 days, and -senders that fail CBV or DSN checks are automatically blacklisted for 30 days. -Whitelisted and blacklisted senders are used to automatically train the -bayesian content filter before being delivered or rejected, respectively. -

    -Real Soon Now users will be able to maintain their own whitelist and -blacklist that applies only when they are the recipient. - -

    Content Filter

    - -Most messages have been rejected or delivered by now, but spammers -are always finding new places to send their junk from. For instance, -we get around 10000 emails a day, of which around 500 are first time -spam senders. A bayesian filter is trained by the whitelists and -blacklists, and scores the message. What is likely spam is either -rejected or quarantined. If the sender is an effective SPF pass, -then they get a DSN notifying them that their message has been -quarantined. (A DSN failure gets the sender auto blacklisted.) -Else, if the reject_spam option is set, the message is rejected. -Otherwise, a CBV is done (failure gets the sender auto blacklisted) -and the message is silently quarantined. -

    -Normally, you don't want email messages to silently disappear into -a black hole, so you should set the reject_spam option. However, -if you don't want your correspondent's email to get rejected, you can -check your quarantine frequently instead. - -

    Honeypot

    - -You can also blacklist recipients by listing them as aliases of the -'honeypot' dspam user. These are collectively called -the honeypot. Any email to these recipients is used to train the -spam filter as spam and chalk up a reputation demerit for the sender, then -discarded. It might be a good idea to blacklist the sender if it has SPF pass -as well, but I'm afraid of accidents. - -

    Reputation

    - -Reputation is tracked by sending domain and effective SPF result. -The GOSSiP server tracks the spam/ham status of the last 1024 messages -for each domain:result combination. When the server is queried during -the SMTP envelope phase (MAIL FROM), it also queries any configured -peers, and the scores are combined. Domains with a history of spam for -a given SPF result are rejected at MAIL FROM. The GOSSiP system has -a command line utility to reset (delete) a reputation for cases where a -sender that was infected with malware is repaired. In addition, -the confidence score of a reputation decays with time, so a bad sender -will eventually be able to try again without manual intervention. diff --git a/doc/python55.gif b/doc/python55.gif deleted file mode 100644 index b7c0b9d..0000000 Binary files a/doc/python55.gif and /dev/null differ diff --git a/doc/requirements.ht b/doc/requirements.ht deleted file mode 100644 index 0696f22..0000000 --- a/doc/requirements.ht +++ /dev/null @@ -1,99 +0,0 @@ -Title: Requirements - -

    Requirements

    - - -
  • While the miltermodule will work with python 1.5, you probably -want to use python 2.0 or better. The python code uses a number of -python 2 features. The email support requires python 2.4. -
  • Python must be configured with thread support. This is because -pymilter uses sendmail's libmilter which requires thread support. -
  • You must compile sendmail with libmilter enabled. In versions of -sendmail prior to 8.12 libmilter is marked FFR (For Future Release) and -is not installed by default. -Sendmail 8.12 still does not enable libmilter by default. You must -explicitly select the "MILTER" option when compiling. -
  • When compiling Python milter against sendmail versions earlier than -8.13, you must set MAX_ML_REPLY to 1 in setup.py. There is no way to tell from -the libmilter includes that smfi_setmlreply is not supported. -
  • You probably want to use sendmail-8.13, since that supports multi-line -SMTP error descriptions and SOCKETMAP. You want SOCKETMAP for use with -pysrs. -
  • Python milter has been tested against sendmail-8.11 through sendmail-8.13. -
  • Python milter must be compiled for the specific version of sendmail -it will run with. (Since the result is dynamically loaded, there could -conceivably be multiple versions available and selected at startup - but -that will have to wait.) This situation may only exist for sendmail -versions prior to 8.12. The protocol seems designed for backward -compatibility - and 8.12 is the first official milter release. -
  • Mea Culpa! After reading the Python Style guide, I realize that -my Python code is not up to snuff. Apparently mixed tabs and spaces -are anathema to those using Windows editors, where tabs can be expanded using -any arbitrary algorithm. Other than that, my -intuition matched Guido's pretty well - although I like to indent by 2 -rather than 4. I will arrange to have tabs expanded to spaces when -exporting new versions. Until then, beware! -
  • - -

    AIX 4.1.5 Requirements

    -To create sendmail RPMs for AIX, you can download my AIX 4.1.5 spec files -for sendmail-8.11.5 -or sendmail-8.12.3. If you have -not already set it up, I use a dummy RPM package -to represent the stuff that comes with AIX. You might also want -my python-2.1.1 spec file for AIX. It -does not include Tk or curses modules, sorry. If y'all trust me, you can -download rpms for AIX 4.x from my AIX RPM directory. -

    -Sendmail-8.12 renames -libsmutil.a to libsm.a. Unfortunately, libsm.a is an important AIX system -shared library. Therefore, I rename libsm.a back to libsmutil.a for -AIX. This presents a problem for setup.py. - -

    RedHat 7.2 Requirements

    - -If you are running Redhat 7.2, the distributed version of sendmail -now enables libmilter by default. RedHat 7.2 bundles -the development libraries with the main sendmail package, so -there is no sendmail-devel package. However, they forgot to include the -headers! So you'll have to get the SRPM and modify it. I suggest -moving the static libs to a devel package and adding the headers. If -this is too much trouble, you can get the mfapi.h -header for sendmail-8.6.11 from here and manually install it as -/usr/include/libmilter/mfapi.h. -

    -If you do modify the SRPM, I suggest renaming libsmutil.a -to libsm.a - just like sendmail-8.12 will. If you manually install -mfapi.h or don't rename libsmutil.a, you'll -need to force libs = ["milter", "smutil"] in setup.py. -

    -If you have installed python2, and want -python-milter to use python2, add python=python2 to setup.cfg -and build with python2 setup.py bdist_rpm. - -

    Redhat 6.2 Requirements

    - -If you are running Redhat 6.2, the distributed version of sendmail -does not enable libmilter. You can download the Redhat 7.2 sendmail.spec -modified to compile on RedHat 6.2: - -sendmail-rhmilter.spec. The -SRPM for sendmail-8.11.6 is available from -Redhat under - -Errata for RH6.2. But that doesn't include the latest security -patches since RH6.2 is no longer supported. -

    -If y'all trust me, you can pick up source and binary sendmail RPMs for RH6.2 -from my linux downloads directory. -The lastest RPMs were built by taking a RH7.2 SRPMS and removing some -RPM features from the spec file that RH6.2 doesn't support, then -recompiling on RH6.2. You can check this by installing the RH7.2 SRPM, -then diffing my sendmail.spec with theirs. Then run -"rpm -bb sendmail-rhmilter.spec" when you are satisfied. -

    -If you have installed python2, and want -python-milter to use python2, add python=python2 to setup.cfg -and build with python2 setup.py bdist_rpm. -You'll need to install the sendmail-devel package to compile milter.